<<高并发系统实战课;; 小记随笔 —— 用户中心案例优化

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,用户中心还拥有一定的用户控制能力,也加大了破解难度,可谓一举多得。

以上是关于<<高并发系统实战课;; 小记随笔 —— 用户中心案例优化的主要内容,如果未能解决你的问题,请参考以下文章

HTTP高并发调优小记

随笔小记

全流程开发 GO实战电商网站高并发秒杀系统 百度云

Java 小记 — RabbitMQ 的实践与思考

第1课 介绍大型站点运维到底是什么?应该具备哪些能力 - 大型网站高并发架构与自动化运维实战

2018最新技术Java架构师高并发高性能高可用分布式集群电商缓存性能调优设计模式项目实战视频教程