文章目录
- 前言
- 一、分布式高并发问题
-
- [1. 分布式锁](#1. 分布式锁)
- [2. 分布式事务](#2. 分布式事务)
- [3. 分布式ID](#3. 分布式ID)
- 二、高并发高性能
-
- [1. 客户端优化](#1. 客户端优化)
- [2. 网络层优化](#2. 网络层优化)
-
- [(1)NDS+CDN 多地部署](#(1)NDS+CDN 多地部署)
- (2)网关层添加黑名单
- (3)负载均衡和静态服务器
- [3. 应用层优化](#3. 应用层优化)
-
- 思路
- (1)缓存使用和优化
-
- [1. 增:缓存预热(热点数据分析)](#1. 增:缓存预热(热点数据分析))
- [2. 删:缓存清除策略](#2. 删:缓存清除策略)
- [3. 改:缓存数据刷新和一致性问题](#3. 改:缓存数据刷新和一致性问题)
- [4. 怎么用:缓存优化](#4. 怎么用:缓存优化)
- [5. 缓存击穿、缓存穿透、雪崩问题解决方案](#5. 缓存击穿、缓存穿透、雪崩问题解决方案)
- (2)高并发下系统优化
- (3)分布式锁优化
- [4. 数据库层](#4. 数据库层)
- 三、高可用
-
- 思路
- [1. 服务主备、集群配置](#1. 服务主备、集群配置)
- [2. 隔离、限流、熔断、降级、恢复](#2. 隔离、限流、熔断、降级、恢复)
- [3. 提供补偿(兜底)方案](#3. 提供补偿(兜底)方案)
前言
实力有限,只能就我知道的写。总篇只写大致方案。
一、分布式高并发问题
不同于单机环境,分布式微服务环境下最大的问题就是会出现不仅是跨线程还会有跨服务的数据一致性问题。单机环境下我们有volatile和synchronized以及JUC下的并发编程工具等工具实现并发编程。分布式跨服务环境下就得使用别的方案支持,例如分布式锁、分布式事务、分布式ID等方案满足业务需求。
1. 分布式锁
(1)mysql
利用mysql的主键或唯一索引。
(2)redis
设置有效时间避免死锁,看门狗线程自动续期。
redis集群的红锁。
(3)zookeeper+mysql乐观锁
解决stw情况下redis锁失效的问题。
分布式锁的问题和优化
单点问题
使用分段锁
2. 分布式事务
思路
项目中尽量不要使用分布式事务,一般来说只会将非核心非强一致性的业务操作例如通知、日志等,核心的操作最好是放在同一个事务处理。
利用mysql本身支持的事务功能,设计一种方案,可以确认在每个服务或数据库上的整段操作是否可行,根据每段操作的执行结果判断是全部提交还是全部回滚。
(1)2pc
协调者,事务执行者(数据库)
一阶段:开启事务,预执行,并返回执行结果给协调者。
二阶段:协调者根据返回的执行结果判断是全部提交还是全部回滚。
缺点:
- 不能完全保证数据一致性
- 占用数据库连接
回滚方案
定时任务校验数据并报警
阿里seata工具优化两阶段提交(乐观锁+undolog)
在一阶段就commit释放资源,但是会记录操作(类似undolog),在二阶段如果成功就不处理失败就执行回滚。
(2)3pc
比起2pc,减少了回滚场景下无用的连接和资源浪费
一阶段:can commit
二阶段:pre commit
三阶段:do commit
(3)tcc方案
场景:数据库与缓存同步方案 try confirm cancel
(4)事务表策略
采用 数据库事件表+消息队列+定时任务\监听器 实现的异步事务方案。
- 用户请求 -> 执行业务 -> 写数据库事件表 -> 直接放回结果
- 定时任务查询事件表 -> 发送消息队列 -> 更新事件表状态已发送
- 接收者接受到消息后消费 -> 保存到另一张待执行事件表 -> 发送消息ack -> 更新事件表状态已消费
- 定时任务查询待执行事件表 -> 执行事务 -> 更新待执行事件表状态已执行
方案中也可以省略定时任务,直接在前一个步骤就执行操作。
(5)消息中间件事务
3. 分布式ID
(1)mysql
基于MySQL的原子自增主键 auto increment。
Segment优化:
批量生成策略,双重缓存策略。
(2)雪花算法
时间戳+64机器码+nodeID+areaID+自增
缺点:单点故障、时间回退、NodeID和areaID的分配
优化:zookeeper+雪花算法
二、高并发高性能
1. 客户端优化
(1)浏览器缓存
(2)部分计算交由客户端完成
(3)减少客户端重复请求
- 按钮置灰
- 重刷校验
- 验证码校验
(4)高并发的业务中减少非必要的功能和请求
(5)优化请求
- 合并多个请求
- 只提交必要数据
(6)将大数据请求拆分为多个请求
2. 网络层优化
(1)NDS+CDN 多地部署
(2)网关层添加黑名单
(3)负载均衡和静态服务器
3. 应用层优化
思路
对应用的优化,主要就两条:最大程度压榨系统性能以及怎么避免系统超过极限。
压榨系统性能本质上其实就是尽可能压榨系统CUP和IO的性能。对CUP的利用率,可以从并发编程入手,对IO的利用率,主要是对缓存的应用。
超过系统压力的情况下处理方案:分压和限流。分系统分业务分缓存,阻塞缓存。
(1)缓存使用和优化
1. 增:缓存预热(热点数据分析)
通过跟踪埋点、日志和数据库,分析高频查询、收藏、购物车、订单这类数据,以及活动等确定热点数据预热。
2. 删:缓存清除策略
基于时效清除、LRU算法、灵活分配策略(使用GC+SoftRefrence<>)
由于GC+软引用的不确定性(不直接受业务控制),一般是用来作为LRU算法的补充优化。
3. 改:缓存数据刷新和一致性问题
- 定时更新、时效更新(被动更新,需要允许数据延迟,例如个人信息、收藏、点赞、评论、排名)
- 主动更新:(cache aside 鸵鸟算法,允许一定容忍度)
1.先更新缓存后更新数据库(可能出现数据库更新失败问题)
2.更新数据库顺便更新缓存(可能出现先后更新缓存问题)
3.删除缓存,更新数据库,后面查询的时候再更新缓存(可能出现在更新数据库过程中又查询了一次缓存)
4.更新数据库,删除缓存,后面查询的时候再更新缓存
4. 怎么用:缓存优化
根据业务灵活使用缓存清除策略。
缓存分段提高缓存利用率。
5. 缓存击穿、缓存穿透、雪崩问题解决方案
布隆过滤器、自动续期、分时段、队列缓冲
(2)高并发下系统优化
- 分系统分业务分缓存
- 分段分流:活动采用分时间段拆分多个活动 和 预付定金活动
- 消息队列: 异步 和 削峰
(3)分布式锁优化
使用读写锁方式 和 分段锁
4. 数据库层
按影响范围:索引优化、分区、分库分表(历史表-归档、水平分表、垂直分表)、读写分离(主从一致性问题)
主从一致性问题:
- 从库禁止写操作
- binlog+IO thread+replaylog+SQL thread 实现主从复制(日志类型需要使用混合模式)
- 对强一致性数据使用读写锁或者放弃使用读写分离和缓存
三、高可用
思路
除了使用主备或集群方式解决单点故障问题。
还可以从整体和局部上分析,通过减少环节和隔离方式避免单个或局部服务出错导致整个系统受影响。(隔离、限流、熔断、降级、恢复)
1. 服务主备、集群配置
2. 隔离、限流、熔断、降级、恢复
- 隔离:服务间尽量保证业务隔离、系统隔离、数据隔离
- 限流:不局限于队列限流、令牌桶、输入验证码等都算,核心就是不要让请求一次请打到服务器上
- 熔断:由于服务器的不确定性,在出现多次请求失败/超时下熔断,不在请求后面服务,一段时间后尝试恢复
- 降级:由于业务的不确定性,在出现高峰期的时候主动舍弃非核心功能,保证核心功能正常使用
- 恢复分批少量开放,逐级恢复
3. 提供补偿(兜底)方案
在开发过程中,分析功能可能出现的问题(超时、异步请求失败、分布式事务失败等),设计补偿方案。
根据具体业务实现(优惠券补发、退款、定时数据核验、等待页面等)