高并发设计
2021-09-06 20:50:53 1 举报
AI智能生成
详细的高并发设计
作者其他创作
大纲/内容
三高
高性能
高并发
高可用
failover故障转移
超时控制
限流
降级
发号器
背景
发号器:如何保证分库分表后ID的全局唯一性?
Snowflake 算法完全可以弥补 UUID 存在的不足,因为它不仅算法简单易实现,也满足 ID 所需要的全局唯一性,单调递增性,还包含一定的业务上的意义。
问题
为何不适用UUID
生成的数据不具备单调递增性,也就是无序的,如果需要排序就会有弊端
空间浪费
ID有序也会提升数据写入性能
不具备业务含义
不利于问题排查
缓存
分类
静态缓存
分布式缓存
memcached
redis
热点本地缓存
当我们遇到极端的热点数据查询的时候
不足
适用于读多写少的业务场景,并且数据最好带有一定的热点属性
带来整体系统复杂度,会有数据不一致的风险
内存不是无限的
运维成本
旁路缓存
方法
写数据:先更新数据库,再删除缓存
读:先查询缓存,再查询数据库
优点
解决了主从复制延迟的问题
缺点
缓存中数据频繁被清理,对命中率有一定影响
优化方案
写数据时更新完数据库,再更新缓存,增加分布式锁,但是对写会造成性能影响
更新数据库时更新缓存,增加较短的过期时间
高可用方案
客户端方案
在客户端配置多个缓存的节点,通过缓存写入和读取算法策略来实现分布式,从而提高缓存的可用性。
写入数据时,进行数据分片
Hash 分片算法
就是对缓存的 Key 做哈希计算,然后对总的缓存节点个数取余
一致性 Hash 分片算法
以很好地解决增加和删减节点时,命中率下降的问题
缺点
脏数据问题
一定要设置缓存的过期时间
分布不均匀
引入虚拟节点的概念。
读数据时,利用多组的缓存来做容错,主从副本两种策略
中间代理层
在应用代码和缓存节点之间增加代理层,客户端所有的写入和读取的请求都通过代理层,而代理层中会内置高可用策略,帮助提升缓存系统的高可用。
服务端方案
就是 Redis 2.4 版本后提出的 Redis Sentinel 方案。
缓存穿透
背景
缓存没有,数据库没有
解决方案
回种空值
会给这个空值加一个比较短的过期时间,让空值在短时间之内能够快速过期淘汰
缺点
大量空值数据,浪费空间,建议评估缓存容量是否支持
布隆过滤器
思路
我们把集合中的每一个值按照提供的 Hash 算法算出对应的 Hash 值,然后将 Hash 值对数组长度取模后得到需要计入数组的索引值,并且将数组这个位置的值从 0 改成 1。在判断一个元素是否存在于这个集合中时,你只需要将这个元素按照相同的算法计算出索引值,如果这个位置的值为 1 就认为这个元素在集合中,否则则认为不在集合中。
优点
时间复杂度O(1)
空间也很少
20亿数组 只需要238M
缺陷
hash碰撞导致错误几率
判断元素在集合中时,这个元素可能不在集合中
一旦布隆过滤器判断这个元素不在集合中时,它一定不在集合中
不支持删除
建议
选择多个 Hash 函数计算多个 Hash 值,这样可以减少误判的几率;
布隆过滤器会消耗一定的内存空间,所以在使用时需要评估你的业务场景下需要多大的内存,存储的成本是否可以接受。
对于极热点缓存数据穿透造成的“狗桩效应”,可以通过设置分布式锁或者后台线程定时加载的方式来解决。
常见问题
缓存穿透
含义
访问不存在的数据,绕过缓存,直接到数据库,数据也没有数据
空值回填
适用于空数据有限
布隆过滤器
缓存击穿
热点key过期,大量请求击穿到DB
互斥锁
不过期
不设置过期时间
业务逻辑,将key的过期时间存储,请求是否小于该值
缓存雪崩
同一时刻大量缓存失效(故障)
随机时间
后台更新
限流+本地缓存
双缓存
数据一致性
cache redis
write back
read/write through
热点数据
拆分复杂结构
迁移热点
多副本
缓存预热
缓存降级
子主题
服务注册与发现
注册中心
存储
动态变更推送
API网关
将一些服务共有的功能整合,独立部署,用来解决服务治理的问题
分类
入口网关
作用
屏蔽服务部署地址和协议细节
植入服务治理策略
限流、熔断、降级、分流等
客户端的认证和授权
黑名单等等
日志记录
分布式链路追踪
出口网关
调用网布API时统一认证、授权、审计、访问控制
如何实现
性能
IO模型
扩展性
责任链模式
线程池
线程隔离
开源实现
kong
zuul
tyk
接口聚合处理方案
独立出专用的服务聚合、超时控制组网关
流量网关
业务网关
抽象独立服务层,做接口聚合的事情
服务监控
内容
延迟
请求响应时间
通信量
吞吐量
错误
饱和度
服务或资源达到上线的程度
如何收集
agent
埋点
开源工具
数据处理和存储
消息队列承接
两个队列
数据写入ES
kibana展示
流式处理
spark
strom
实战
如何设计一个支持高并发大存储量的计数系统
通用设计
横向扩展
缓存
异步
数据库
池化技术
空间换时间
数据库连接池等
解决连接复用问题
数据库
主从读写分离
主从复制
同步延迟
缓存
查询主库
冗余信息
一般延迟再一百毫秒以内,如果出现秒级别需要注意
如何保证无感数据访问
中间件对数据源管理
mycat独立部署方案
缺点性能问题
TDDL嵌入式代码
缺点语言支持问题
分库分表
背景
单表数据量千万甚至上亿级别
索引文件占用磁盘空间过大,无法缓存全量索引信息,从而影响查询性能
备份和恢复时间边长
不同模块数据都在一个主库,一旦故障,都会受影响
方式
垂直拆分
将数据库的表拆分到多个不同的数据库中。
一般是按照业务类型来拆分,核心思想是专库专用,将业务耦合度比较高的表拆分到单独的库中
水平拆分
将单一数据表按照某一种规则拆分到多个数据库和多个数据表中,关注点在数据的特点
规则
按照字段哈希值拆分,适用于实体表
按照某一字段区间拆分,例如时间
问题
引入了分库分表键,也就是分区键,也就是我们对数据库做分库分表所依据的字段。
原则
性能没有瓶颈,尽量不要分库分表
如果做就一步到位,满足几年的业务需求
很多nosql数据库,提供了自动sharding特性,可以采用nosql代提关系型数据库
NOSQL
背景
传统关系型数据库弊端
特点
提升写入性能
提升扩展性
mongo
副本集
分片
负载均衡
消息队列
作用
削峰填谷
异步处理
解耦合
如何确保消息一定被送到,且只被消费一次?
消息丢失
消息生产过程中丢失数据
重传机制
在消息队列中丢失
异步刷盘
但是异步刷盘,发生故障还是容易丢,可以减少刷盘间隔,会对性能有影响
kafka集群备份,保证消息不丢失
方案
如果需要确保消息一条都不能丢
不要开启异步刷盘,而是使用kafka集群方式
如果有一定容忍度
建议不部署集群
在消费过程中丢失
幂等
消息生产过程中
kafka原生支持,这个特性保证消息虽然在生产端重复,但是消息队列只会存储一份
消费端
通用层
存储,查询是否存在后,再处理
业务层
乐观锁
版本号
消费性能问题
背景
消息队列中堆积数量过多,导致数据几个小时都无法被处理和返回
监控
子主题
负载均衡
策略
静态策略
轮训
待权重的轮训
动态策略
有限连接数最少服务
响应时间权重等
故障检测
存活检测
多机房部署
同城双活
异地多活
压测
注意点
最好线上环境和数据进行压测
不能使用模拟请求,使用线上流量
拷贝流量方式
不要从一台服务器发起流量
定义
高并发大流量下,进行的压测
全链路压测平台
关键点
流量隔离
风险控制
模块
流量构建和产生
压测数据隔离模块
系统健康度检查和压测流量干预模块
0 条评论
下一页