分布式理论和系统架构设计

CAP理论

分布式锁

分布式一致性

分布式事务

负载均衡

微服务

 

一  CAP和BASE理论

1.1  CAP理论

        分布式领域中存在CAP理论,且该理论已被证明:任何分布式系统只可同时满足两点,无法三者兼顾。很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。

 C:Consistency,一致性,数据一致更新,所有数据变动都是同步的。读操作总是能读取到之前完成的写操作结果,满足这个条件的系统称为强一致系统,这里的“之前”一般对同一个客户端而言; 

    A:Availability,可用性,系统具有好的响应性能。系统提供的服务必须处于可用的一个状态,用户的每一个请求都能在有限的时间内返回。在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

    P:Partition tolerance,分区容错性。 :以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。  出现网络故障、down机什么的还能用

满足 ca:做成一个节点

一般来讲,容错性是分布式系统必须要满足的,一般架构师根据业务特点在一致性和可用性之间平衡

elasticsesarchCAP

AP 根据CAP理论在牺牲一致性(C)的,保证了数据的分布(P)和可达(A)。当然数据是有最终一直性的。

ZookeeperCAP

ZooKeeper设计的本意是保持节点的数据一致,也就是CP。所以,这样 一来,你可能既得不到一个数据一致的(CP)也得不到一个高可用的(AP)的Service发现服务了  2台没法玩了

1.2   BASE理论

BASE理论是对CAP中的一致性和可用性进行一个权衡的结果

BA:Basically Available,基本可用

S:Soft State,软状态,状态可以有一段时间不同步

E:Eventually Consistent,最终一致,最终数据是一致的就可以了,而不是时时保持强一致

二     分布式一致性

  1. 强一致性

这种一致性级别是最符合用户直觉的,他要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响比较大。

  1. 弱一致性

这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不具体承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。弱一致性还可以再进行细分:

    1. 会话一致性:该一致性级别只保证对于写入的值,在同一个客户端会话中可以读到一致的值,但其他会话不能保证。
    2. 用户一致性:该一致性级别只保证对于写入的值,在同一个用户会话中可以读到一致的值,但其他用户不能保证。
    3. 最终一致性:最终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。

三     分布式锁

分布式锁实现的关键是在分布式的应用服务器外,搭建一个存储服务器,存储锁信息。在实现的时候要注意的几个关键点:

锁信息必须是会过期超时的,不能让一个线程长期占有一个锁而导致死锁;

同一时刻只能有一个线程获取到锁。

3.1 基于数据库实现分布式锁(主键的唯一性)

       利用第三方数据库 主键的唯一性做 锁

       在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。 (数据库字段 方法名做唯一性约束)

3.2 基于缓存(Redis等)实现分布式锁

优缺点:可以使用缓存来代替数据库来实现分布式锁,这个可以提供更好的性能,同时,很多缓存服务都是集群部署的,可以避免单点问题。通过超时时间来控制锁的失效时间并不是十分的靠谱。

设置成功返回1,

3.3 基于Zookeeper实现分布式锁

        ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:

  1. 创建一个目录mylock; 
  2. 线程A想获取锁就在mylock目录下创建临时顺序节点; 

  3. 获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁; 

  4. 线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点; 

  5. 线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。
  1. 优点:具备高可用、可重入、阻塞锁特性,可解决失效死锁问题。
  2. 缺点:因为需要频繁的创建和删除节点,性能上不如Redis方式。但是可靠性比redis高。

四   分布式事务

  1. 两阶段型: 强一致性。但是实现起来复杂、成本较高,不够灵活,有一个严重问题,不能满足高可用,性能要求不高
  2. 补偿型: 如果A成功B失败,那么回调A的回滚函数。
  3. 异步确保型:
放入消息队列。保证最终一致性
  4. 最大努力通知型: 保障,放入消息队列定时同步回滚

在分布式服务事务设计,按照不同业务设计这一个原则

  1. 如果一致性要求比较高的操作,下单-库存。补偿型+最大努力通知型
  2. 如果不是很高。可以异步确保型+最大努力通知型
  3. 最后还加上对账模式T+1。每天晚上定时比较,一致性

五    分布式思想

  1. 分片+副本+读写分离 redis mysql
  2. 分片+副本+去中心化  es

5.1   数据持久化

在分布式系统设计里面,一般恢复数据有两种方式:

  1. 快照备份(es快照是副本索引文件,redis是rdb二进制文件)
  2. translog事务日志

Elasticsearch是副本+translog(默认5s,内存到磁盘),redis是 rdb(定时快照)和aof(默认1s,内存到磁盘),es和redis如果不是实时fsync,那服务重启,可能丢死失段时间内的数据

六   微服务

6.1   什么是微服务

        微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。

  • 应用按业务拆分成服务
  • 各个服务均可独立部署
  • 服务可被多个应用共享
    • 服务之间可以通信   

6.2   实现方案

6.3   微服务治理(Hystrix、dubbo)

服务限流、熔断、降级、异步RPC是基于SOA(面向服务的架构)的分布式系统中一些常见的基本策略,并且这些策略现在都有成熟的开源框架支持。用好这些策略,对整个系统的容错性、稳定性有很大帮助。

限流

  1. 计数器限流:计数器限流只要一定时间内的总请求数超过设定的阀值则进行限流,是一种简单粗暴的总数量限流,而不是平均速率限流。
  2. 漏桶限流:漏桶可以看做是一个具有固定容量、固定流出速率的队列,漏桶限制的是请求的流出速率。漏桶中装的是请求。漏斗
  3. 令牌桶限流:令牌桶是一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌,填满了就丢弃令牌,请求是否被处理要看桶中令牌是否足够,当令牌数减为零时则拒绝新的请求。(安全性高)

熔断

服务熔断一般是某个服务(下游服务)故障引起,处理:直接短路掉,不实际调用,而是直接返回一个mock的值。而不是一直等到此服务超时。

  1. Closed:熔断器关闭状态,调用失败次数积累,到了阈值(或一定比例)则启动熔断机制;
  2. Open:熔断器打开状态,此时对下游的调用都内部直接返回错误,不走网络,但设计了一个时钟选项,默认的时钟达到了一定时间(这个时间一般设置成平均故障处理时间,也就是MTTR),到了这个时间,进入半熔断状态;
  3. Half-Open:半熔断状态,允许定量的服务请求,如果调用都成功(或一定比例)则认为恢复了,关闭熔断器,否则认为还没好,又回到熔断器打开状态;

降级

有了熔断,就得有降级。所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值

6.4   优雅停机

       Java的优雅停机通常通过注册JDK的ShutdownHook(钩子)来实现,当系统接收到退出指令后,首先标记系统处于退出状态,不再接收新的消息,然后将积压的消息处理完,最后调用资源回收接口将资源销毁,最后各线程退出执行。

核心思想:

        引流 挡板 等待停机

超过一段时间还有停止完毕,强制KILL -9

  1. 通知注销服务
  2. 开启挡板
  3. 钩子调用销毁业务服务(比如把没有消费的先给消费了)
  4. 自旋检查请求是否完成
  5. 超时KILL -9

优雅停机可以解决以下场景:

  1. KILL PID
  2. 应用意外自动退出(System.exit(n))
  3. 使用脚本命令的方式停止应用

优雅停机解决不了以下场景:

  1. 突然断电
  2. 机器物理破坏
  3. KILL-9 PID 或 taskkill /f /pid


七  负载均衡

7.1  负载均衡实现方式

一般互联网设计:

7.1.1  DNS(Domain Name System,域名系统)域名解析

client->dns server-client->web server  

缺点:集群调度不可控、应用服务器ip直接暴露、故障不能迅速转移

利用DNS处理域名解析请求的同时进行负载均衡是另一种常用的方案。在DNS服务器中配置多个A记录,如:www.mysite.com IN A 114.100.80.1、www.mysite.com IN A 114.100.80.2。

每次域名解析请求都会根据负载均衡算法计算一个不同的IP地址返回,这样A记录中配置的多个服务器就构成一个集群,并可以实现负载均衡。调度权交给了DNS服务器,DNS服务器也没办法了解每台服务器的负载情况,只不过把所有请求平均分配给后端服务器罢了。

由于DNS服务器会有缓存,该IP仍然会在DNS中保留一段时间,那么就会导致一部分用户无法正常访问网站。(解决方案:写个动态监听程序,动态dns)

7.1.2 反向代理(nginx)

反向代理服务器是一个位于实际服务器之前的服务器,所有向我们网站发来的请求都首先要经过反向代理服务器,服务器根据用户的请求要么直接将结果返回给用户,要么将请求交给后端服务器处理,再返回给用户。

优点:

  1. 隐藏后端服务器

与HTTP重定向相比,反向代理能够隐藏后端服务器,所有浏览器都不会与后端服务器直接交互,从而能够确保调度者的控制权,提升集群的整体性能。

  1. 故障转移

与DNS负载均衡相比,反向代理能够更快速地移除故障结点。当监控程序发现某一后端服务器出现故障时,能够及时通知反向代理服务器,并立即将其删除。

  1. 合理分配任务

我们可以根据服务器的配置设置不同的权重,权重的不同会导致被调度者选中的概率的不同。

  1. 静态页面和常用的动态页面的缓存

缺点:调度者压力过大 

7.2 负载均衡算法

7.2.1 轮询算法(加权)

    轮询很容易实现,将请求按顺序轮流分配到后台服务器上,均衡的对待每一台服务器,而不关心服务器实际的连接数和当前的系统负载。按公约后的权重设置轮循比率

7.2.2 随机算法(加权)

Random随机,按权重设置随机概率。在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

7.2.3 哈希算法(一致性hash)

  1. 一致性哈希

将object1、object2、object3、object4四个对象通过特定的Hash函数计算出对应的key值,然后散列到Hash环上,对象的hash值就能快速的定位到对应的机器中。

如果node3机器挂了或新增:过按顺时针迁移的规则,那么object2被迁移到了NODE4中。

  1. 首先求出memcached服务器(节点)的哈希值,并将其配置到0~232的圆(continuum)上。
  2. 然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
  3. 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。
  4. 首先求出memcached服务器(节点)的哈希值,并将其配置到0~232的圆(continuum)上。
  5. 然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
  6. 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。

保证平衡性:加入虚拟节点

  1. ip哈希:设置一个hash算法

.7.2.4 最少连接算法(least connection)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值