《码农翻身》读书笔记

前言

五一假期期间在家休息,把《码农翻身》二刷了一遍,之前很久也看过一遍但是刷第二遍还是有很大的收获,特别是 Java 技术栈相关的部分,有些话都是作者的一些经验总结,感觉很有必要摘录下来细品一番。

摘录

CPU
CPU 必须把数据装载到寄存器中才能进行运算
CPU 的运行速度快的丧心病狂,但是它能做的事情却简单得令人发指,主要有以下4种:
(1) 从内存的某个格子中读取数据,放入自己内部的寄存器 Rx
(2) 把 Rx 中的数据写入内存的某个格子中(会覆盖原有的数据)
(3) 进行数学计算和逻辑运算
(4) 根据条件进行跳转
对于那些大神级别程序员来说,汇编语言也是小菜一碟。Ken Thompson 和 Dennis Ritchie 不就用汇编语言写了第一版的 UNIX 操作系统吗?求伯君不就用汇编语言写了 WPS 吗?

Java注解
元注解:可以认为是注解的注解
@Target 表示该注解的应用目标,可以是类、方法、方法参数等;
@Retention 表示这个注解要保留到什么时候,可以只在源码中,或者在 .class 文件中,或者在运行时。
对于 @Controller @RequestMapping @Transactional 这样的注解,大家更喜欢和 Java 方法写在一起,显得简单而直观。

泛型
Java 泛型的限定符还支持 super,Comparable 应该写成 Comparable <? super T?>

协议
计算机所有问题都可以通过增加一个中间层来解决
Java JNI(Java Native Interface),可以用C语言来实现,然后在Java中封装一下。

Spring 的本质
我们在进行软件系统设计的时候,一项非常重要的工作就是把一个大系统按业务功能分解成一个个低耦合、高内聚的模块,分而治之。

什么是框架
  先学了 Java SE,把集合、线程、反射、I/O、泛型、注解之类的基础知识学了一遍。
  你如果对Java后端感兴趣,那还有更多东西可学。用框架实现了业务只是很小一方面,还有系统架构设计、缓存、性能、高可用性、分布式、安全、备份等很多内容。你学得越多,就会发现无知的领域更多,所谓学无止境,就是如此。

HTTP Server
我这样的英语水平,这几十页的英文 HTTP 协议我不吃、不喝、不睡两天也看不完。死猪不怕开水烫,慢慢磨吧。

Build 的演进之路
  大部分人只会抱怨项目很无趣,没有挑战,遇到问题也只会安于现状。只有少数人会发现工作中的“痛点”,并且真正动手解决它,给公司带来价值。这是提高自己,让自己和别人区分开来的重要方法。

再见!Bug
  每个程序员都梦想从头写一个东西,不愿意读别人的代码,甚至同行相轻,瞧不起别人的代码。但实际情况是,自己重写一遍,不见得比现在已经运行的代码好到那里去,甚至更差!除非你了解了所有的细节,用大量的时间仔细规划、小心编程,但是现实中哪有时间让你这么玩啊?

让人怀疑的C语言
  由于太底层,刚接触计算机的学生也不能写出操作系统、数据库、中间件等系统级软件,哪怕写一个简单的、粗糙的软件也难。只能写一点与数据结构相关的小程序,再加上被指针不断地“蹂躏璀璨”,很容易丧失斗志。
  其实学习是一个螺旋上升的过程,在这个上升的过程中,成就感很重要,直接决定了一个人能不能继续学习下去。我在刚学习C语言的过程中就因为没有成就感,差点放弃了。
  通常来说,带图形界面的程序容易激发成就感。所以,我认为C语言不太适合入门。虽然C语言不适合入门,但还是应该学习一下,因为C语言太贴近硬件了,能帮助你理解程序在机器层面到底是怎么工作的。
  想想看,自己用C语言写一个小的Web服务器、简单的数据库、简单的分布式文件管理系统,是不是也很酷?更重要的是,系统级编程博大精深,并且非常稳定,值得深入研究,成为专家。

赖以谋生的Java
《Effective Java》
《Java 编程思想》
《Java 核心技术》
《深入Java虚拟机》
《深入理解Java虚拟机》
  不仅看书,还去读 JUnit源码、Spring 源码、Hsqldb源码、Jive 源码,再加上工作中写的大量代码,终于可以得心应手地使用 Java 编程了。
  后来我明白了,Java 最适合的还是后端编程,别让它干那些它不想干也干不好的事情,如桌面编程。
  后端编程还有很多事情需要处理,像负载均衡、灾难恢复、缓存、消息、分布式、数据备份、搜索等。后端的技术还是相对稳定的,这些知识介于业务层和系统层之间,值得发掘和积累。
  很多时候用 Java 解决一个问题,基本上就只有那么一种方案,照着规矩做就是了。Java 本身的特点也适合大型项目的合作开发。

优雅的Ruby
  动态语言由于缺乏静态检查,所以只好把运行时的检查写好,这就是单元测试。对 Ruby 来说,测试代码量和业务代码量 1:1 是非常正常的事情,有的甚至是 2:1,动态语言都有这样的劣势,但我们主要还是要利用它们的优点,让我们的编程生活更加舒适,不是吗?

老司机的精进
  凡事必先骑上虎背,有了问题的引导,你会疯狂地学习,迅速地提升自己。
  对于性格内向的程序员,很多时候你认为基本准备好了其实就够了,凡事必先骑上虎背,勇敢地迈出去,努力地争取一下,你就会发现自己登上了更高一层的台阶。

好奇心
  对于程序员,如果你看到新技术、新产品没有像小孩看到新玩具那样两眼放光,没有立刻在自己电脑上试试的冲动,你就需要仔细考虑一下是否真的对软件开发有兴趣。如果根本没兴趣,那不要蓝费时间,还是趁早转行,有更多适合你的职业在等着你。
  没有好奇心,就不愿意学习新技术。一名架构师,如果没有对技术的敏感度和前瞻性,一直抱着一套技术架构不变,估计很快就会被淘汰。所以对技术的好奇心/兴趣是一切的基础。
  很多人会语法,也懂框架,但是在基本功上却不过关,因而只能在初级程序员上踏步。
  这个基本功的训练就是数据结构和算法,我的经验是多做习题,让这种思维在脑子里固化,以后的编程就可以信手拈来了。

透彻理解技术的本质
只是学会使用是不行的,不但要知道 How,还要知道 Why。
停下来,思考,才是进步的本质。

写出漂亮的代码并不容易

  1. 需要思路清晰
  2. 有良好的编程基础
  3. 有优秀的抽象能力
  4. 对一门语言的熟练掌握
    学习Java开发的可以思考一下为什么 Spring 有 Controller、ViewResolver 这样的概念?

技术领导力
  要用技术的影响力来领导人,而不是威权和职位。换句话说,就是要能让技术人员服你。有了技术影响力,你在团队里发出的声音才会被倾听、被尊重。但影响力不是很快就建成的,这是一个漫长的过程:你解决了一道技术难题,你提出的方案被证明可行……

对自己狠一点,开始写作吧
  如果你们把一门技术通俗易懂地给别人讲明白,那就说明你已经掌握了。这种“转教别人(Tech others)”的方法属于主动学习,效率是最高的。但是在工作和生活当中,你是很少有机会去给别人讲授的。既然没法给别人讲,那就退而求其次吧,把自己的理解写出来。
  有人可能要问了:我也可以按照这个思路去学习,为什么要写下来呢?原因很简单,不写出来,很容易放弃深度思考。你会觉得,我已经知道是怎么回事儿了————其实一些关键的细节被大脑给忽略了。
  我们已经进入了一个碎片化的时代,我们的大脑已经养成了碎片化文化的习惯,一天不看碎片化的信息就觉得不舒服,这样下去会慢慢地丧失深度思考的能力。写作会逼着你思考,梳理知识体系,防止自己被碎片化所填满。
好的程序员都是代码喂出来的,动手实践必不可少,所以我还经常写代码。
优秀和平庸的差别可能就是那一点点坚持吧!坚持不懈地做一件事,每天前进一点点,最后量变会发生质变。

Java 静态(static)方法读取 Nacos 配置中心

为了降成本节省服务器资源,需要将配置中心从 Apollo 切换到 Nacos,因为注册中心是 Nacos 直接复用集群即可。

问题描述

util 里面获取配置的方法都是 static 静态方法,这就导致了 @Value 根本获取不到 Nacos 里面的配置,所有都改成非静态方法改动很大,很不实际,对调用方很不友好。

尝试过程

查了很多关于Nacos 获取配置中心的资料,资料都很浅显,都是在一个 controller 里面获取,关于静态方法获取的资料找到篇是用 @PostConstruct 注解一个方法将变量赋值给一个 static 变量,这种方法还真行,不过缺点很明显,参数只会在进程启动的时候加载进去,配置中心修改之后并不会生效,需要重启进程才会生效,没有什么价值。

解决方案

试了很多方案都行不通,于是请教组内老司机帮忙协助,在静态方法用 SpringBeanUtil.getBean(AppConfig.class) 这个方法先实例化 bean,然后用 bean 去调用里面的动态方法,是的,获取配置里面的方法还是换成了动态的,这样才方便获取到 @Value 的值,但是用来给业务层调用的方法依然是 static,对业务层调用无影响。

Nacos 配置中心接入流程梳理

官方文档:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

- 阅读全文 -

Linux 设置环境变量

平时登录服务器经常会设置一些路径作为环境变量来提升工作效率,下面记录一下设置环境变量的各种方法。

Solution 1: 临时设置

使用 export 命令

export PATH="$PATH:/usr/local/bin"

查看是否生效

export

Solution 2: 修改 profile 文件

vim /etc/profile

# 在里面加入命令
export PATH="$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/bin"

编辑完之后,运行命令生效

source /etc/profile 

Solution 3: 修改 .bashrc 文件

这种方法适用于设置不同账号不同的环境变量,一台服务器多个用户使用的话可以设置自己的环境变量。

# root 用户
vim /root/.bashrc

# 普通用户
vim /home/xxx/.bashrc

# 在里面加入命令
export PATH="$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/bin"

修改完之后退出当前账号,重新登录系统,测试是否生效

echo $PATH

php-fpm reload 时 nginx 出现 error log 分析

起因

每次 Jenkins 发版的时候 nginx 总会有几个 error log 出现,量也不是很大,通过时间点查看 access log,发现 http status 是 502。

2019/08/08 10:07:35 [error] 11346#0: *395555896 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 100.79.15.33, server: xxxxxx, request: "GET /api/v2/current-ad?language=zh_CN HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-cgi-56.sock:", host: "xxxxxx"
2019/08/08 10:07:35 [error] 11347#0: *395557146 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 100.79.15.23, server: xxxxxx, request: "POST /hw/v2/scene/bundle/lists HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-cgi-56.sock:", host: "xxxxxx"

解决方案

通过查找资料找到了需要配置的参数:

process_control_timeout = 10

参数含义是 设置子进程接受主进程复用信号的超时时间,控制子进程处理来自master的信号的时间,默认为 0 如果正在处理请求, 很可能会收到错误报警。

现在我们需要在 php-fpm.conf [global] 配置块里面配置,我这里配置为 10s,没有配置了 [global] 里面会导致 php-fpm 启动失败,切记!
配置完成之后需要 reload 加载最新配置,第一次 reload 还是会有 error 的,因为我们的配置还没有生效,之后的 reload 就可以解决此问题,这就可以放心的发版了!

Linux 平台安装 MongoDB

说明

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

步骤

1. 下载

https://www.mongodb.com/download-center/community
Version 选择最新的稳定版, OS 选择 Linux 64-bit legacy x64,会看到下载地址。

cd /usr/local/src
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.11.tgz

2. 解压

tar zvxf mongodb-linux-x86_64-4.0.11.tgz
mv mongodb-linux-x86_64-4.0.11 /usr/local/mongodb

3. 文件说明

Name Comments
bsondump 导出 bson 结构
install_compass compass 是一个 GUI 的管理工具
mongo 客户端(相当于 mysql.exe)
mongod 服务端(相当于 mysqld.exe)
mongodump 整体数据库导出(相当于 mysqldump)
mongofiles 操作 GridFS 文件
mongoreplay 重放流量到其他实例
mongos 路由器(分片时用)
mongotop 耗时数据统计
mongoexport 导出易识别的 json 或 csv,方便用代码处理
mongoimport 导入 json, csv 等格式
mongorestore 数据库整体导入,与 mongodump 相结合
mongostat instance 的状态统计,类似 vmstat

4. 启动

MongoDB 的可执行文件位于 bin 目录下,所以可以将其添加到 PATH 路径中:

export PATH= /usr/local/mongodb/bin:$PATH

MongoDB的数据存储在data目录的db目录下,但是这个目录在安装过程不会自动创建,所以你需要手动创建data目录,并在data目录中创建db目录。

mkdir -p /data/db

最简单的启动,前台运行

cd /usr/local/mongodb/bin
./mongo

后台运行

cd /usr/local/mongodb/bin
./mongod --dbpath /data/db --logpath /var/log/mongodb.log --logappend --fork --port 27017
Param Comments
--dbpath 数据存储目录
--logpath 日志存储目录
--port 运行端口(默认27017)
--fork 后台进程运行

5. 注意点

mongodb非常的占磁盘空间, 如果你用虚拟机练习,可能空间不够,导致无法启动.
可以用 --smallfiles 选项来启动,
将会占用较小空间 400M左右.