高并发系统实战课-极客时间
PS
博客内容参考了极客时间-徐长龙老师的高并发系统实战课,作为个人学习记录使用
初识
- 读多写少(用户中心)
- 强一致性(电商系统)
- 写多读少(链路跟踪系统)
- 读多写多(游戏,直播类系统)
第一章
先梳理数据库结构,再对系统进行高并发改造是很有帮助的
精简数据虽然能换来更好的响应速度,但不提倡过度设计,要在”更多的字段“和”更少的职能“之间找到平衡点
数据主要有四种:实体对象主表,辅助查询表,实体关系和历史数据,不同类型的数据所对应的缓存策略是不同的
数据主体表
每一个实体都拥有一个独立且唯一的ID作为标识,这个ID对于高并发环境下的缓存很重要,通过自己的ID可以直接查找到对应的订单,昵称头像等等,这种方式性能肯定很好。但是业务除了按照ID查找外,还有一些需要通过组合条件查询的。比如:
- 在7月4号下单购买耳机的订单有哪些?
- 昨天是否有用户名前缀是rick用户注册?
这种根据条件查询的数据是不太容易做缓存的,因为高并发服务缓存的数据通常是能够快速通过Hash直接匹配的数据,而这种带条件查询统计的数据很容易出现不一致,数据量不确定导致的性能不稳定等问题。因此这类数据只适合存在关系数据库货提前预置计算好结果放在缓存中直接使用,做定期更新。所以我们应该在后续的开发过程中尽量避免使用数据库做计算。
缓存保存的基本都是实体数据,key前缀+实体ID → user_info_9527,然后通过一些缓存中的关联关系再获取指定数据。
实体辅助表
会根据不同用途对主表进行拆分 → 纵向表拆分(主键对应)
放在辅助表中的数据,一般是主要业务查询中不会使用的数据,只有在极个别的场景下才会取出使用。
辅助表另一个用途就是辅助查询,当原有业务数据结构不能满足其他维度的实体查询时,可以通过辅助表来实现。
拆分辅助表会和主体出现1:n甚至是m:n的数据关系,需要定期地对数据整理核对,通过核对数据来找出数据差异,会更简单一些。
有时候为了提高查询效率,会把同一个数据冗余在多个表内,有数据更新时,需要同步更新冗余表和缓存的数据。
实体关系表
使用一个关系表来记录实体间m:n的关联关系
举例
a表(ID, 相关属性, b表关联ID多条)
b表(ID, 相关属性, a表关联ID多条)
a表(ID, 相关属性), b表(相关属性), c(id_a,id_b)
在对1:n,m:n关系的数据做缓存时,建议提前预估好可能参与的数据量,防止过大导致缓存缓慢
通常会将主体的ID作为key,在value内存保存多个关联的ID来记录这两个数据的关联关系,而对于读取特别频繁的业务缓存,才会考虑把数据先按照关系组织好,然后整体缓存起来。
有些多级依赖关系很难在并发高的系统中维护(需要及时同步这些数据在缓存中的变化),会降低一致性及要求来满足业务的高并发情况。
什么样的数据适合做缓存
ID能够精确匹配的数据实体很适合做缓存
String,List,Set辅助或关系查询
Hgetall指令性能并不好,容易让缓存卡顿
动作历史表
记录的是数据实体的动作或状态变化过程。如用户登陆日志,用户积分消费获取等,一般用于记录,展示最近信息,不建议用在业务的实时统计计算上。
思考题
邀请人注册之后减免的场景该如何设计?
可以按照动作和结果来分:
动作:发出邀请的动作可以有多次,一个用户可以分享给很多用户 → 动作历史表
结果(结果导向关系):分享之后用户注册成功生成一条用户记录 → 关系表