//---------- 需求 ----------//
互联网各个领域
教育
医疗
农业
娱乐
社交
购物
旅游
政府
金融
交通
//---------- 架构演变 ----------//
一旦业务开始加速发展,用户逐渐增多,系统瓶颈开始暴露,可以做以下四点调整
独立部署
web服务器集群,实现可伸缩性
部署分布式缓存系统,使查询尽可能在缓存命中
数据库实施读/写分离,实现HA(高可用)架构
发展到一定阶段
利用cdn加速系统响应
业务垂直化,降低耦合,从而实现分而治之的管理
soa
微服务
//---------- 系统服务化需求 ----------//
超时和重试(failover 读操作)
<!--- 服务调用失败时, 重试其他服务节点,通常用于读操作 --->
<dubbo:registry cluster="failover" />
<!--- 只发起一次调用, 失败立即报错,通常用于非幂等性的写操作 --->
<dubbo:registry cluster="failfast" />
<!--- 失败安全,出现异常时直接忽略,通常用于写入审计日志等操作 --->
<dubbo:registry cluster="failsafe" />
<!--- 失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作 --->
<dubbo:registry cluster="failback" />
<!--- 并行调用多个服务节点,成功1个即返回,通常用于实时性要求较高的读操作 --->
<dubbo:registry cluster="forking" />
上面的配置也适用于服务提供方,如果服务调用方和服务提供方配置有相同的参数, 默认以调用方为主
服务治理
服务的动态注册与发现
服务的扩容评估
服务的升/降级处理
黑白名单
权限控制
服务负责人
资源调度
服务跟踪
分布式事务
分布式事务一般情况下保持最终一致性即可
jvm调优,吞吐量和低延迟是相互矛盾
//---------- 分布式调用跟踪系统 ----------//
(定期清理数据)
服务性能低损耗
业务代码低侵入
监控界面可视化
数据分析准实时
dubbo RpcContext
采样率方案(可配置)
//---------- 大流量限流/消峰 ----------//
问题:
连接资源耗尽
分布式缓存的容量被撑爆
数据库吞吐量降低
方案:
扩容
动静分离(静态放cdn)
缓存
服务降级
限流
令牌桶算法限制的是流量的平均流入速率
漏桶算法限制的是流量的流出速率
guava ratelimiter
nginx 接入层限流
http {
# 定义每个IP的session空间大小
limit_zone one $binary_remote_addr 20m;
# 与limit_zone类似,定义每个IP每秒允许发起的请求数
limit_req_zone $binary_remote_addr zone=req_one:20m rate=10r/s;
# 定义每个IP能够发起的并发连接数
limit_conn one 10;
# 缓存还没来得及处理的请求,缓存不下新的请求将会被拒绝和抛弃
limit_req zone=req_one burst=100;
server {
listen 80;
server_name localhost;
location / {
stub_status on;
access_log off;
}
}
}
消峰
分时段
排队
异步
多线程/fork join
mq(activeMq)
rocketMQ
支持顺序消息
支持事物消息
支持集群与广播模式
亿级消息堆积能力
完善的分布式特性
支持push和pull两种消息订阅模式
单master模式
多master模式(建议,宕机不能消费)
多master/slave异步复制模式(性能低)
多master/slave同步双写模式(性能高)
//---------- 分布式配置管理服务案例 ----------//
集中式资源配置需求
配置信息统一管理
动态获取/更新配置信息
降低运维人员的维护成本
降低配置出错率
zookeeper
配置管理
分布式协调/通知
分布式锁
统一命名
节点维护着一个版本号(dataVersion),随着数据的变更递增
实现Wathcer接口用于监听事件变更
Znode不适合存储大数据
// bean动态注册
//实现接口ApplicationContextAware
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//如果Bean定义中配置了数据源信息,一定要将属性"destroy-method"设置为"close"
ConfigurableApplicationContext cfgContext = (ConfigurableApplicationContext)applicationContext;
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)cfgContext.getBeanFactory();
new XmlBeanDefinitionReader(beanFactory).loadBeanDefinitions(new FileSystemResource(""));
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName: beanNames) {
beanFactory.getBean(beanName);
}
}
客户端容灾
Diamond
配置信息固化到服务端数据库,服务端本地缓存,客户端本地缓存中
//---------- 大促场景下热点数据的读/写优化案例 ----------//
缓存
缓解应用系统或关系型数据库的负载压力
提升系统吞吐量
Ehcache
Ehcache的本质是同一个进程内的缓存技术
特殊的应用场景下,本地缓存 + 分布式缓存
oof-heap
存放生命周期长的对象
redis
jedis
集群
水平化处理
分布式缓存可能存在的单点瓶颈
同一热卖商品高并发读需求
基于redis集群多写多读方案
使用zookeeper来配置同一热卖商品的key
localcacahe结合redis集群的多级cache方案
本地缓存只需缓存两类数据+定时轮询查询更新+不设置TTL过期策略
商品详情
商品库存
实时热点自动发现机制
同一热卖商品高并发写需求
乐观锁
利用"实际库存数>=扣减库存数"
查询InnoDB行锁时所引起的一系列问题
select * from information_schema.INNODB_TRX where trx_state='LOCK WAIT';
分布式锁来避免超卖
分布式锁不能沦为系统瓶颈
不能产生死锁
支持重入锁
redssion
clusterServersConfig.setMasterConectionPoolSize(100);
clusterServersConfig.setSlaveConnectionPoolSize(100);
clusterServersConfig.setTimeout(1000);
redisson = Redisson.create(config);
RLock lock = redisson.getLock("xxx");
lock.lock(20,TimeUnit.MILL);
lock.unlock();
boolean lockResult = lock.tryLock(10,20,TimeUnit.MILLISECONDS);
if(lockResult) {
lock.forceUnlock();
}
批量提交扣减库存
库存扣减结果如何响应给指定的用户
如何避免商品库存售不罄
redis watch命令实现乐观锁
控制单机并发写流量方案
单机排队串行写方案(不建议)
抢购限流方案
AliSQL5.6.32
//---------- 数据库分库分表案例 ----------//
数据库读写分类
数据库垂直分库
数据库水平分库分表
sharding
sharkey(路由条件)
定义一套特定的路由算法和规则
Cobar 代理
Mycat 代理 √
Shark 应用集成 √
Shark
支持两类分库分表模式
单库多表模式
多库多表模式
读写分离
wr_index=r32w0 //不配置读写分离 r0w0
分库分表模式
shardMode=true
consistent=true
分库路由算法
dbRuleArray=#key1|key2# % 1024 / 32
分表路由算法
tbRuleArray=#key1|key2# % 1024 / 32
表后缀拼接规则
tbSuffix=_0000
com.sharksharding.core.shard.SharkDatasourceGroup
targetDataSources
key=0
value-ref="dataSource1"
...
扩容
片的数量=2*库的数量
使用jdbcTemplate
如果sql语句中的第一个参数并不是定义在配置信息中的路由条件时,那么shark将抛出异常
分库分表后的影响
acid如何保证
多表之间的关联查询如何进行
无法继续使用外键约束
无法继续使用oracle提供的sequence或mysql提供的AUTO_INCREMENT生成全局唯一和连续性ID
避免多表联合查询
多级sequenceId
shark获取唯一性和连续性的sequenceID
建表
配置数据源
SequenceIDManger.init(dataSource);
调用SequenceIDManger.getSequenceId(100,10,5000); //IDC机房,业务类别,数字长度(向数据库申请的ID缓存数)
Solr
满足多维度的复杂条件查询(解决like模糊查询慢)
分布式事务
两阶段提交协议
三阶段提交协议
paxos协议
尽量避免分布式事务
数据库高可用方案
主从
基于配置中心实现主从切换(手动切换)
shark
GetJdbcTemplate.getJdbcTemplate();
<bean /> 标签中属性destroy-methos一定要设置为close
基于Keepalived实现主从切换(自动切换)
基于MHA实现主从切换
mysql半同步复制
峰值流量较大的场景TPS有影响
(分库分表后)订单冗余表需求
同一份(买家卖家)订单数据进行冗余存储
数据同步写入
数据异步写入
优先保证买家的数据落盘
保障冗余表的数据一致性
最终一致性
线上检测补偿
基于增量日志扫描的线下检测(定时任务扫描)
1,单机
2,集群
3,使用cdn加速系统响应
4,垂直拆分
5,企业soa
6,微服务架构
服务化与RPC
序列化与反序列化在重性能场景可以使用二进制协议
为dubbo设置超时时间应该是有针对性的,业务时间短,设置短,业务时间长,设置长一些
写服务不建议开启failover,读服务开启才会显得有意义
限流
令牌桶算法流程
漏桶算法流程
rocketMQ
消峰案例
缓存优化-cdn
缓存
多级缓存
实时自动发现机制
库存扣减
库存扣减优化
redis watch
并发写抢购
读写分离
垂直分库
水平分库分表
数据库高可用
主从
keepalived
mysql半同步复制机制
写冗余表(起线程或者队列)
线上检测补偿机制
线下检测补偿