高可用、高伸缩系统架构知识
本文为《分布式Java应用与实践》笔记。
一、负载均衡机器选择
- 随机选择
- Hash选择:静态页面加载,常见用于静态图片加载
- Round-Robin:根据地址列表按顺序选择
- 按权重选择:静态权重和动态权重
- 按负载选择:需要搜集负载状况,实际较少使用
- 按连接选择:按连接数多少分配,但新开机器问题大
- unicorn策略:所有顾客到一个收银台排队,收银员处理完毕后亮灯通知
二、 2PC保证一致性
基本流程:
- 开启事务
- 通知master执行(写入undo和redo)
- 如有一个master反馈不能执行,则回滚(rollback)
- 通知所有master完成操作(commit)
缺点:
- 同步阻塞问题
- 协调者单点故障
- 数据不一致(commit请求发送,有些没收到)
- 协调者和唯一参与者全部宕机,事务永远不确定状态
三、 3PC保证一致性
- 在2PC基础上增加了preCommit阶段,canCommit,doCommit
- master收到preCommit之后继续等doCommit或者等一段时间后提交
- 优缺点:
- 超时执行减少了对资源的阻塞
- 同时产生一定的数据一致性问题,例如abort没有及时到达
四、 尽可能避免错误
- 设计可容错的系统:一是Fail Fast原则,有错误的时候立刻中断流程,避免无谓操作,二是保证接口和对象设计的严谨性
- 设计具有自我保护能力的系统:警惕所有第三方调用,设计缓存等
限制使用资源:
- 避免过大的HashMap等集合
- 注意释放不再引用的对象(ThreadLocal的set(null)方法)
限制日志文件的使用
- 限制网络资源:使用连接池;保留操作系统资源
- 限制线程的使用:选择合适的线程池
五、 垂直伸缩
增加CPU后得不到改善的情况:
- 单线程任务:考虑并行分解任务,SUN的Fork/Join
- 锁竞争激烈:尽可能降低锁竞争的部分
- 支撑并发请求的线程数固定:根据CPU数量计算合理的线程数
增加内存后得不到改善的情况:
- cache集合大小固定:根据可用内存大小计算
- JVM堆内存固定:需要进行相应调整
支撑大数据量:
- 分库:访问分散,数据库关联查询增加
- 分表:单张表数据减少,但开发复杂(DAL),分页较为麻烦