注明:原文由【薛定谔猫】发表于其个人微信公众号【架构师是怎样炼成的】中。
双十一终于过去了,趁双十二的需求还没下来前,晚上稍微有点时间搞点自己的事情了,距离上篇微信公众号文章已经过去快三个月了,今天决定写一篇关于分布式知识体系的文章,分布式架构整个知识体系纷繁复杂,不加以总结很难形成知识网络.我将从基础理论,系统设计,高可用三方面总结分布式知识体系.
基础理论
1. 节点与网络
➤ 节点
传统的节点指的是一台单体的物理机,包含所有的服务及数据库(即传统的单体应用),随着虚拟化的发展,单台物理机上可以部署多台虚拟机,实现资源利用的最大化,节点也变成了单台虚拟机上的服务,目前随着容器技术的成熟,服务逐步在容器化(目前阿里的服务已100%容器化,基于自研的pouch容器,此容器已开源),也就是节点只是轻量级的容器服务.总体来说,节点就是能提供单位服务的逻辑计算资源的集合.
➤ 网络
分布式架构的根基是网络,不管是局域网还是公网,没有网络一切都无从可谈,对于网络需要至少熟悉传输层(TCP)与应用层(Http)常见协议
2. 一致性理论
2.1 强一致性理论ACID
➤ Atomicity:原子性一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在某个中间环节
➤ Consistency:一致性是指事务使得系统从一个一致的状态转换到另一个一致状态,在事务开始之前和结束之后,对数据库没有完整性没有破坏
➤ Isolation:隔离性,并发事务之间互相影响的程度,数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行导致的数据不一致(脏读,可重复读,幻读,串行化)
➤ Durability:持久性 事务处理结束后,对数据的修改书永久性的,即使系统故障也不会丢失(除非所有的备份磁盘都永久损坏了)
2.2 分布式一致性CAP
分布式环境下,我们无法100%保证网络正常连接和信息的传送(毕竟网络是不可靠的),于是发展出了CAP/FLP/DLS三个重要理论
➤ CAP:分布式计算系统不可能同时保证一致性(Consistency),可用性(Avaliablity),分区容忍性(Partition),只能做出取舍,保证两个.
➤ FLP:在异步环境中,如果节点间的网络延迟没有上限,只要有一个恶意的节点存在,就没有算法能在有限的时间内达成共识.
➤ DLS:
1)在一个部分同步的网络模型(网络延时有界限但是我们不知道在哪里)下的协议可以容忍1/3(拜占庭)任意错误.
2)在一个异步模型中的确定性的协议(没有网络延时上限)不能容错.
3)同步模型的协议(网络延迟可以保证小于已知时间)可以达到100%错误.
2.3 弱一致性Base
多数情况下,其实我们也并非要求强一致性,部分业务也可以容忍一定程度的延迟一致,所以为了兼顾效率,发展出来的最终一致性BASE理论,BASE是指基本可用Basically Available),软状态(Soft State),最终一致性(Consistency)
➤ 基本可用Basically Available):分布式系统在出现故障的时候,允许损失部分可用来保证核心可用.
➤ 软状态(Soft State):指允许系统存在中间状态,而该中间状态不会影响系统整体可用性,分布式存储中一般数据至少会有三个副本,允许不同节点副本同步的延时就是软状态的体现.
➤ 最终一致性(Consistency):最终一致性是指系统中所有数据副本经过一定时间后,最终能够达到一致的状态.弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况.
2.4 一致性算法
一致性算法是分布式系统最核心本质的内容,包含:
➤ Paxox(如zookeepr)
➤ Raft(如etcd,consule)
➤ Gossip(如redis)
系统设计
1. 文件系统
单机计算机的存储始终都有上限,随着网络的出现,多台计算机协作存储文件的方案也相继被提出,现代分布式文件系统的奠基论文是来自Google的《The Google File System》,常见的分布式文件系统有:
➤ HDFS
➤ FastDfS
➤ Ceph
常见分布式文件系统(来自维基百科)
2. 数据库
数据库其实也数据文件系统,只是在文件系统的基础上增加了事务,检索等高级特性,所以复杂度更高,传统的关系型数据库为了兼顾事务和性能的特性,在分布式方面的发展有限,非关系型数据库摆脱了事务的强一致性束缚,达到了最终一致性.
➤ 关系型数据库:Mysql,Oracle
➤ 列式存储:Hbase
➤ 文档型存储:ElasticSearch,MongoDb
➤ KV类型:Redis
3. 计算
分布式计算是在分布式存储的基础上,充分发挥分布式系统的数据冗余备份,多副本高效获取数据的特性,从而进行计算,把原本需要长时间计算的任务拆分成多个任务并行处理,从而提高效率
➤ 离线计算:Hadoop
➤ 实时计算:Spark
➤ 流式计算:Storm,Flink,Apache Steams
4. 缓存
缓存作为提升性能的利器无处不在,小到CPU与内存之间的缓存,大到分布式应用缓存,分布式缓存系统大大提升了数据访问时间,带来的问题是如何保证数据一致性,引入分布式锁来解决
➤ 持久化:Redis
➤ 非持久化:Memchache
5. 消息
分布式系统需要一个连接组件和服务的消息传递中间件,理想情况是松耦合的方式,以便最大限度的提高可伸缩性,异步消息传递被广泛使用
➤ Kafka
➤ RocketMq
6. 日志
错误对于分布式系统来说在家常便饭,在而我们设计系统时本身就需要把容错作为普遍存在的现象来考虑,那么当错误出现的时候,如何快速定位和恢复就非常重要了.
对于小则几十个节点,多则几点节点的分布式集群来说,将日志统一收集也是分布式系统必须考虑的,ELK目前已成为标配
➤ E:ElasticSearch
➤ L:LogStash
➤ K:Kibana
高可用
1. 流量调度
1.1 负载均衡
负载均衡是我们对服务如何消化流量的通用设计,通常分为物理层的底层协议分流的硬件负载均衡和软件层的软负载均衡,负载均衡解决方案已是业内成熟的方案,我们通常会针对特定业务在不同场景进行优化,常用的负载均衡方案
➤ F5
➤ LVS
➤ Nginx/Tengine(阿里基于Nginx开源)
常用负载均衡算法:
➤ 轮询法(Round Robin)
➤ 加权轮询法(Weight Robin)
➤ 随机法(Random)
➤ 加权随机法(Weight Random)
➤ 最小连接法(Least Connections)
➤ 源地址哈希法(Hash)
➤ 一致性哈希法(Consistency Hash)
1.2 网关设计
在我们建设好分布式系统后,最先受到考验的关口就是网关了,我们需要关注系统流量的情况,也就是如何对流量的管理,我们追求的是在系统可容纳的流量上限内,把资源留给最优质的流量使用,而把非法恶意的流量拦在门外,这样在节省成本的同时确保系统不会被冲击而宕机.
负载均衡首当其冲的就是网关,中心化集群流量最先到的打到的地方就是网关了,如果扛不住的话,那么整个系统将不可用
➤ 高性能:网关设计第一需要考虑的是高性能的流量转发,网关单节点通常能达到上百万的并发流量
➤ 分布式:出于流量压力分担和灾备考虑,网关设计同样需要分布式
➤ 业务筛选:网关同设计简单的原则,排出调大部分的恶意流量
➤ 请求校验:请求鉴权拦截非法流量
➤ API聚合:聚合服务端接口,减少服务调用
常用的企业级网关有:
➤ Nginx+_Lua自研网关
➤ Kong
➤ Zuul网关
1.3 流量控制
流量分配
➤ 计数器
➤ 队列
➤ 漏斗
➤ 令牌桶
➤ 动态流控
流量限制
在流量激增的时候,通常我们需要有流量措施来防止系统出现雪崩,那么久需要预估系统的流量上限,然后设定好上限数,但流量增加到一定阈值后,多出来的流量则不会进入系统,通过牺牲部分流量来保全启动的可用性
➤ 限流策略
➤ QPS粒度
➤ 线程数粒度
➤ RT阈值
➤ 限流工具:这里强烈推荐一款阿里今年开源的限流利器Sentinel,历经双十一历练
2. 服务调度
打铁还需自身硬,做好流量调度后,剩下的就是服务自身的健壮性了
2.1 注册中心(服务的根据地)
➤ zookeeper
➤ etcd
➤ conule
➤ eureka
2.2 服务编排
通过消息的交互序列来控制各个资源的交互,参与交互的资源都是对等的,没好友集中的控制,微服务环境下服务众多,我们需要一个总的协调器来协议服务之间的依赖,调用关系,k8s是我们的不二选择
2.3 服务控制
发现:
服务启动后需要发现注册中心,并且把自身的服务信息注册到网关,也即是网关接入,注册中心则会监控服务的不同状态,做健康检查,把不可用的服务归类
降级:
当用户激增的时候,我们首先在流量端做手脚,也就是限流,当我们发现限流后系统响应变慢了,有可能导致更多问题时,我们需要对服务本身做一些操作,服务降级就是把当前不是很核心的功能关闭掉,或者不紧要的准确性放宽范围,时候在做一些人工补救
➤ 降低一致性约束
➤ 关闭非核心服务
➤ 简化功能
熔断:
当我们做了以上的操作后,还是觉得不放心,那么就需要对数据再进一步操作.熔断是对过载的一种自身保护,一般我们的服务依赖的其他的二方服务,有的二方服务可能会因为业务量的突增或者大部分机器宕机导致自己在调用此二方服务长时间不能返回,这些长时间不能返回的二方请求会占用大量的线程等资源,造成了其他的并不依赖该二方服务的接口因为资源较少性能严重下降,甚至自己的服务器因为没资源而崩溃,此时需要对此二方请求进行熔断,熔断状态有
➤ 闭合状态
➤ 半开状态
➤ 断开状态
➤ 熔断工具:Hystrix
3. 数据调度
数据存储最大的挑战就是数据冗余的管理,冗余多了效率低且占用资源,副本少了起不到灾备的作用,我们通常的做法是把有状态的请求,通过状态分离,转化为无状态的请求
➤ 状态转移:分离状态全局存储,请求转换为无状态流量,比如我们通常会将登陆信息缓存至全局的redis中,而不需要在多个应用中去冗余用户的登陆数据
➤ 分库分表:数据横向扩展
➤ 分区分片:多副本冗余
4. Devops
分布式配置中心:
全局配置中心按环境来区分,统一管理,减少了多处配置混乱的局面
➤ Diamond(阿里内部未开源)
➤ Apollo
➤ SpingCloud Config
5. 部署策略
微服务部署是家常便饭,如何让我们的服务更好的支撑业务发展,稳健的部署策略是我们考虑的,如下的部署策略适合不同业务和不同阶段
➤ 停机部署
➤ 滚动部署
➤ 蓝绿部署
➤ 灰度部署
➤ A/B测试
6. 作业调度
作业调度是系统必不可少的环节,传统的方式是在Linux服务器上配置crond定时任务或者直接在业务代码里面完成调度任务,现在已有成熟的方案:Elastic-job
7. 全栈监控
由于分布式系统时由众多机器共同协作的系统,而且网络也无法保证完全可用,所以我们必须建设一套各个环节都能监控的系统,这样我们才能从底层到各个层面进行监控,出现意外及时修复,不让我们的系统裸奔
➤ 基础层:CPU,I/O,内存,线程,吞吐,负载,JVM
➤ 中间件:分布式系统接入了大量中间件系统,中间件本身也需要监控
➤ 应用层:qps,rt
➤ 监控链路:zipkin,pinpoint,eagleeye等等分布式链路跟踪
注明:本文为转发文章,原文由【薛定谔猫】发表于其个人微信公众号【架构师是怎样炼成的】中。