分布式问题
问题
-
一致性问题
- 主从延迟
- 对于即时性高的接口,直接从主库中读取
- 资源抢夺
- 不进行读写分离,在主库中完成流程
- 主从延迟
-
分片id冲突
- 实现分布式ID
-
事务不支持跨库原子性
- 一个业务中可能包含多个库中的写操作,该业务需要具有原子性,但事务不具备跨库原子性
- 解决办法
- 将有关联的表放在一个数据库中
- 同库操作可以使用一个事务
- 如用户表&用户频道表,文章基本信息表&文章内容表 放在一起
- 使用分布式事务
- 核心是二阶段提交协议(简称2PC协议/XA协议)
- 会出现事务等待的情况,增加死锁的产生几率,效率低
- 实现基于消息的最终一致性方案
- 通过消息队列执行异步任务,部分失败则不断重试或全部取消
- 分布式中间件 mycat
- 一般会提供一定程度的最终一致性方案,如任务分发,任务重试,消息幂等
- 基于mysql进行了二次封装,学习/修改成本高
- 将有关联的表放在一个数据库中
-
不支持的跨库操作 join/分组/聚合/排序
- 解决办法
- 分两次查询进行,在应用端合并
- 解决办法
项目中的处理
- 复制
采用主从架构,实现了“手动读写分离”,但没有对主从延迟进行特殊处理
- 分片
- 实现了垂直分表 用户表&文章表
- 使用雪花算法生成了分布式ID, 为水平分表提供了准备(单表数据超过1000W)
- 后续分库
- 注意将相关的表放在同一个数据库节点中
- 对于跨库操作, 先分别处理, 再合并, 并根据业务逻辑实现最终一致性方案
- 应用层设计方案
- 悲观锁
- 开发者主动设置锁
- 乐观锁
- 先不加锁(假设不会有并发问题), 但是更新前校验数据一致性, 需要手动代码实现
- Django项目中先判断库存, 再生成订单,就是乐观锁设计
- 高级的乐观锁可能会采用版本号/时间戳来校验, 需要进行表设计
- 悲观锁
1.读取点赞数, 如like_count=10
3.每次更新表中的数据时,为了防止发生冲突,需要这样操作
update t_article set like_count = 11 where article_id=5 and like_count = 10;