软件工程师SOP
SOP就是标准操作流程,类似的含义是最佳实践。掌握好SOP,可以让事情做的更对,更成熟而且快速。
单元测试改动 SOP
- 先要保证原来的代码以及单元测试是处于通过的状态
如果不这么做就直接写新的代码,新的测试,之后若出现单元测试通不过,会隐藏着一种原因,就是本来的测试就不工作,这样调试起来极其困难。
- 添加新的测试
这是一种测试驱动的原则,测试的代码就是一种需求规格。
默认新写的测试是一定会失败的
-
再做代码改动
-
调试单元测试,使得通过
-
调整所有修改的文件的代码风格,通过代码规范检查标准
-
验证所有的其他测试是否通过
Oncall SOP
Oncall先看责任,如果只是普通的oncall,那么大致SOP如下:
- 保证可以及时接受消息
保证手机通畅,接到电话后,马上打开电脑(要带在身边),第一时间查看。
- 第一时间判断问题的严重性,并回复
10分钟左右,给出自己的第一判断。
首先,查看是否出现过类似的问题。
如果没有,那么这个时候应该有一些文档来参考问题的严重程度。
- 查看系统的性能指标系统,程序运行错误系统
检查问题的严重性,以便进一步的回复
-
如果自己可以分析清楚,那么回复,并给出解决建议
-
如果自己不可以解决,第一时间升级到上一层oncall
做代码的重构
- 先了解哪些地方需要修改
可以使用AI(copilot或者Claude的agent模式)来问。
- 分析这些地方的先后次序
可以问AI。
-
和队友做确认
-
分别做改动
可以在改动后,问AI是否是正确的改动。
- 部署之前先部署到QA和SandBox环境详细测试
异步消息设计SOP
- 尽量保证消息来的时候是有时间顺序被系统接收的
- 如果系统本身是并行处理,那么在前一条相关的消息没有处理好的时候,需要有检测 条件可以知道,检测到之后把当前消息全部放入队列存起来,之后再按时间排序并处理。
- 每条消息被打上唯一的ID,并且保证幂等
幂等就是多次重复执行,但是结果不会破坏业务逻辑。
例如:存数据(例如客户的订单、支付)的时候 (1) 把数据打上唯一的ID标记 之后存的时候判断,如果存过了,那么就不存了。
(2) 使用数据库的约束机制
建立键约束,如果检测到,那么就不重复写入数据。
(3)使用状态机
对于管理的数据,只有几种状态,例如open,paid,close,failed几种状态。
(4)乐观锁
例如把读取和更新作为一对操作,锁在一起,每次只有一个线程能拿到这个锁并做完读取和更新的操作。
具体实现细节:读取的时候,也要读取数据的版本(也就是锁),然后,只能在这个版本的情况下进行更新, 更新完之后立马递增版本号。
坏处:需要重试机制,因为更新操作可能会失败;ß
多个线程抢锁的时候,如果一个线程成功,意味着其他线程都要失败,而失败是要重试的,容易混乱。
结论:适合短事务。
Web项目K8S部署结构
三个部分:
- 主程序
负责提供API,Web界面,以及HTTP请求。
其中往往一起部署: Nginx 代理容器 + Unicorn 应用容器。
Nginx 容器:
- 终止 SSL/TLS 连接
- 处理长连接(ELB 健康检查)
- 监听 443 端口
- 将请求转发到 localhost:11000
Unicorn 容器:
- 运行 Rails 应用
- 监听 11000 端口
- 处理实际的业务逻辑
外部请求 → Nginx (443) → Unicorn (11000) → Web应用(例如Rails应用)
Unicorn在整个部署中的核心作用:
- HTTP 服务器:将 HTTP 请求转换为 Rails 应用调用
- 进程管理器:管理多个 worker 进程,提供并发处理能力(注意,同一个请求只会被一个进程处理,worker的数量可设置为CPU核心的数量,因为执行的任务多为CPU密集型,且rails多线程效率低)
- 稳定性保障:进程隔离确保单个请求不会影响整个应用
- 资源优化:COW 内存共享,减少内存使用
- 运维友好:支持零停机重启和优雅关闭
主线程的副本数比其他的多,例如生产环境中部署30个副本。
- 工作线程Workers
不处理http请求,但是做后台的操作,例如读取数据库,处理消息队列等。
workers是默认24小时都在运行的。
- 定时任务CornJob
和Workers类似,但是是定时执行,例如每一天的2点执行。