针对数据库集群
- 读写分离:将访问压力分散到集群的多个节点,没有分散存储压力
- 分库分表:分散访问压力,分散存储压力
读写分离
架构图:
其中,主机负责读写,复制数据到从机,从机负责读。引出 2 个问题:复制延迟、分配机制。
对于「复制延迟」,解决思路:
- 写操作后的读操作,都发给主机。比如注册账号后,立即登陆(读操作),请求主机。
- 二次读取。从机读取失败后,再读主机。
- 业务分离。关键业务读写是主机,非关键业务读操作是从机。
- 引入缓存。例如,注册后将账号加入缓存,设置失效时间。登陆先查 redis,没有再查从机,此时数据已经同步完成。最后没有数据,再读主机。
对于「分配机制」,2 种常用方法:
- 代码封装。在代码种封装个 Apdater 层,对外提供 API
- 数据库中间件。类似云开发的云数据库,开发者无需关心负载、备份等问题,由云厂商解决
读写分离应用场景?
适用于:读请求多的场景。
读写分离后,主机(读写)可以去掉索引,提高写入速度;从机(读)增加索引,提高读取速度。
分库分表
分库:按照业务模块将数据分散到不同的数据库服务器。
问题:一些数据库操作(例如 join、分布式事务)需要自己在代码中模拟,开发难度大。
分表:分为垂直分表和水平分表。
垂直分表:用于将不常用且占大量空间的字段拆分出去,会导致表的操作数增加。
水平分表:记录数增加时,需要考虑。
水平分表会带来一些问题,例如路由、总数、排序、join 等表操作。
- 路由:决定数据属于哪个子表
- 范围路由:1-1000 属于子表 1,2-1000 属于子表 2。优点是直接扩表即可,缺点是数据分配不均匀。
- hash 路由:自定义 hash 规则,例如根据 id 取余,就是子表 id。优缺点和范围路由相反。
- 配置路由:新建一张新表存储“路由信息”。例如用户表、信息
- 总数:
- 代码封装:多次读取统计
- 新建表存储记录数
分库分表何时引入?
- 改善硬件条件,垂直扩容
- 考虑读写分离、引入缓存、全文检索(针对搜索)
- 单库单表满足不了,考虑分库 => 分表 => 垂直分表(按照业务逻辑拆分) => 水平分表
缓存问题
缓存穿透
描述:缓存没有发挥作用,业务系统需要再次去存储系统查询数据
原因:
- 原始数据不存在 9(给默认值)
- 数据第一次被访问,没在缓存中(拉取)
- 数据生成消耗过多资源(优化业务逻辑)
缓存雪崩
描述:指当缓存失效(过期)后引起系统性能急剧下降的情况。例如重启系统,大量请求落到缓存,缓存要重新生成;存储系统被频繁访问,压力大。
解决方法:
- 如果是多线程服务器,可以加锁。效率低,不推荐。
- 开启独立更新线程,定时刷缓存。业务访问时,数据不存在,可以返回默认值,或者通知更新线程更新缓存。
缓存热点
描述:举个例子,微博明星告白,突然涌入大量需求。
解决方法:加机器。不同机器缓存过期时间不同,防止雪崩。