那些年曹大写过的博客

某天晚上看到曹大在群里指点江山,折服。感叹为何曹大如此渊博,遂决定从头到尾研读完他所有的博文。

前后共花了一个月的时间,今天终于读完了(2020-11-24~2020-12-26),总共 118 篇。从 15 年 10 月 31 日开始的第一篇,到今天,总共写了 5 年多的时间。基本上每半个月产出一篇,非常稳定。

从最初讲具体的工作,例如将 MySQL 数据导入到 ES,到近期的《中台的末路》、《架构的腐化》、《工程师应该怎么学习》等名篇,水平一步步提高,视野也在一步步变大。

这些博文里很多内容都是从工作中提炼、总结出来的,这需要对自己所做的工作非常熟悉,并且需要做很多思考才行。这对我们而言,是有启发的。

还有一些是论文或文档的翻译,翻译它们而不是仅仅看一遍,对我们深刻理解内容是很有帮助的。连曹大都这样做了,我们有什么理由不做呢?

总的感受是,我们需要不断思考、反思、总结,并且持续不断地写出来。在所有文章里,如果只推荐一篇的话,那无疑就是《工程师应该怎么学习》[1]这篇。其中最激励我的一段是:

人这一辈子,最重要的是能把路越走越宽。对于工程师来说,能够锻炼软技能的场合其实不是很多,但也不代表完全没有。即使没有也可以自己创造机会,例如组内、组间、部门内的技术分享都是不错的机会。

更大规模的技术分享可能因为主办方“势力眼”,在你级别不高或者影响力不大的时候,不提供给你这样的机会,但是作为一个向上的人,迟早会有走到这一步的一天。你所要做的是提前做好准备,在那一天到来的时候,在聚光灯下旁征博引,谈笑风生。

祝大家都能成为更好的自己!

我们只有保持终生学习的姿态,才有可能不被时代抛弃。

If you don't keep moving, you'll quickly fall behind.

下面是详细的文章内容介绍,最后有一张表格,列出了所有的文章链接和概览。因为 xargin.com 没有 archive 功能,所以这篇文章算是全网最全的、最方便的博客入口。


第 1 篇是 15 年 10 月 31 日开始的,到今天已经 5 年了,主要讲如何使用 vagrant 来搭建一套 lnmp(linux/nginx/mysql/php)开发环境,解决一些诸如只用线上才出现的 bug,以及新同学如何能快速搞定开发环境。

第 2 篇主要讲的是一致性哈希。我又查了下其他资料,总结下一致性哈希的优点:当增减 server 时,可以移动最少的 keys;因为数据是均匀分布的,所以更容易水平扩展。现实世界中,比如 Amazon's Dynamo 数据库的分区组件、Apache Cassandra 跨集群的数据分区等等都用到了一致性哈希。

第 3 篇是将 MySQL 里的数据导入到 Solr 来满足一些特定的查询需求。

第 4 篇把 Solr 换成 ES,再来一次。

第 5 篇主要内容是说用 PHP 实现服务发现很难,不如 Java 那样方便。人家亚马逊的贝索斯在 2002 年就要求服务化,而阿里则是 2009 年则开始的。

第 6 篇主要内容是讲从 MySQL 导入大量数据时,碰到 GC 问题,导致连登陆都不行,最后通过加大 JVM 的运行时内存解决;Stop the world 机制简称 STW,即在执行垃圾收集算法时,Java 应用程序的其他所有除了垃圾收集帮助器线程之外的线程都被挂起;思想其实很朴素,用空间来换时间。

第 7 篇是关于乐观锁的内容,悲观锁用 select for 先锁定记录,然后再 update 更交换机数据;而乐观锁则比较前后的版本(例如订单,也可以比较 status)来解决并发更新时的数据覆盖问题。记住这个时间点,5 年前,曹大刚听说乐观锁^_^。

第 8 篇是一份 Redis 事务相关的文档翻译。主要内容有事务的使用、事务的错误、使用 watch 等。

第 9 篇还是一个连续剧,书接第 6 篇,在实际操作的过程中,将 MySQL 的数据导入到 ES 中遇到的导入数据有丢失的问题,主要原因是有主从延迟。处理办法就是每次都去向前多取一点:select * from [业务表] where update_time > date_sub(now(), 10 minute);。嗯,曹大会刻意总结在工作中遇到的问题及思考的解决方案,即使看起来比较简单。

第 10 篇其实也是一个续集(一致性哈希),书接第 2 篇,主要讲了 2 种缓存客户端如何生成虚拟节点的算法。并且,从这篇文章得知,PHP 是没有什么可以全局复用的全局变量的,所以每次 web 请求从 nginx 到 cgi 都会重新走各种 web 框架的 index.php。

第 11 篇主要是总结了在开发的过程中遇到的问题及解决方案,它同时也是曹大在公司做过的分享。比较重要的点有:没有填 update_time 而采用了 create_time,且由于主从同步或者时钟或者其他问题导致的“工单系统是有可能在未来创建过去一段时间的工单的”,或者说“一个时刻创建了在这个时刻之前”,这个是通过每次都向前多取 10 分钟的变更数据。还有一个点是每天低峰期删数据导致的大量删除 binlog 会对系统造成压力。另外,这时就已经用了 gin 框架了。

第 12 篇是对当时同步 MySQL 和 ES 的方案的一个总结反思,说明了优点和缺陷。嗯,估计是最后一篇了。前后也有四、五个月了。

第 13 篇曹大喷了一个 php 框架 laravel 里的一个实现:闭包套闭包在函数调用的时候类似于递归调用,也存在压栈压爆的问题。最后一段:没错,拿技术解决问题,但是不要为了炫技而炫技。(特别是你的特技可能连一个“丑陋”的解决方案都打不过。找到一篇 Go 相关的责任链文章[2],对照看一下。

第 14 篇是看一个用 C 写的消息队列的源码。重点在于曹大对于“如何做分布式”的总结和思考:proxy 和 smart client。

第 15 篇讲的是如何设计一个灰度发布系统。从作用到分桶/分类策略,到用哈希算法对 key 进行哈希分桶从而实现千分比灰度。最后还提了几个问题并作了解答:使用 md5 和 sha1 不能保证均匀分布怎么办?如何选取分桶?使用 md5 或者 sha1 对 CPU 消耗太高怎么办?学到了两个如何对字符串算 md5 和 sha1 的命令:

echo -n 15810321343 |openssl dgst -sha1
md5 -s 15810321343


15810321343


md5=>
05eadde36e5e5c3a00015a8f07d98d6b


sha1=>
7962e1ba260de074ef895af44c62ad353ee36c2c

第 16 篇从数据库、检索服务、日志三个方面来谈 ES 能做的事,以及优势和限制。企业内部使用的 elasticsearch 是提供垂直搜索的一种方案,内容可能是一些结构化的数据,而不像大搜索那样都是杂乱的内容。数据库层面,查询条件可以转化为 bool 查询;单表 count 也容易解决;但 ES 不能实现 Join,事务。在检索服务层面,集群便可以非常方便地进行动态扩展,数据也不容易丢失;缺点是分词不是很科学。日志方面,ELK,每天建一个索引。

第 17 篇介绍了曹大自己开发的工具:elasticsql,使用 SQL 来查询 ES,目前 629 星。工作中遇到了问题,然后就手动开发一个工具,并且写文章总结,赞!

第 18 篇讲迅雷。文件会按 16KB 进行切分,每个文件块用 sha1 算法计算一个哈希值,用作小块的校验。将一个文件的所有小块的 sha1 连接得到的字符串再进行 sha1,得到整个文件的 id。之后简单讲了 server hub、peer hub、file server 的工作原理。因为迅雷成立时,互联网上的轮子并没有那么多,所以很多都得自研,文档也不全。最难解决的问题不是 P2P 下载,而是各种乱七八糟的 case。

第 19 篇列出了实际工作过程中碰到的各种低级的做法。我自己印象深刻的且之前没碰到过的有:滥用回调,增加系统复杂性;访问数据库不做批量;树形结构的表结构设计问题;工作流系统update不判断修改前的状态;抱怨接口性能是语言问题。嬉笑怒骂,皆成文章。

第 20 篇,把 logstash/kibana/elasticsearch 之类的东西统统变成 5.0 的过程中,遇到的一些问题及解决。

第 21 篇,公司登陆验证用的 Google Authenticator 来做校验的原理。也就是将一个 key 分发给某个具体的帐户,然后服务端和客户端可以每隔 30 s 算一个 token。将 token 和帐户验证即可确定身份。

第 22 篇,翻译的一个后 GitHub 上的后端面试项目[3],并给出一些问题的回答。这些题基本都是比较开放的问题,很少一问一答这种。5 年前的了,不过我看原项目地址 7 个月前还有更新。

第 23 篇,HTTP 中间件的形式如何写。这里给出了一些前置、后置、耗时统计的控制的例子,不过最后给的一个例子有点问题,不是太好理解。我找到了一篇叶剑峰大佬写的比较好理解的,能直接运行的例子[4]。可以看到,《Go 语言高级编程》中也有这篇内容,可见平时的积累是非常重要的。

第 24 篇是问题 kafka 消息重复问题的排查,其实也没有各种现场排查,最终仅通过文档的说明就发现了问题:消费者在 poll 的时候才发送心跳,那如果处理消息的时间稍长就会被判失活,导致将正在消费的 partition rebalance 给其它消费者。因此解决办法就是升级到 0.10。这也告诉我们不要太快使用新发布的软件,因为有很多问题还没有生产环境中发现。

第 25 篇又是一篇吐槽文,工作中有时总是会遇到太“笨”的合作方,人家不会转一点脑子,什么问题都来问你,本来你就已经清楚地说明了。但一旦有什么在他们预期之外的事情,他就会来麻烦你。文中给出一些应对的办法,这当然需要后端去学习一些前端知识。工程师,终身学习是基本的。

第 26 篇,讲的是 redis 的 SDS 是不是二进制安全的。简单来说,通过使用二进制安全的 SDS[5],而不是 C 字符串,使得 Redis 不仅可以保存文本数据,还可以保存任意格式的二进制数据。起因是看到群里有人看到 redis 里有 strlen 的调用,就怀疑 redis 的 SDS 的二进制安全是不是真的。之后,一番实验和看代码,发现真正调用 sdsnew 函数的是在内部字符串用或者是测试用。

嗯,2016 年的博客看完了,总共 26 篇,基本两周一篇的节奏。

第 27 篇,是一篇译文[6]。Redis 客户端和 Redis 服务器使用 RESP 协议通信,RESP 是 REdis Serialization Protocol 的简称。虽然 redis 协议设计得十分对阅读友好(human readable)并且十分容易实现,但实际实现起来和二进制协议的性能依然比较接近。例如,RESP 使用了前缀的 length 来传输 bulk 数据,所以没有必要像 JSON 一类的数据结构需要通过扫描来查找特殊字符,也没必要在发送数据的时候给数据加上引号(quote the payload)之类的。

第 28 篇,在某个本来想打游戏度过的周末,听说有 B 站的分享,于是去听了,结尾感慨:本来用来打游戏的周末又学了不少东西。整篇文章就是对这次分享的一次总结,其中又结合自己平时的思考。有一点是讲业务和基础架构绑在一起的好处。

第 29 篇,发现曹大有个习惯比较好,就是经常会翻译一些比较重要的文档。因为人总是容易遗忘,即使某个东西你现在很清晰,过了一段时间之后就会忘记。我想记住的具体的知识点就是:leader 会维护一个 in-sync replica (ISR) 的集合:是和 leader 的进度完全一致的那些 follower。其他的先不深究。

第 30 篇是一篇思考,关于系统如何处理错误,直白一点是如何向用户、向研发展示错误。应该管用户一些提示,而不是直接白屏,用户在故障之后恢复时能正常使用系统,而不是像有些权限系统设计的那样缓存个几天。对研发而言,根据错误能快速定位到错误的地方是最重要的。开头整理的一些错误场景总结如下:依赖组件挂了;依赖服务挂了;依赖方超时了;调用方的参数有问题;调用方的参数无法正确地通过校验;用户的某种操作在业务逻辑上不具有合理性,不能够接着让他执行下去;程序自身出错了,比如数组越界,对字符串和数字进行加和操作,或者是把 null 当成了某种合法的数据结构,通过点或者下标来获取某种属性。

第 31 篇,吐槽 Go 包非中心化管理的一些问题。最主要的一个问题是不好和开源项目“合作”的问题。

第 32 篇,介绍了分布式如何实现。首先是用 MySQL 实现,但解决不了租期的问题;接着用 redis 的 setexnx 命令,也有一个问题是:因为 redis 的主从同步是异步行为,在主上加锁成功,数据没有同步之前 master 挂掉了,那之后就可能会有多个实例(用户进程)持有锁,这显然不是我们希望的。(这里我的理解是其他用户进程会能向新主申请到锁);然后就是 redis 的作者提出了 Redlock 的加锁方法。

第 33 篇,使用代码示例讲解如何使用 parser 包做一些“高级”的事情:基于 ast 做很多静态分析、自动化和代码生成的事情,非常酷炫。

第 34 篇,利用 MySQL 的 information_schema 表来自动生成代码,依然很酷炫。

第 35 篇,讲 awesome go 的入选标准,主要关注两方面:1. goreport(包含 gofmt/go_vet/gocyclo/golint/license/ineffassign/mispell) 的结果;2. 测试覆盖率(coveralls,或者 gocover)。

第 36 篇,17 年 6 月份,那时我快毕业了。当年如日中天的 ofo 也早已经一地鸡毛,用户的押金也得到几百年之后才能还清。想起那时的创始人何等风光,如今安在?本问主要探讨密码锁的一些方案设计。

第 37 篇,关于 pprof 和火焰图的使用,嗯,曹大少有的教程类文章。这里有个如果涉及到 http handler 的压测,profile 的时候可以有技巧地把 Write/Read 的开销除开。

第 38 篇,公司都是要盈利的,都有自己的业务,业务驱动其实是常态,老板只关心有没有实现想要的功能,你如何实现,实现的代码质量如何这些并不重要,这也是现在你看到的公司的各种垃圾代码,这个问题也没法解。但对于个人而言,多看好的开源代码、多看《重构》这样书,以及使用 test 等方法能一定程度上解决问题。

第 39 篇,一个比较常见的问题,之前我也写过一篇类似的[7],当时我用的一个主要工具就是:perf top

第 40 篇,回顾从 07 年入校以来的点滴,真情流露。曹大多才多艺!

第 41 篇,先是场景引入(今天刚好看到 caoz 讲的如何做分享),再层层递进。得出如果在内存中计算交集的一个方法:map[int]int。

第 42 篇,讨论阿里的一个开源库 ApsaraCache(类 redis) 所做的优化是如何实现的。主要有两点:增加对 MemCache 的支持;优化短链接。

第 43 篇,举了两个 Go 语言中 panic 无法被用户 recover 的情况:并发 map 读写;reflect.Call。结论:go 服务不用 supervisor 又不加监控就等着被开除吧。哈哈哈~

第 44 篇和第 45 篇是关于《Clean Architecture》的读书笔记,摘一句:对于商业公司的金主来说,软件系统有两方面的价值,一方面是软件的行为价值,也就是指软件的业务功能;另一方面是软件的结构,指软件的架构,易变性,可维护性,属于软性价值。软件工程师的职责是保证系统两方面的价值都能够达到最大。但是实际情况是,大多数人就只会聚焦在某一个方面,顾此失彼。

第 46 篇,宣告《Go 语言高

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值