You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
7.6 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 42 | 细数技术研发的注意事项
你好,我是景霄。
技术研发一直以来都是各大公司的核心部分之一,其质量的好坏直接影响到了产品的质量以及用户对产品的体验。如何建立一套规范、健全的开发体系,就显得尤为重要。今天我就和你聊聊技术研发的注意事项。
## 选择合适的编程语言
比如我们正在开发一个系统首先根据具体的需求我们需要对系统的各个部分选择合适的编程语言。一般来说infra这层我们更偏向于使用C++而纯的服务器端则是以Python、Java、PHP等等为主。以搜索引擎为例下面我画了一个它的简略架构图
![](https://static001.geekbang.org/resource/image/72/d5/72caf6b3be8758651e6071bd49cb24d5.png)
你可以看到大概的工作流程是用户在客户端client输入一个查询query发送请求request到达服务器端server-side服务器端首先向NLP service发请求并对请求进行分析等到拿到各项信号signal再向后端backend发送请求后端会做特征抽取feature extraction利用ML 模型进行结果的检索candidate retrieval、排序最后再把结果返回给服务器端和客户端。
这里的NLP Service和后端我们都会使用C++。因为这部分的处理最为复杂和耗时都涉及到了特征抽取和model serving对延迟latency的要求极高只有C/C++这类语言才能满足需求。
而服务器端或者叫中间层middle tier我们则会使用Python、Java、PHP等语言。因为这部分并没有特别复杂的处理和对延迟的高需求主要是以一些业务逻辑为主并且对程序员来说使用这种高级语言也更容易上手和调试。
## 合理使用缓存
缓存cache在实际工程中十分重要可以想像如果没了缓存我们今天所用的绝大多数产品估计都会崩溃。缓存为我们节约了大量的CPU 容量capacity和延迟。
还是以刚刚的搜索引擎系统为例,我们在客户端、服务器端和后端都会设置缓存。在客户端,我们一般会缓存用户的搜索记录,比如当你点击搜索框时,自动弹出的建议关键词的前几个,就可以是缓存的结果。这不需要向服务器端发请求,可以直接从客户端下载。
而在服务器端,我们也会设置缓存来存储一些搜索结果。这样,如果同一个用户多次发送相同的请求,就不需要再向后端请求,直接从缓存里面拿结果就可以了,快速又高效。
同样的后端也需要缓存。比如在model serving这块儿我们通常会有几个小时的缓存不然每次提供实时的在线服务时对CPU的负荷很大延迟也会很高。
总而言之,如果没了缓存,容易造成很多问题。
* 服务器负荷迅速飙升,崩溃的几率大大增加。
* 端对端的延迟迅速飙升,请求超时的概率大大增加。
但是不是缓存越多就越好呢?显然也不是。
第一,通常来说,缓存比较昂贵,所以在使用上,我们都会有一个限度,不能无限制索取。
第二缓存不是万能的过度增加缓存也会损害用户的产品体验。比如搜索结果的retrieval和排序这两块理想状况下肯定是做实时的model serving最好因为这样对用户的个性化推荐更准确和实时。之所以会对model有几个小时的缓存更多的是出于性能的考虑但如果把缓存从几小时改为几天显然不合适无疑会对用户的产品体验造成极大的负面影响。
因此缓存到底取多久、取多少往往是用户对产品参与度和性能的一个权衡需要根据一些具体的分析以及A/B测试做出决定。
## 健全的日志记录系统
健全的日志记录系统也是尤其关键的一点。大型公司的系统往往由成千十万个小系统组合而来如果发生故障比如Google、Facebook的某项服务突然宕机了我们就需要以最快的速度找出原因并做出修复。这靠的是什么呢靠的正是健全的日志记录系统使得我们能够方便地分解错误原因一层一层追溯直到找到根源。
一般来说,在线上环境中,我们需要两种类型的日志记录模式。
一种是实时logging考虑到服务器的压力通常会做降采样downsampling比如log实际流量的1%。这样的好处是可以及时跟踪各项指标如果有情况立即触发警报alert
比如某天的中午12点一位工程师push了一段会造成服务器奔溃的代码进入产品实时logging检测到异常发出警报这时有关人员便会进行排查。如果发现这个代码的push时间和警报触发时间一致就能够最快地恢复revert最小化其带来的负面影响。
同时实时logging也有利于我们进行各种线上实验。比如ML组的A/B测试常常需要调参我们的通常做法就是每隔几小时查看实时 logging的table根据各项指标适度调整参数。
第二种是每天更新一次也就是daily的 full logging有助于我们统计一些信息进行分析比如做成仪表板dashboard方便查看每天的各项指标来跟踪进度。此外full logging的table也常常用于ML组的训练数据training data
## Profiling必不可少
关于profile之前我们也提到过在实际开发中是非常重要的一项功能能够帮助开发人员详细了解系统每个部分的效率并加以提高。
在线上环境中我们通常会在许多必要的地方加上profile的代码这样我们就能够知道这段代码的延迟是多少哪个部分的延迟特别严重等等然后对症下药。
如果没有profile很容易导致开发人员随意增加功能而不进行优化这样以来随着时间的推移系统越来越冗余延迟也会越来越高。因此一个成熟的系统一定会有profile的代码帮助开发人员随时监控内部的各项指标变化。
## test、test、test
这一点我也已经在前面的文章中强调过了测试test一定不能少。无论是单元测试unit test、集成测试integration test还是其他都是保证代码质量、减小bug发生概率的一个有效手段。
在真正规范的公司或是小组里,开发人员如果新增或改变了一个功能而不写测试,是过不了代码评审的。因此,测试一定要写,尤其是系统复杂了以后,很多工程师都要在上面开发各种不同的新功能,很难保证各个部分不受影响,测试便是一种很好的解决方法。
除了日常开发中所写的测试外在代码push到线上之前最好还要加一层测试。还是以刚刚的搜索引擎系统为例我所知道的Google或者Facebook的代码在push的过程中都会有专门的service去模拟不同的用户发送请求然后看返回的响应是不是符合要求。如果出错就会阻止代码的push这也就告诉了开发人员他们所写的代码可能存在问题需要再次检查。
## 写在最后
关于技术研发的注意事项,我主要强调这些内容。事实上,日常开发工作中,很多的细节都值得特别关注,而对于易错的地方,用系统化的流程解决不失为一个高效的方案。那么,在你的日常工作中,有哪些特别留心的地方值得分享,或者有哪些疑惑的地方想要交流吗?欢迎在留言区写下你的想法。