<<高并发系统实战课;; 小记随笔 —— 用户中心案例优化
Posted Blue Mountain
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了<<高并发系统实战课;; 小记随笔 —— 用户中心案例优化相关的知识,希望对你有一定的参考价值。
案例介绍
用户中心的主要功能是维护用户信息、用户权限和登录状态,它保存的数据大部分都属于读多写少的数据。常见的优化方式主要是将用户中心和业务彻底拆开,不再与业务耦合,并适当增加缓存来提高系统性能。
用户中心通常是系统改造中第一个要优化的模块,因为它常常和多个系统重度耦合,所以梳理这个模块对整个系统后续的高并发改造非常重要。
结构梳理
数据库表结构主要可以分为四类,从数据结构出发,先对一些场景进行改造,按照这四类进行数据整理后,再按需设计缓存策略会轻松很多。
数据实体表
实体表一般会作为主表 ,它的一行数据代表一个实体,每个实体都拥有一个独立且唯一的 ID 作为标识。其中,“实体”代表一个抽象的事物,具体的字段表示的是当前实体实时的状态属性。
但是实体表的字段属性需要确认,不要过多,尤其是不要包含 text 字段,否则会导致数据量过多,作缓存时容易过大且需要进行一些特定字段剔除的处理。
不常用的字段可以通过横向或纵向拆分到辅助表中。
实体辅助表
实体表字段过多,且部分字段使用频率并不高的场景下,可以把这些字段摘出来,形成一张实体辅助表。
-
纵向拆分
直接把字段拆出来,辅助表的通过记录主表 ID 进行关联,它们之间的常见关系为 1:1。 -
横向拆分
一张横表,通常如下:
create table params (
id bigint not null auto_increment,
external_id bigint not null,
key varchar(64) not null,
value varchar(128),
primary key (id),
index idx_cluster_id (external_id));
engine=InnoDB default charset=utf8mb4;
通过 kv 方式维护,辅助表的通过记录主表 ID 进行关联,他们之间的常见关系为 1: n。
实体关系表
- 1: n 常用来表示从属关系
- n: 1 常用来表示分类聚合
- m:n 多对多关系,常见于社交等,建议简化为多组 1: n 关系进行维护
历史动作表
一般来说,动作历史数据表记录的是数据实体的动作或状态变化过程,比如用户登陆日志、用户积分消费获取记录等。这类数据会随着时间不断增长,它们一般用于记录、展示最近信息,不建议用在业务的实时统计计算上。
总结
- 能够通过 ID 快速匹配的实体,以及通过关系快速查询的数据,适合放在长期缓存当中;
- 通过组合条件筛选统计的数据,也可以放到临时缓存,但是更新有延迟;
- 数据增长量大或者跟设计初衷不一样的表数据,这种不适合、也不建议去做做缓存。
缓存
不是所有的数据放在缓存就能有很好的收益,我们要从数据量、使用频率、缓存命中率三个角度去分析。
临时缓存
最实用简单的方式就是临时缓存形式
- 先从缓存读,如果有,直接返回
- 如果没有,从数据库读取,并存入缓存,设置 TTL 过期时间
但这个在一些场景会出现缓存更新不及时的情况,比如
- 单条实体数据缓存刷新
- 关系型和统计型数据缓存刷新
单条实体数据缓存刷新
这种比较简单,在数据更新时,直接提出缓存相关缓存,待下次请求进入时再重新从数据库加载即可。
关系型和统计型数据缓存刷新
监控 binlog 更新
通过订阅数据库来找到 ID 数据变化触发事件,然后监听事件触发到具体执行逻辑来实现缓存更新。
版本号缓存设计
如果我们表内的数据更新很少,那么可以采用版本号缓存设计。这个方式比较狂放:一旦有任何更新,整个表内所有数据缓存一起过期。
比如对 user_info 表设置一个 key,假设是 user_info_version,当我们更新这个表数据时,直接对 user_info_version 进行 incr +1。而在写入缓存时,同时会在缓存数据中记录 user_info_version 的当前值。
识别主要实体 ID 来刷新缓存关联型数据缓存
这要保证其他缓存保存的 key 也是主要实体 ID,这样当某一条关联数据发生变化时,就可以根据主要实体 ID 对所有缓存进行刷新。这个方式的缺点是,我们的缓存要能够根据修改的数据反向找到它关联的主体 ID 才行。
长期热数据缓存
数据库要是扛不住平时的流量,我们就不能使用临时缓存的方式去设计缓存系统,只能用长期缓存这种方式来实现热点缓存,以此避免缓存穿透打沉数据库的问题。要求我们的业务几乎完全不走数据库,并且服务运转期间所需的数据都要能在缓存中找到,同时还要保证使用期间缓存不会丢失。
这边提供一个长期热缓存的简单实现逻辑图。一些 key point:
- 如何判定是否是热点数据?
- 对于数据量小,可以直接通过 list、map 维护
- 对于数据量大,可以通过 Bloom Filter
- 锁的作用
- 仅让抢到锁的服务去做更新操作,其他的直接读缓存,减少压力。
- 为什么数据没查到要写 null 到缓存
- 减少对于这个 key 查询 db 的压力
Token: 降低用户身份鉴权压力
传统的 Session 方式是把用户的登录信息通过 SessionID 统一缓存到服务端中,客户端和子系统每次请求都需要到用户中心去“提取”,这就会导致用户中心的流量很大,所有业务都很依赖用户中心。
为了降低用户中心的流量压力,同时让各个子系统与用户中心脱耦,我们采用信任“签名”的 token,把用户信息加密发放到客户端,让客户端本地拥有这些信息。而子系统只需通过签名算法对 token 进行验证,就能获取到用户信息。这种方式的核心是把用户信息放在服务端外做传递和维护,以此解决用户中心的流量性能瓶颈。
此外,通过定期更换 token,用户中心还拥有一定的用户控制能力,也加大了破解难度,可谓一举多得。
以上是关于<<高并发系统实战课;; 小记随笔 —— 用户中心案例优化的主要内容,如果未能解决你的问题,请参考以下文章