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