总遇到留言说我最近写鸡汤,不写技术。
其实吧,我脱离技术大概五年多了,五年没有coding,没有code review,没有跟员工讨论具体技术实现问题,(啊,不是完全没有,有一次半夜急了跟开发商调bug,就那么一次,手生的厉害,所幸搞定了)。偶尔遇到一些圈里朋友咨询技术问题,都是靠当年带出来的徒弟或者其他朋友帮忙应付。所以今天我去谈技术,都只是谈一些上古时代的东西了,那么多技术网红都在写一线的东西,好多新东西我都没听说过,哪里敢冒出来露丑。
再说,以前写过的技术系列,访问量和传播率都不是那么可观,大概也反映了读者的态度。
如何应对并发(1) - 关于数据索引
如何应对并发(2) - 请求合并及异步处理
如何应对并发(3) - 需求裁剪
如何应对并发(4) - 分布式数据库及反范式设计
如何应对并发(5) - 关键的关键,是认识负载
如何应对并发(6) - 琐碎的日常
史上最简单的推荐系统设计
我在旧文中多次提到discuz,比如下面这篇。
从CNZZ历史讲创业与打工的区别
因为第一呢,当年大部分php程序员都接触过这个代码,所以面试的时候我也喜欢从中找问题点。第二呢,当时我们对这个代码吃的还是比较透的,确实学了很多东西。
那么,今天,就从这里入手,讲讲我当初,通过discuz体会和领悟到的一些技术细节,虽然是上古时期的技术,但是对于一些应届生或者是新入行的服务端程序员,我个人认为,还是有一点价值的。
当然,如果您是技术高手,可能会觉得本文很low,烦请自行忽略,谢谢。
1、数据索引的设计,特别是复合索引
Discuz的索引设计和SQL代码都写的非常好,从纯粹的数据库索引优化来说,基本达到极致,索引这问题说简单也简单,会者不难,但是很多很多初入行的和大学刚毕业的并不是很理解索引效率的关键,我上面列的文章有专门一篇讲这。
当年面试有个送分题,mysql里,一个数据查询可以用到几个索引,一个索引可以用到几个字段,这个居然也会有不少人搞不清楚。(当然,上古时期的Mysql和现在又有了区别,据说新版本的Mysql已经可以支持一条查询多个索引了,具体情况我没有测试和验证过。)
基于此,复合索引,索引字段的选择,顺序的设计,性能的分析,其实我对复合索引很多认识的启蒙和认知的校验,都是通过Discuz的数据结构体会到的。
2、二分查找
Discuz关于用户所在地区的查询,我常用的一个经典面试题,通过ip表快速反查地址,每秒效率要求千次以上,我专门扒过discuz的代码,有一部分是用二分法查询实现的,但实话说,discuz代码执行效率并不高,原因是因为这是一个通用系统,没有用到共享内存机制,所以源数据加载这块效率浪费很大。
但二分查询是一个对有序队列快速定位查询非常有效简单的算法,当然,我这么说出来,肯定很多人觉得很简单,但是遇到实际场景,还是有很多人想不到用这样的解决思路。
3、安全存储
Discuz在用户信息存储中,在密码加密环节用了随机Salt,很多知名网站都没有意识到随机salt的意义和目的。简单重述一下,这是你数据库被扒之后仍能保证用户密码安全的有效方式。
我一开始对这个策略也有点糊涂,后来隔了一段时间才明白过来。
信息安全常识科普
创业公司如何做好信息安全(上)
创业公司如何做好信息安全(下)
4、不迷信内存效率
这个纯粹从代码和数据结构来看,可能真的看不到,但我记得戴志康好像分享过心得,说正确使用数据表结构,比使用内存效率更高,当时分享的是针对是discuz的用户session表设计思路,开始听上去觉得不可思议,但后来发现这是对的。
这个其实给我们后续研发有了很大的启发,就是不迷信内存的效率,我们都知道内存读取写入的效率远高于物理硬盘,但是如果我们无结构的读取并处理数据,可能就明显不如有正确结构的数据表操作,在后续的优化过程中这样的范例数不胜数。
后来我们研发工程师(我带出来的哦),也跟我说,经过实测分析,通过memcache读取大块数据并获得其中的细节信息,效率远不如读取正确索引设计下的数据库记录。
另一个典型范例是,当时我们用到的一些缓存表最初是myqsl的heap引擎,因为这是内存引擎么,想当然很快,后来使用过程中发现存在严重问题调整为物理存储的innodb引擎。原因其实很简单,heap引擎是表级锁,大量查询请求时经常锁死,而innodb是行级锁,并发查询下执行效率更优。
那么有人会说,innodb的写入效率是灾难,哦,其实用异步机制写入,效率可以和myisam不相上下的。
此外,写入效率影响很大的一个环节是binlog文件处理,这里跟淘宝余峰学了一招,顺便分享给大家,binlog是顺序写,索引文件是随机写,顺序写比随机写效率要高一个数量级,所以正确的解决方案是,用单独的物理硬盘存储binlog,可以有效避免同时写binlog和索引文件的不必要开销。
余峰的大招很多,比如还有如何充分挖掘多核cpu的缓存加载原理来提升mysql查询和同步效率等等,类似这样的,但限于我的技术基础薄弱,以及我们应用场景毕竟没有那么苛刻,这类的黑科技完全没学会。(由于没学会,可能描述不够严谨)
这里引申一个问题,不迷信内存效率,要正确理解不同数据存储引擎,存储类型的特点和适用场景。
比如mysql的myisam, innodb, heap三种不同常见存储引擎的优缺点和适用范围;比如前文留言有人提到redis,redis是mysql非常好的补充,二者结合可以解决极大多数情况下的数据并发场景,但redis四种数据结构,各有什么优缺点,各有怎样的适用范围,在不同场景下如何选择,这依然需要很透彻的了解才能做到。
我们当年对discuz, + ucenter + uchome的代码做了比较深度的优化和处理,主要处理思路也可以分享一下。