数据系统是无意识的,但人应该是有温度的
作为分布式课的教材之一,从学期中就开始阅读,断断续续一直到如今学期结束,也算是读完大部分内容。作者的知识面之深从行文中也可见一斑,能把技术的本质,使用场景,和不同解决办法的trade-off讲解得深入浅出。
第一部分里,第一章介绍了分布式系统的衡量标准,Reliability, Scalabity和Maintainability。在介绍服务器反应时间中,因为单纯的平均值不能反映出一些极值(outlier)的情况,于是介绍了百分位数值,就是把响应时间从小到大排列,比如P99就是顺序位置处于99%的响应时间,P50则是中位数。而像Amazon这种所谓“Customer Obsession”的公司用的则是P99.9,也就是在1000个request中,通过优化P99.9值,来保证绝大多数用户的使用体验,因为在这1000个用户当中,通常request耗时最长的用户也就说明账户中的数据最多,则消费最多,aka金主爸爸。
第二章介绍了几种常见的数据模型和它们分别的使用场景,relational model、document model、graph-like data model。同时还介绍了query language,像是declarative和imperative的区别,declarative就是你只提供你需要的结果,而不关心具体是如何实现。相反imperative则需要你提供每一步执行的指令,我们通常用的编程语言Java,Python之类的都是imperative。
有了模型,第三章就要讨论如何存储和查询数据,便要用到数据结构。从最简单append only Log开始,用Hash来存储key value pair,这种方法有着很快的查询时间,但对range-query不友好以及会占用较大的内存。如果将key进行sort,同时把整个log划分成小的segment,就解决了上面的两个问题,每个小的segment叫做一个Sorted String Table(SSTable),存在硬盘中,而在内存中存的则是这个key在硬盘中的offset。这样的一整个结构叫做Log Structure Merge Tree。除此之外还有B数,B-Tree,可以想象成多叉树结构,除了最低成的leaf node上储存的是actual value之外,其它的节点寸的都是通往那个value的索引。这一章还介绍了Data Warehousing,让我想到Snowflake公司这个名字除了创始人爱滑雪之外的第二层含义应该就是Data Warehouse中的Snowflake Schema,雪花的中心是Fact table,储存用户的每一笔消费,每一次点击,周围的dimension table(一笔消费有多个dimension,如time,product等)则像冰晶一样往六个方向延展开来,竟感受到一丝美学情怀。
第二部分开始讲分布式数据系统,这部分可以算是重点难点。首先介绍了如何实现数据分布的途径,第一种是通过Data Replication(数据复制),按照节点角色的不同为可以分为Single-leader, Multi-leader和Leaderless Replication。在Single-leader中,所有的write请求都会被direct到leader,而剩下的follower则相当于read replica主要用来提升read的速度。但是让所有的write都放在一个节点可能不符合实际需求,尤其是像今天AWS和GCP都有遍布全球的Data Center,于是有了Multi-leader,不同DC之间的leader在接收到write之后在背后通过异步(asynchronously)复制使每个leader拥有同样的数据,同时在单个DC之内使用Single-leader。Leaderless,顾名思义就是没有leader,每一个replica都可以获取用户的读/写请求。这便会有一个问题,可能由于delay,不同replica返回的结果不一样,那又如何保证eventual consistency呢?于是又引入了Read repair和anti-entropy,简单来说,read repair就是给每个reponse贴上一个version number,大家统一只返回最新的那个。anti-entropy可以理解为由于每个replica都在独立运作,系统的熵(混乱度,或者replica之间的数据差异)是趋于增加的,这时候就可以通过一种机制来不断查看replica之间的差异,并将这种差异通过复制数据来补齐从而抑制熵增的过程。
Distribute Data除了Replication还可以进行Partition,数据分区。分区通常和复制结合起来使用,即每个分区在多个节点上都保留有副本。如果分区负载均衡,则可以成倍地增加读写的throughput,但如果分布不均,则可能出现hot-spot,即某一分区承担过多负载。分区的方式有通过key range和hash of key, 第一种方便实现range query,但是容易出现hot-spot,因为frequently accessed的key可能就是那么几个。第二种可以使负载均匀分布,但是无法很好handle range query.
第七章讲Transaction,主要是一些概念的东西,比如ACID特性,Atomicity指一系列的write/read要么全部发生,要么全不发生。Consistency指保持data integrity的一些constraint,比如银行账户余额不能为负。Isolation指不同transaction之间的执行是相互隔离,而隔离的强弱又会涉及到另一话题,Isolation Level。最后的Durability指一旦transaction committed,写入的任何数据都不会丢失。
接下来两章是我看得最吃力的两章,第八章介绍了分布式系统面临的问题。主要的问题有1. 不可靠的网络,数据包可能会发生丢失或者延迟,当收不到对方节点的回应时,无法确定消息是否送达。利用timeout可以解决一些问题,但是如何选取合适的timeout又是一门学问。2. 系统中的时钟不同步,由于1的存在,导致了即使通过NTP(Network Time Procotol)也无法保证不同节点上的时钟是一致的。3. 节点可能“撒谎”,也就是Byzantine Faults. 一些节点由于硬件的malfunction而导致“撒谎”,因此在分布式系统中我们不能单一的依赖某个节点,而是要通过少数服从多数,来达到一定的quorum consistency。这一点与区块链技术有点相似,在一个peer-to-peer的系统中,需要从一堆mutually untrusting parties中得到对某个transaction的一致认可。不过即使分布式系统存在诸多挑战和问题,但我们依旧可以在此基础上创建一个可靠的系统。好比IP是不可靠协议,会发生丢包,延迟,但是基于IP的TCP协议却是可靠的。
第九章介绍了如何达到Consistency和Consensus。Linearizability可以理解为让整个系统看起来好像只有一份数据,~=strong consistency/immediate consistency。前面说过一种eventual consistency,是一种很弱的达到一致性的模型,还有一种causal consistency,则是介于二者之间。因为Linearizability的最强一致性会带来网络中断情况下可用性很差的问题,实际上几乎很少使用。本章还介绍了如何实现分布式系统中的consensus,需要取得consensus的场景比如有Leader election, Atomic commit。Two-Phase commit是一种在多个节点中实现atomic transaction commit的算法,工作原理是引入了一个coordinator,原先在single node一步就能完成的commit现在分成两步,phase1询问各个node是否ready to commit,只有当所有的node都返回yes才会触发phase2: 发送commit的request,同时coordinator需要将commit或是abort的决定写入log防止coordinator自己crash。而在实际中,我们并不需要开发consensus algorithm,而是可以利用类似ZooKeeper这样的服务来将consensus algorithm外包出去,除此之外还有failure detection, membership service. 最后也直接给出建议,如果你需要系统有这些特性,还要求fault tolerant,直接用ZooKeeper好了。
第三部分粗略读了batch processing和stream processing. 最后一章直接拔高主题,升华到社会责任的层面。前面十一章的内容介绍tech,最后一章谈及ethic。作者不仅技术牛逼,更是具有社会责任感和人文关怀的程序员。《黑镜》有一集就讨论了这个问题,通过算法给每个人打分,结果每个鲜活的个体都沦为一个个冷冰冰的分数,而这些数据算法,正是放大善与恶的帮凶。作者说作为工程师,我们都应该treat data with humanity and respect. 如果每个工程师都能恪守这一呼吁,don’t be evil,那么《黑镜》的世界应该也就不会到来。