美文网首页
《高并发系统实战课》学习笔记 day1

《高并发系统实战课》学习笔记 day1

作者: 滔滔逐浪 | 来源:发表于2023-01-08 16:40 被阅读0次

    任何老系统在做高并发改造的时候都要先做一次表的梳理
    因为老系统在使用数据库的时候存在很多问题,比如实体表字段过多,表查询维度和用途多样,表之间关系混乱,这些问题会让缓存改造十分困难,严重拖慢改造进度。

    精简数据会有更好的性能

    用户中心的主要功能是维护用户信息,用户权限和登录状态,它保存的数据大部分都属于读多写少的数据。用户中心常见的优化方式主要是将用户中心和业务彻底拆开,不再与业务耦合,并适当增加缓存来提高系统性能。


    image.png

    对表的功能和字段进行了业务解耦和精简,他的核心是,长度小的数据在吞吐,查询,传输上都会很快,也会更好的管理和缓存。
    精简后的表拥有更少的字段,对应的业务用途也会比较单纯。
    不过需要注意,精简数据量虽然能换来更好的响应速度,但是不提倡过度设计,因为表字段如果缺少冗余会导致业务实现更为繁琐。
    因此我们需要在更多的字段和更少的职能之间找到平衡。

    数据的归类和整理

    除了通过精简表的职能来提高表的性能和维护性外,我们还可以针对不同类型的表做不同方向的缓存优化,如下图

    image.png

    数据主要有四种,实体对象主表,辅助查询表,实体关系和历史数据,不同类型的数据所对应的缓存策略是不同的,如果将一些职能拆分不清楚的数据硬是放在缓存中,使用的时候就会碰到很多烧脑的问题。

    image.png

    将历史记录和需要实时更新的好友状态混在一起,显然不合理,如果我们做归类梳理的话,应该拆分成三个职能表,分别进行管理。
    1,历史记录表,不做缓存,仅仅展示最近几条,极端情况临时缓存
    2,好友关系(缓存关系,用于统计有几个好友)
    3,来访统计数字。
    因此需要明白数据归类的重要性。
    数据实体表
    先看下用户账号表,这个表是一个实体表,实体表一般作为主表,他的一行数据代表一个实体,每个实体都拥有一个独立且唯一的ID作为标识。其中,“实体”代表一个抽象的事务,具体的字段表示的是当前实体实时的状态属性。
    这个ID对于高并发环境下的缓存很重要,用户登录后就需要用自己的账户的ID直接查找到对应的订单,昵称头像和好友列表信息。如果我们的业务都是通过这样的方式查找,性能肯定很好,并且很适合做长期缓存。
    但是除了按ID查询外,还有一些是需要通过组合条件查询的,比如:

    在 7 月 4 日下单购买耳机的订单有哪些?
    天津的用户里有多少新注册的用户?有多少老用户?
    昨天是否有用户名前缀是 rick 账户注册?

    这种根据条件查询统计的数据是不太容易做缓存的,因为高并发服务缓存的数据通常是能够快速通过Hash直接匹配的数据,而这种带条件查询统计的数据很容易出现不一致,数据量不确定导致的性能不稳定等问题,并且如果涉及的数据出现变化,我们很难通过数据确定同步更新那些缓存。
    因此,这类数据只适合存在关系数据库或提前预置计算好结果放在缓存中直接使用,做定期更新。
    除了组合条件查询不好缓存外,像count(),sum()等对数据进行实时计算也有更新不及时的问题,同样只能定期缓存汇总结果,不能频繁查询。所以我们应该在后续的开发过程中尽量避免使用数据库进行计算。
    如果这种查询的频率比较高,就会严重影响其他用户的登陆,而且新增的昵称索引还会额外降低当前表插入数据的性能,这也是为什么我们的后台系统往往会单独分出一个从库,做特殊索引。
    一般来说,高并发用缓存来优化读取的性能时,缓存保存的基本都是实体数据。那常见的方法是先通过“key 前缀 + 实体 ID”获取数据(比如 user_info_9527),然后通过一些缓存中的关联关系再获取指定数据,比如我们通过 ID 就可以直接获取用户好友关系 key,并且拿到用户的好友 ID 列表。通过类似的方式,我们可以在 Redis 中实现用户常见的关联查询操作。总体来说,实体数据是我们业务的主要承载体,当我们找到实体主体的时候,就可以根据这个主体在缓存中查到所有和它有关联的数据,来服务用户。现在我们来稍微总结一下,我们整理实体表的核心思路主要有以下几点:

    精简数据总长度
    减少表承担的业务职能
    减少统计计算查询
    实体数据更适合放在缓存中;
    尽量让实体能够通过ID或关系方式查找。
    减少实时条件筛选方式的对外服务。
    
    

    下面我们继续来看另外三种表结构,你会发现它们不太适合放在缓存中,因为维护它们的一致性很麻烦。

    实体辅助表

    为了精简数据且方便管理,我们经常会根据不同用途对主表拆分,常见的方式是做纵向表拆分
    纵向表拆分的目的一般是2个,一个是把使用频率不高的数据摘出来。常见的表字段很多,经过拆分,可以精简他的职能,而辅助表的主键通常会和主表一致或通过ID进行关联,他们之间的常见关系是1:1

    而放到辅助表的数据,一般是主要业务查询中不会使用的数据,这些数据只有在极个别的场景下才会取出使用,比如用户账号表为主体用于做用户登陆使用,而辅助信息表保存家庭住址、省份、微信、邮编等平时不会展示的信息。

    辅助表的另外一个用途是辅助查询,当原有的业务数据不能够满足其他维度的实体查询时,可以通过辅助表来实现。
    比如有一个表是以“教师”为主体设计的,每次业务都会根据“当前教师 ID+ 条件”来查询学生及班级数据,但从学生的角度使用系统时,需要高频率以“学生和班级”为基础查询教师数据时,就只能先查出 “学生 ID”或“班级 ID”,然后才能查找出老师 ID”,这样不仅不方便,而且还很低效,这时候就可以把学生和班级的数据拆分出来,额外做一个辅助表包含所有详细信息,方便这种查询。另外,我还要提醒一下,因为拆分的辅助表会和主体出现 1:n 甚至是 m:n 的数据关系,所以我们要定期地对数据整理核对,通过这个方式保证我们冗余数据的同步和完整。不过,非 1:1 数据关系的辅助表维护起来并不容易,因为它容易出现数据不一致或延迟的情况,甚至在有些场景下,还需要刷新所有相关关系的缓存,既耗时又耗力。如果这些数据的核对通过脚本去定期执行,通过核对数据来找出数据差异,会更简单一些。此外,在很多情况下我们为了提高查询效率,会把同一个数据冗余在多个表内,有数据更新时,我们需要同步更新冗余表和缓存的数据。这里补充一点,行业里也会用一些开源搜索引擎,辅助我们做类似的关系业务查询,比如用 ElasticSearch 做商品检索、用 OpenSearch 做文章检索等。这种可横向扩容的服务能大大降低数据库查询压力,但唯一缺点就是很难实现数据的强一致性,需要人工检测、核对两个系统的数据。

    实体关系表

    image.png

    在关系型数据中,可以额外用一个关系表来记录实体间m:n的关联关系,这样2个实体就不用因为相互依赖关系,导致难以维护。
    在对1:n或者m:n关系的数据做缓存时,提前预估好可能参与的数据量 ,防止过大导致缓存缓慢。同时,通常保存这个关系在缓存中会把主体的ID作为key,在value内保存多个关联ID来记录这2个数据的关联关系,而对于读取特别频繁的业务缓存,才会考虑把数据先按关系组织好,然后整体缓存起来,来方便查询和使用。
    需要注意的是,这种关联数据很容易出现多级依赖,会导致我们整理起来十分麻烦。当相关表或者条件更新时,我们需要及时同步这些数据在缓存中的变化。所以,这种多级依赖关系很难在并发高的系统中维护,很多时候需要降低一致性的要求来满足业务的高并发情况。
    总的来说,只有通过ID进行关联的数据的缓存时最容易管理的,其他的都需要特殊维护。
    现在我们简单总结一下,到底什么样的数据适合做缓存。一般来说,根据 ID 能够精准匹配的数据实体很适合做缓存;而通过 String、List 或 Set 指令形成的有多条 value 的结构适合做(1:1、1:n、m:n)辅助或关系查询;最后还有一点要注意,虽然 Hash 结构很适合做实体表的属性和状态,但是 Hgetall 指令性能并不好,很容易让缓存卡顿,建议不要这样做。
    总结在项目初期,数据表的职能设计往往都会比较简单,但随着时间的推移和业务的发展变化,表经过多次修改后,其使用方向和职能都会发生较大的变化,导致我们的系统越来越复杂。所以,当流量超过数据库的承受能力需要做缓存改造时,我们建议先根据当前的业务逻辑对数据表进行职能归类,它能够帮你快速识别出,表中哪些字段和功能不适合在特定类型的表内使用,这会让数据在缓存中有更好的性价比。一般来说,数据可分为四类:实体表、实体辅助表、关系表和历史表,而判断是否适合缓存的核心思路主要是以下几点:能够通过 ID 快速匹配的实体,以及通过关系快速查询的数据,适合放在长期缓存当中;通过组合条件筛选统计的数据,也可以放到临时缓存,但是更新有延迟;数据增长量大或者跟设计初衷不一样的表数据,这种不适合、也不建议去做做缓存。


    image.png

    学习来源:极客时间

    https://mp.weixin.qq.com/s/kQaIdmgSkOnhOT4bVGrGhw

    相关文章

      网友评论

          本文标题:《高并发系统实战课》学习笔记 day1

          本文链接:https://www.haomeiwen.com/subject/tvmucdtx.html