← BACK TO BLOG

综合学习

团队提效、架构设计、MQ、Redis、MySQL、Docker 与微服务等主题的综合学习笔记与要点整理。

次阅读

团队提效

  1. 统一开发工具。
  2. 代码评审,一致化大家的认知,统一代码风格。
  3. 新人业务名词 / 概念培训
  4. 任务拆分,最大可能并行开发
  5. 人员备份

架构图

调度.jpg

架构.jpg

MQ(RocketMQ)

为什么需要使用 MQ

  1. 异步处理(多线程和 MQ)
  2. 实现解耦
  3. 流量削峰(MQ 可以实现抗高并发)

MQ 如何避免消息堆积的问题

  1. 提高消费者消费的速率;(对我们的消费者实现集群)
  2. 消费者应该批量形式获取消息,减少网络传输的次数;

如何高可用?

  1. NameServer 因为是无状态,且不相互通信的,所以只要集群部署就可以保证高可用。
  2. Master 和 Slave,Master 角色的 Broker 支持读和写,Slave 角色的 Broker 只支持读,Master 会向 Slave 同步消息。 Consumer 的读请求会被自动切换

有哪些消息模型?

  1. 队列模型
  2. 发布/订阅模型

MQ 如何保证消息不丢失?

  1. MQ 服务器端消息持久化到 CommitLog(日志文件)中
  2. 生产者 消息确认机制 必须确认消息成功刷盘到硬盘中,才能够认为消息投递成功。
  3. Broker 通过主从模式来保证高可用

Broker 支持 Master 和 Slave 同步复制、Master 和 Slave 异步复制模式,生产者的消息都是发送> 给 Master,但是消费既可以从 Master 消费,也可以从 Slave 消费。同步复制模式可以保证即使 > Master 宕机,消息肯定在 Slave 中有备份,保证了消息不会丢失。

  1. Broker 的刷盘机制:同步刷盘和异步刷盘,不管哪种刷盘都可以保证消息一定存储在 pagecache 中(内存中),但是同步刷盘更可靠,它是 Producer 发送消息后等数据持久化到磁盘之后再返回响应给 Producer。
  2. 消费者 必须确认消息消费成功 。

处理消息重复

  1. 业务幂等:第一种是保证消费逻辑的幂等性,也就是多次调用和一次调用的效果是一样的。这样一来,不管消息消费多少次,对业务都没有影响。
  2. 消息去重:第二种是业务端,对重复的消息就不再消费了。这种方法,需要保证每条消息都有一个惟一的编号,通常是业务相关的,比如订单号,消费的记录需要落库,而且需要保证和消息确认这一步的原子性。

延时消息了解吗?

电商的订单超时自动取消,就是一个典型的利用延时消息的例子,用户提交了一个订单,就可以发送一个延时消息,1h 后去检查这个订单的状态,如果还是未付款就取消订单释放库存。

四部分组成

对应到 RocketMQ 中,这四个角色就是 Producer、 Consumer、 Broker 、NameServer

  1. Producer 在发送消息前从 NameServer 中获取 Topic 的路由信息也就是发往哪个 Broker,Consumer 也会定时从 NameServer 获取 Topic 的路由信息,Broker 在启动时会向 NameServer 注册,并定时进行心跳连接,且定时同步维护的 Topic 到 NameServer。
  2. Broker 消息存储和中转角色,负责存储和转发消息,Broker 内部维护着一个个 Consumer Queue,用来存储消息的索引,真正存储消息的地方是 CommitLog(日志文件)。

Redis

Redis 的持久化机制是什么?各自的优缺点?

RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。 优点: 1、只有一个文件 dump.rdb,方便持久化。 2、容灾性好,一个文件可以保存到安全的磁盘。 3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能。 4、相对于数据集大时,比 AOF 的启动效率更高。 缺点: 1、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)

AOF:持久化 AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。 优点: 1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。 2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。 缺点: 1、AOF 文件比 RDB 文件大,且恢复速度慢。 2、数据集大的时候,比 rdb 启动效率低。

如何选择

  1. 如果想达到足以媲美PostgreSQL的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入AOF文件来恢复原始的数据
  2. 可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化

缓存扩容

缓存扩容主要关注的是缓存的容量和缓存命中率:

  • 增加缓存容量:直接增加Redis实例的内存以容纳更多的数据。这可以通过增加服务器内存或者将缓存数据分布到更多的Redis实例来实现。
  • 水平扩展:和持久化数据一样,可以通过Redis Cluster进行水平扩展,将缓存数据分布在多个节点上。
  • 缓存策略优化:调整缓存淘汰策略(如LRU、LFU、TTL等)以确保高价值的数据能长期保存在缓存中,并减少不必要的缓存占用。
  • 使用多级缓存:可以结合使用本地缓存(如Guava、Caffeine等)和Redis缓存,形成多级缓存结构,减轻Redis的压力。
  • 热点数据优化:针对热点数据进行优化,确保热门数据的缓存效率,通过调整缓存TTL或者增加特定数据的缓存容量来处理。

Redis的过期键的删除策略

  1. 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
  2. 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
  3. 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果

Redis的内存淘汰策略有哪些

  1. noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
  2. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
  3. allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。

Redis 的内存优化可以从以下几个方面入手:

  1. 数据结构选择 例如,对于小集合数据,如果元素数量较少,可以使用 ziplist 编码而不是 hashtable ,以节省内存。 合理选择字符串的编码方式,如 int 、 embstr 或 raw 。
  2. 键值对精简 缩短键的长度,去除不必要的前缀或后缀。 减少值的大小,例如只存储必要的字段。
  3. 定期清理过期数据 设置合理的过期时间策略,及时删除不再需要的数据。
  4. 限制数据量 使用 maxmemory 配置限制 Redis 使用的最大内存。 结合 LRU (Least Recently Used)或 LFU (Least Frequently Used)算法淘汰数据。
  5. 数据压缩 对于某些值,可以在存储前进行压缩,读取时解压缩。
  6. 优化数据存储方式 例如,将频繁访问但不常修改的数据存储在 Redis 中,其他数据存储在其他数据库中。

三大集群模式

主从复制模式

优点:

  1. 配置简单,易于实现。
  2. 实现数据冗余,提高数据可靠性。
  3. 读写分离,提高系统性能。 缺点:
  4. 主节点故障时,需要手动切换到从节点,故障恢复时间较长。
  5. 主节点承担所有写操作,可能成为性能瓶颈。
  6. 无法实现数据分片,受单节点内存限制。

哨兵模式

优点:

  1. 自动故障转移,提高系统的高可用性。
  2. 具有主从复制模式的所有优点,如数据冗余和读写分离。 缺点:
  3. 配置和管理相对复杂。
  4. 依然无法实现数据分片,受单节点内存限制。

Cluster模式

在Cluster模式下,Redis将所有的键值对数据分散在多个节点上。每个节点负责一部分数据,称为槽位。通过对数据的分片,Cluster模式可以突破单节点的内存限制,实现更大规模的数据存储。 数据分配

  1. 通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据,默认分配了16384 个槽位
  2. 每份数据分片会存储在多个互为主从的多节点上
  3. 数据写入先写主节点,再同步到从节点(支持配置为阻塞同步)
  4. 同一分片多个节点间的数据保持一致性
  5. 读取数据时,当客户端操作的key没有分配在该节点上时,redis会返回转向指令,指向正确的节点
  6. 扩容时时需要需要把旧节点的数据迁移一部分到新节点

优点:

  1. 数据分片,实现大规模数据存储。
  2. 负载均衡,提高系统性能。
  3. 自动故障转移,提高高可用性。 缺点:
  4. 配置和管理较复杂。
  5. 一些复杂的多键操作可能受到限制。

主节点选举

  1. 过滤:“不健康”(主观下线、断线)、5 秒内没有回复过 Sentinel 节 点 ping 响应、与主节点失联超过 down-after-milliseconds*10 秒。
  2. 选择 slave-priority(从节点优先级)最高的从节点列表,如果存在则返回,不存在则继续。
  3. 选择复制偏移量最大的从节点(复制的最完整),如果存在则返 回,不存在则继续。
  4. 选择 runid 最小的从节点。

缓存击穿、缓存穿透、缓存雪崩?

缓存击穿 缓存击穿是指某一个或少数几个数据被高频访问,当这些数据在缓存中过期的那一刻,大量请求就会直接到达数据库,导致数据库瞬间压力过大。

  • 加锁更新,⽐如请求查询 A,发现缓存中没有,对 A 这个 key 加锁,同时去数据库查询数据,写⼊缓存,再返回给⽤户,这样后⾯的请求就可以从缓存中拿到数据了。
  • 将过期时间组合写在 value 中,通过异步的⽅式不断的刷新过期时间,防⽌此类现象

缓存穿透 缓存穿透是指查询不存在的数据,由于缓存没有命中(因为数据根本就不存在),请求每次都会穿过缓存去查询数据库

  • 缓存空值/默认值
  • 在存储和缓存之前,加一个布隆过滤器

缓存雪崩 大量的缓存数据同时过期或缓存服务器突然宕机了,导致所有的请求都落到了数据库上

  • 集群部署
  • 多级缓存
  • 随机值过期时间
  • 限流和降级(令牌桶或漏斗算法)

怎么处理热 key?

  • 客户端多级缓存
  • 把热 key 打散到不同的服务器