本文只是对所读书籍做一些总结,不代表博主的实战经验,#_#(注:有时候中间件的可扩展性视为可伸缩性,因为可扩展性和高可用性通常是相关联的)。
也叫高并发,主要指标有响应时间、并发数、吞吐量等。
1、Web前端方面
浏览器:缓存、压缩、合并请求、减少Cookie传输、延迟加载JS
CDN、反向代理:缓存静态资源
2、应用服务方面
使用缓存:本地缓存、分布式缓存、多级缓存
尽量异步:消息队列(MQ)、异步方法(@Async)
搭建集群:横向扩展
优化编码:多线程、算法、数据结构、对象复用(池化)、GC
3、数据库
字段优化:类型选择、是否需要索引、冗余
索引:执行计划、避免失效
缓存:MySQL缓存、Mybatis一级二级缓存
SQL优化:减少JOIN、批量操作、注意大事务和死锁
读写分离、分库分表:sharding-jdbc / Mycat
4、中间件
ES、Redis、MQ、ZK...
5、硬件
增加带宽、换SSD
业界通常使用多少个9衡量,比如4个9即99.99表示一年最多53分钟不可用。
网站不可用时间(故障时间)= 故障修复时间点 - 故障发现(报告)时间点
1、应用失效转移
搭建集群进行负载均衡
2、数据冗余备份
主从架构:MySQL、Redis
3、优化代码
限流、降级、超时、重试、隔离
4、避免
压测、监控
5、紧急处理
回滚、预案
临时搞个促销,多加几台机器性能就上去了,活动结束,机器撤掉------这就体现了可伸缩。
应用服务器集群:无状态
缓存服务器集群:哈希取模算法、一致性哈希算法
数据库集群:增加从库
中间件:不支持的就别用了
产品:突然想到一个需求,你下班前搞好(调侃,正规点的流程都不允许)
工程师:好咧,我加一下XX就可以了
程序猿:啊?这样整个XX都要重写,有点难哦
------显然,工程师的代码耦合性低,容易扩展
1、事件驱动架构
观察者模式(发布订阅)、消息队列(MQ)
2、分布式服务
业务和基础可复用的区分拆开
3、数据结构
反例:ElasticSearch修改字段需要重建索引(一般预留字段)
正例:Hbase的列族设计就很灵活
4、开放接口平台
异步复制,优先保证可用性,但会最终一致性。
1)主库每次提交事务之前,将数据更改的事件记录到二进制日志(Binary Log)中。
2)首先从库启动一个I/O线程,请求主库建立一个普通的客户端连接,然后主库启动一个特殊的二进制转储(binlog dump)线程读取二进制日志中的事件,最后从库的I/O线程将接收到的事件记录到自己的中继日志(Relay Log)中。
3)从库的SQL线程读取中继日志中的事件将其重放。
基于语句的复制:SQL。基于行的复制:数据。
MySQL能够动态切换,默认情况下使用基于语句的复制,不行了就切换到基于行的复制。用户也可以通过binlog_format进行设置。
主从:
异步复制,不满足强一致性,因为是否成功不影响主节点对外提供写服务,所以保证可用性。
从节点会使用各种策略全力追赶主节点,所以最终一致。
Redis同步支持主从同步和从从同步(后续版本增加,以减轻主节点的同步负担)。
主节点会把写指令记录在本地的内存buffer中,然后异步复制到从节点,从节点一边重放一边向主节点反馈自己同步的偏移量。buffer有限且是定长的环形数组,如果内容满了会被从头覆盖,这时候需要执行快照同步。
主节点快照同步时把当前内存的全部数据快照到磁盘文件然后把它们传送到从节点,从节点接收完毕首先清空当前缓存执行全量加载然后继续增量同步。快照同步过程中如果主节点又发生覆盖buffer的情况,只能再次进行快照同步了。避免这种死循环可以配置合适的buffer大小参数。
新节点加入时,先快照同步,完成后增量同步。
Redis 2.8.18版本 之后支持快照同步的无盘复制,主节点遍历内存直接将序列化的内容发送到从节点。
Redis 3.0版本 之后使用wait指令可以让异步复制变身同步复制,这样就保证了强一致性。
哨兵模式Sentinel可以监控主节点状态实现自动主从切换,它的min-slaves-to-write和min-slaves-max-lag两个选项可以限制主从延迟过大,表示在指定时间内(第二个参数,秒)至少有指定数量(第一个参数)的从节点完成了正常复制,否则就对外停止写服务,丧失可用性。
集群:
数据各自独立(这样才能扩容)。
采用基于Paxos协议(个人觉得太难理解了~)的ZAB协议。节点分为Leader、Follower和Observer三种角色类型。
// TODO
// TODO
AP优于CP,即优先保证可用性,但会最终一致性。
多个副本之间采用对等复制(Peer to Peer),不分主从,都可以进行写操作,然后相互之间进行数据更新。这样难免存在冲突问题,如何解决呢?
Eureka Server启动时进行syncUp操作,先从其中一个节点获取注册的应用实例信息,然后复制到其它节点。复制时使用HEADER_REPLICATION的heep header来标识,这样其它peer节点收到之后就不会再对它的peer节点进行复制了。
使用lastDirtyTimestamp标识数据版本高低,使用heartbeat也就是renewLease操作进行节点之间数据修复。
// TODO
主从:
使用Zookeeper
集群:
// TODO