分布式之道
认识分布式
集群
-
加服务器
- 扛量
-
实现
- 相同服务部署在多台服务器
- 服务器之间通过负载均衡
分布式
-
一个任务需要10小时
-
想要将时间缩短到1个小时
- 需要10台服务器
-
-
ABC3个应用
-
A
-
A也是可以集群化的
- A
- A
- A
-
-
B
-
C
-
-
将不同应用部署到不同服务器,形成多个节点,每个节点可以形成集群
-
同时节点之间还可以保持通信已保证分布式集群的响应输出
分布式事务
传统事务
-
ACID
- 原子性
- 一致性
- 隔离性
- 持久性
分布式事务
-
理解
- 分布式系统里面的事务
-
理论
-
CAP理论
-
C一致性
-
所有节点访问的都是同一份最新的数据库副本
-
强一致性
- 没有延迟
-
最终一致性
- 数据有延迟
- 但最终会同步到最新的
-
-
-
A可用性
-
每次请求都能获取正确的响应,不保证数据为最新的数据
- 高可用 有需要需要牺牲强一致性
-
-
P分区容错性
-
整体理解
- 已实际效果来说,相当于对通信的时限要求
- 系统如果不能在时限内达成数据一致性,就意味着发生了分区
- 这个时候就需要在一致性 和 可用性中间做出选择
-
分区
-
分布式系统由若干节点组成,每个节点之间通过网络进行通信
-
网络分区/孤立节点/脑裂
- 有些节点因为网络原因,不能继续通信
- 就会形成孤立的节点
-
-
容错
-
是一种分布式的能力
- 要做到节点之间的网络异常发送后,整个分布式系统任然可用
-
分析
-
情况1:数据只存储到一个节点上
- 发生了网络分区
- 与这个节点失去通信能力的节点都访问不到数据了
-
解决方法
-
为了提高容错能力,会被数据复制到分布式系统的所有节点上面
-
分区发生后
-
每个节点都能访问数据
- 保证了可用性
-
-
-
通过这种解决方法,提高了分布式系统的容错能力
-
-
-
代来的问题
-
复制的数据节点越多
-
节点的数据不一致的可能性就越大(网络的不确定性)
- 带来了一致性的问题
-
-
-
-
CAP为什么不能同时满足
-
PCA天平
-
P
- C
- A
-
-
举例
-
两个节点
-
N1
-
应用A
-
数据库V0
- 用户请求 V0-V1
-
-
-
N2
-
应用B
-
数据库V0
- 同步N1数据 V0-V1
-
-
-
-
正常是
- N1节点上的应用A数据发生更新变成V1,那N2上面的数据库需要同步更新成V1
-
出现网络故障
-
N1 N2 网络发生故障 N1数据是V1,N2数据是V0
-
这个时候用户访问N2节点
-
两个选择
-
1 牺牲数据一致性
- 返回用户旧的V0数据
-
2 牺牲可用性
- 让用户等,知道网络正常,数据更新到V1之后,再返回给用户
-
-
-
-
-
-
-
BASE理论
-
基本可用
-
分布式系统出现故障
- 允许损失一部分可用性
- 拿响应时间和功能上的损失换来可用
-
举例
-
访问量大的时候
- 对一些不重要的功能做降级处理
- 同时在响应时间上放宽限制
-
-
-
软状态
-
弱状态 柔性状态
- 这个中间状态不会影响系统的整体可用性
-
举例
-
在下单完成进行支付的过程中
-
我们让页面显示“支付中”
- 等待支付系统完成数据同步
-
-
数据库读写分离
- 写库复制同步到读库会有一个延时
-
-
-
最终一致性
-
在允许出现中间状态的情况下
- 经过一段时间,各项数据状态才最终达到一致
-
可以理解为弱一致性
-
举例
- 订单系统的订单状态
- 库存系统的库存状态
- 支付系统的支付状态
-
-
互联网最核心的需求:高可用
- 保证用户请求能获得相应
-
-
-
实现分布式事务方法
-
两阶段事务提交
-
理解
-
准备阶段
- 参与者完整约束检查,达成关于分布式事务一致性的共识
-
提交阶段
- 根据之前达成的共识完成相应操作
-
-
两阶段事务提交会消耗更长的时间
- 可能出现事务积压甚至死锁
- 系统的性能和吞吐量会下降
-
正常电商领域不会使用两阶段提交
- 低效
-
-
电商大促,无论峰值访问量有多大,商城系统都是确保可用的
-
数据一致性会有延迟
- 比如:付款成功,订单状态暂时未更新
- 牺牲了,C保证了A P
-
-
分布式锁
-
理解
-
线程中需要访问共享资源
-
保证线程同步安全
- synchronized
- lock
-
-
分布式系统是一个多进程的环境
-
在单体式部署到分布式部署
- 也需要锁
-
-
-
分布式锁的实现方式
-
用锁的三个过程
- 定义锁
- 获得锁
- 释放锁
-
目前采用的方式
- 数据库
- redis
- zookeeper
-
-
Redisson框架使用
-
定义任务 TestLock
-
属性
- name
- RedissonClient
- CountDownLatch
-
run方法
-
定义锁
- RLock lock = redisson.getLock(“TestLock”);
-
获取锁
- lock.tryLock(300,30, TimeUnit.MICROSECONDS)
-
处理
- dosomething
- latch.countDown();
-
释放锁
- lock.unlock();
-
-
-
通过线程池模拟创建5个线程,
通过减数器,等待最终全部完成-
main
-
创建减少计数器
- CountDownLatchlatch = new CountDownLatch(fixNum)
-
配置config
- new Config()
- config.useSingleServer().setAddress(“redis://192.168.25.130:6379”)
-
创建 RedissonClient
- RedissonClient redisson = Redisson.create(config);
-
通过线程池创建5个线程
-
threadPool1 = Executors.newFixedThreadPool(fixNum)
-
每个线程执行定义的任务
-
for (int i = 0; i < 5; i++) {}
- threadPool1.submit(new TestLock(“client-”+i,redisson,latch));
-
-
关闭线程池
- threadPool1.shutdown();
-
-
等待减少计数器到0
- latch.await();
-
System.out.println(“所有任务执行完毕”);
-
-
-
XMind - Trial Version