Redis

1. Redis简介

Redis是一个内存型数据库,读写速度非常快,常广泛应用于缓存,或分布式缓存,也常常用作高性能的分布式锁,其中Redis提供了各种数据结构(比如String,List,Set,Zset,Hash)来支持不同业务场景,自带持久化机制,过期策略,不同内存淘汰策略,提供Redis主从进行数据备份实现读写分离,哨兵模式进行故障自动主从转移实现高可用,Redis集群进行数据分片存储以及故障转移实现高并发高可用

2. 为什么要用缓存?为什么要用Redis作为缓存?

为什么要用缓存?

  1. 高性能:缓存是直接操作内存,速度相当快。使用缓存可加快用户访问速度,提高用户体验

  2. 高并发:缓存能够承受的请求是远远大于直接访问数据库的,将大部分对数据库的请求转移到缓存上去,可以减低数据库负载,提高请求并发量.

为什么要用Redis作为缓存?

  1. Redis 是专业的缓存服务,可以处理每秒百万级的并发
  2. Redis 提供了各种数据结构(比如String,List,Set,Zset,Hash)来支持不同业务场景
  3. Redis 自带持久化机制,过期机制,以及不同的内存淘汰机制,无需自己实现管理内存
  4. Redis 提供Redis主从,哨兵模式,Redis集群等特性,进而保证了缓存服务的高可用高并发可扩展



3. 为什么单线程的Redis效率如此高?

  • Redis是一种内存型数据库,纯内存性操作十分快
  • Redis采用了单线程的文本事件处理器,使用非阻塞式的IO多路复用技术同时监听多个Socket,将Socket产生的事件放入队列中等待事件分派器将事件分派给对应的事件处理器进行处理。单线程避免了多线程的频繁上下文切换开销,而非阻塞的IO多路复用技术保证了Redis单线程处理的效率



4. Redis的单线程模型是什么?

Redis采用单线程的文本事件处理器,使用非阻塞式的IO多路复用技术同时监听多个Socket,将Socket产生的事件放入队列中等待事件分派器将事件分派给对应的事件处理器进行处理。
在这里插入图片描述
比如客户端向服务器发起连接请求,此时 Server socket接收到该连接请求会产生一个 AE_READABLE 事件,IO 多路复用程序监听到 Server socket 产生的事件后,将该事件压入队列中。文件事件分派器从队列中获取该事件,交给连接应答处理器。连接应答处理器会将Server Socket的 AE_READABLE 事件与命令请求处理器关联。

假设此时客户端发送了一个 set key value 请求,此时 redis 中的 Server Socket 会产生 AE_READABLE 事件,IO 多路复用程序将事件压入队列,此时事件分派器从队列中获取到该事件,由于Server socket的 AE_READABLE 事件已经与命令请求处理器关联,因此事件分派器将事件交给命令请求处理器来处理。处理完成后,它会将 Server Socket 的 AE_WRITABLE 事件与命令回复处理器关联。如果此时客户端准备好接收返回结果了,那么 redis 中的 Server Socket 会产生一个 AE_WRITABLE 事件,同样压入队列中,事件分派器找到相关联的命令回复处理器,由命令回复处理器对 Server Socket 输入本次操作的一个结果,比如 ok,之后解除 Server Socket 的 AE_WRITABLE 事件与命令回复处理器的关联。这样便完成了一次通信



5. Redis常见数据结构以及使用场景

(1)String

常用命令:set,get,setnx(不存在时设置),setex(设置过期时间),decr,incr等

String是Redis中最基本的类型,是简单的key-value类型,Redis的string可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512MB。常用于常规key-value缓存应用,比如常规计数:点赞数,微博数,粉丝数等。

(2)Hash

常用命令:hget,hset等

Hash 是一个 string 类型的 field 和 value 的映射表,常用于存储对象,比如存储用户信息,商品信息等等。

(3)List

常用命令:lpush,rpush,lpop,rpop,lrange,Blpop,Brpop

List 是一个双向链表, list常用于存储列表信息,比如微博的关注列表,粉丝列表,消息列表。并且list提供了blpop,brpop队列阻塞操作,可用于作为阻塞队列,List提供了lrange范围查询,可用于分页操作

(4)Set

常用命令:sadd,srem,sinter,sunion,sdiff,smembers,sismember,scard 等

Set 是一个自动去重的集合。当你需要存储一个列表数据,又不希望出现重复数据时,Set是一个很好的选择,使用Set 可轻易实现集合交集、并集、差集的操作,例如求共同好友,共同关注问题,共同粉丝等等

(5)Sorted Set

常用命令: zadd,zrem,zrange,zcount,zcard等等

sorted set是一个通过score排序的有序map,Sorted Set常用于排序,例如用户积分排名,活跃度排名等等

(6) BitMap

常用命令:SETBIT,GETBIT,BITCOUNT, BITOP

BitMap 是一种二进制位图,利用较小的内存记录超大数据量的存在/不存在信息,可用于记录日活跃用户,用户上线次数统计等等。具体见https://www.cnblogs.com/davidwang456/articles/9314662.html

(7)HyperLogLog

常用命令: PFADD,PFCOUNT,PFMERGE

HyperLogLog 用于基数统计,提供不精确的去重计数方案(标准误差是 0.81%),并且每个HyperLogLog 键只需要花费 12 KB 内存。它虽并不保留输入的元素但对输入元素具有记忆性能进行去重统计。比如统计需要每个网页每天的UV(不重复访问量,同一个用户一天之内的多次访问请求只能计数一次),如果统计PV(访客量), 那非常好办,给每个网页一个独立的 Redis 计数器就可以了,这个计数器的 key 后缀加上当天的日期。这样来一个请求,incrby 一次,最终就可以统计出所有的 PV 数据。若使用set需要为每一个页面一个独立的 set 集合来存储所有当天访问过此页面的用户 ID,如果你的页面访问量非常大,比如一个爆款页面几千万的 UV,你需要一个很大的 set 集合来统计,这就非常浪费空间。Redis 提供了 HyperLogLog 数据结构就是用来解决这种统计问题的.

(8)Geo

常用命令:geoadd,geopos,geodist,georadius

Geo 用于记录地理位置,可以向其中添加地理空间位置(纬度、经度、名称),就可以测量两地距离,距离某地距离多远的地点有哪些



6. Redis过期处理策略/内存淘汰机制/持久化机制

6.1. Redis过期键处理策略

  • 定期删除:redis默认是每隔 100ms 就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载!
  • 惰性删除 :定期删除可能会导致很多过期 key 到了时间并没有被删除掉。所以就有了惰性删除来保证过期 key不会被使用,使用前先查一下那个 key是否过期,过期则删除掉。

6.2. Redis内存淘汰机制

redis内存淘汰机制是为针对缓存而设计,redis有一个最大内存是,可通过设置maxmemory来完成,当内存达到maxmemory时,则需要按照相应的策略对内存中的数据进行淘汰删除使得内存可以继续留有足够的空间保存新的数据。

  • redis 提供的8种淘汰策略
    (1)volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最久未使用的数据淘汰。每一个对象都记录了一个lru,即该对象空转时间,LRU算法是在其数据集中随机挑选几个键值对,取出其中 lru 最大的键值对淘汰。
    (2)volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选即将过期的数据淘汰。从过期时间的表中随机挑选几个键值对,取出其中 ttl 最小的键值对淘汰
    (3)volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
    (4)allkeys-lru:从数据集(server.db[i].dict),移除最近最少使用的key(这个是最常用的)
    (5)allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
    (6)no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。
    4.0版本后增加以下两种
    (7)volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选使用频率最小的key淘汰。每一个对象记录着一个创建时间,以及使用次数,可计算出使用频率,从数据集中随机挑选几个键值对,取出其中使用频率最低的键值对淘汰
    (8)allkeys-lfu:从数据集(server.db[i].dict)中,移除使用频率最小的key

  • 常见策略选择
    (1)allkeys-lru:如果我们的redis应用是缓存应用,对缓存的访问存在相对热点数据,或者我们不太清楚我们应用的缓存访问分布状况,我们可以选择allkeys-lru策略。这个策略可以保证redis都是热点数据
    (2)allkeys-random: 如果我们的redis应用是缓存应用,对于缓存key的访问概率相等,则可以使用这个策略。
    (3)volatile-ttl:如果对数据有足够的了解,能够为key指定hint(通过expire/ttl指定),那么可以选择volatile-ttl进行置换

6.3 Redis持久化机制

当redis作为一个内存型数据库时,需要将其内存的数据进行持久化写入文件以备机器重启或者机器故障之后的数据恢复,并生成的RDB文件可用于redis集群数据同步,数据备份。

6.3.1 三种持久化策略
  • RDB持久化:Redis通过创建快照记录在内存里面的数据在某个时间点上的副本。RDB是Redis默认持久化方式,在redis.conf配置文件中默认有此下配置:

save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

  • AOF持久化:Redis将redis内存中的数据转换成对应的命令set key等形式,通过向文件中写入命令的方式保存数据在某个时间点的副本。并且可通过AOF重写的方式减少AOF文件体积,默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:

appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no #让操作系统决定何时进行同步

  • Redis 4.0 开始支持 RDB 和 AOF 的混合持久化:默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。
6.3.2 RDB与AOF优缺点
  • RDB恢复数据快,数据丢失严重,RDB主要用于主从同步,AOF恢复数据慢于RDB,在appendfsync everysec模式下数据最多丢失1s数据量,若你非常关心你的数据,不可以承受数分钟以内的数据丢失,则可选择AOF持久化方式,AOF持久化已成为主流的持久化策略。



7. Redis主从同步

Redis主从提供了数据备份,可用于实现读写分离,并且Redis主从是故障转移的必要条件

7.1 Redis主从复制

7.1.1 两种主从复制方式
  • 完全重同步:完全重同步用于初次复制情况,主服务器执行BGSAVE生成RDB文件,使用一个缓冲区记录同步期间所有写命令,在发送RDB文件至从服务器,从服务器收到RDB文件,更新数据库状态,主服务器将记录在缓冲区的写命令发送至从服务器,从服务器执行这些写命令,此时主从一致。
  • 部分重同步:部分重同步用于从服务器断线连接后与主服务器的同步,将断线期间执行的写命令发送给从服务器执行,主从服务器重新回到一致状态。
7.1.2 主从复制原理
  • 主服务器复制偏移量+从服务器复制偏移量:主从服务器各维护者一个复制偏移量,用于判断主从给服务器是否处于一致状态,若相等则处于一致状态

在这里插入图片描述

  • 复制积压缓冲区:主服务器维护着一个固定大小的缓冲队列,用于保存最近传播的写命令以及每个字节偏移量,每当主服务器向从服务器传播命令时,都会写入复制积压缓冲区,所以复制挤压缓冲区可能保存着部分重同步所需的写命令,而这部分命令则可能是从服务器断线后主服务器执行的那一部分命令
    在这里插入图片描述
  • 服务器运行id:从服务器发送命令会带上主服务器id,用于判断主服务器是不是原来哪个主服务器,若不是则要执行完全重同步

7.2 命令传播

主服务器将写命令执行,向从服务器传播,让从服务器执行写命令,保证主从一致。

7.3 心跳检测

在命令传播阶段,从服务器会对主服务器进行心跳检测,每隔1S发送一个心跳检测请求,并且带有从服务器复制偏移量,主要用于检测主从网络连接状况以及在命令丢失条件下进行命令补发


8. Redis集群

Redis集群实现了数据分片存储以及故障转移,为缓存服务提供了高并发高可用可扩展的保证

8.1 Redis节点与集群数据结构

一个集群由多个Redis节点组成,一个Redis节点就是一个运行在集群模式下的Redis服务器,而每个节点都会使用一个ClusterNode来记录自己节点的状态,一个ClusterState保存整个集群信息。

  • ClusterNode:包括节点名字,节点创建时间,节点ip地址,端口号,角色(主节点,从节点),Slot二进制数组记录本节点的分槽信息,numSlots管理的槽数量。ClusterNode结构的Slaves数组记录从节点名单,从节点数量numsSlaves,SlaveOf记录从属主节点,fail_report下线报告链表记录其他节点对该节点的下线报告
  • ClusterState:包括集群状态(上线/下线),集群节点数,集群节点名单,ClusterNode结构的Slots[16384]数组保存了整个集群分槽信息,slots_to_keys跳表保存槽和键之间的关系以便获取属于某个槽的所有键,ClusterNode结构的importing_slots_from[16384]数组记录了当前节点正在从其他节点导入的槽, ClusterNode结构的migrating_slots_to[16384]数组记录了当前节点正在迁移至其他节点的槽

8.2 Redis分槽与命令执行

Redis集群通过分片方式来保存数据库的键值对,整个集群被分为16384个槽[0-16383],每一个键必定属于其中一个槽

分槽信息记录与传播

  • 记录节点槽指派信息:集群上线前需要将16384个槽进行分配,不同节点会管理不同的槽,并将自己管理的槽信息记录至ClusterNode中Slot二进制数组,并且会将本节点的管理的槽信息进行传播
  • 传播节点的槽指派信息:一个节点会将自己的slots数组通过消息的方式发送给集群中的其他节点,以此来告诉他们自己目前负责哪些槽,其他节点接受到这些信息后会更新ClusterState结构的Slots数组
  • 记录集群槽指派信息:最终ClusterState中ClusterNode结构的Slots[16384]数组记录了集群的的所有分槽信息,知晓了任一槽的负责节点

重新分片实现原理
Redis重新分片操作是由集群管理软件redis-trib负责,redis-trib通过向源节点和目标节点发送命令进而实现重新分片
在这里插入图片描述

Moved错误
客户端向服务器发出键命令,节点计算该键对应的槽位置,如果该槽在本节点,直接处理,否则找到负责该槽的节点,向客户端返回一个Moved错误并带有负责节点的ip和端口信息等Moved :,客户端接受到Moved错误后将请求转向该负责节点,由该负责节点处理该请求

ACK错误
如果一个节点收到了关于键key的命令请求,并且键Key的所在槽i由该节点负责,那么该节点会尝试在自己数据库中查找Key,若找到则直接返回,若没找到可能键Key对应的槽正在迁移,则会检查migrating_slots_to[i],若槽i没有迁移则说明key不存在,若槽i确实在迁移,则会向客户端返回ACK错误,引导其到正在导入的节点中去查找Key.

8.3 故障检测故障转移与主从选举算法

故障检测原理
集群中每个节点都会定期向其他节点发送ping命令,检测对方在线情况,若在规定时间内未收到该节点的PONG回复,则将该节点标记为疑下线状态为其生成下线报告,并且将下线报告广播给其他节点,集群中各个节点通过互相发消息的方式交换各节点的状态信息。若集群中存在一个节点发现某个主节点被半数以上的主节点标记为疑下线报告,则将其标记为已下线(Fai),并向集群广播该主节点Fail的消息,所有收到Fail消息的节点都将其标记为已下线(Fai)。接下来从节点对已下线的主节点进行故障转移。

故障转移原理
(1)基于Raft选举算法从 从节点选举出主节点
(2)将下线的主节点的槽撤销并分配给新的主节点
(3)新的主节点向集群广播一条PONG消息,宣布自己从 从节点变为主节点,使其它节点刷新对自己的认知
(4)故障转移完成,新的主节点开始接受和自己负责的槽相关的命令

Redis主从选举算法
(1)当从节点得知自己跟随的主节点已下线后,会向集群中发送投票消息进行广播,要求其他负责槽的主节点对其进行投票
(2)集群中的每个负责槽的主节点都由投票权,并且都会将票投给第一个向它申请的从节点,并向其支持的从节点发送支持消息
(3)如果某个从节点收到超过半数的主节点的支持消息,则该从节点成为主节点,主从选举结束,否则,集群进入新的配置纪元,再次投票重复上述过程直到选择出一个主节点

注:为了简化,以上选举过程都默认是在同一配置纪元下进行

8.4 消息

  • MEET消息:用于集群建立,一个节点加入集群需要向所有集群中的节点进行握手,更新节点的认知。
  • PING消息:用于检测集群中节点在线情况。
  • PONG消息:用于回复MEET消息或PING消息,以及一个节点向集群广播PONG消息使其它节点刷新对自己的认知,比如故障转移成功时向集群广播一条PONG消息,宣布自己从 从节点变为主节点
  • FAIL消息:用于传播主节点已下线消息,以便集群进行故障转移
  • PUBLISH消息:用于集群所有节点执行相同命令

8.5 redis主从v哨兵vs集群区别

  • redis主从可以进行数据备份,进而进行读写分离,从节点处理读请求,主节点处理写请求,redis主从也是故障转移的必要条件
  • 哨兵用于实现故障自动转移,保证高可用性,但哨兵没有解决写操作无法负载均衡及使用的全增量式存储,存储能力受到单机限制,不具有分布式特点,需要使用集群解决,一般使用集群,不用哨兵
  • 集群不仅将数据分散存储,还提供了类似哨兵的故障转移,保证了高并发性高可用性


9. 缓存常见问题及解决方案

9.1 缓存穿透

原因:缓存穿透是指故意请求数据库中一定不存在的数据,导致缓存失效,请求全部打到数据库中了,可能导致数据库崩掉

解决方案

  • 使用布隆过滤器,利用bitmap判断请求的Key是否存在,将不存在的Key请求拦截过滤掉
  • 将空结果缓存,若在数据库对Key查询无数据,则在缓存中为Key缓存一个空值,并且设置一个很短的过期时间。

9.2 缓存击穿

原因:缓存击穿是指热点Key失效,大量请求同时请求过期键,请求全部打到数据库上去了,导致数据库崩掉。

解决方案
(1) 加入互斥锁,只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据就可以了,在分布式下可使用分布式锁(memcache的add,redis的setnx, zookeeper的添加节点操作)

String get(String key) {  
   String value = redis.get(key);  
   if (value  == null) {  
    if (redis.setnx(key_mutex, "1")) {  
        // 3 min timeout to avoid mutex holder crash  
        redis.expire(key_mutex, 3 * 60)  
        value = db.get(key);  
        redis.set(key, value);  
        redis.delete(key_mutex);  
    } else {  
        //其他线程休息50毫秒后重试  
        Thread.sleep(50);  
        get(key);  
    }  
  }  
}  

(2) “永远不过期”,在redis内部确实没有为Key设置过期时间,但在Key对应的value对象中设置1个超时值(timeout1),当从cache读取到value时若发现它要过期了,通过一个后台的异步线程进行缓存的构建。这种方法对于性能非常友好,唯一不足的就是构建缓存时候,其余线程(非构建缓存的线程)可能访问的是老数据,会出现数据不一致的情况,但是对于一般的互联网功能来说这个还是可以忍受
在这里插入图片描述

9.3 缓存雪崩

原因:缓存同一时间大面积的失效,比如缓存服务器宕机,同一时间大量缓存过期效等情况,导致大量请求打到数据库上,造成数据库短时间内承受大量请求而崩掉
解决方案
(1)保证缓存层服务高可用性,采用分布式缓存,主从替换策略进行故障转移,即使其中一台缓存服务器宕机,仍也可对外提供服务
(2)依赖隔离组件Hystrix为后端限流并降级,比如限流组件可以限制每秒最多2000个请求打到数据库上,多余的其余请求被降级,比如提示用户服务器忙,请稍后再试。
(3)为不同的key,设置不同的过期时间,在原有基础上加一个随机time,让缓存失效的时间点尽量均匀,在同一时间不会有大量的key失效

9.4 数据库与缓存一致性问题

https://www.jianshu.com/p/a9bbcd3ec1e5

高并发下缓存+数据库双写一致性方案

  • 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
  • 更新的时候,先再删除缓存,在更新数据库。
  • 根据缓存的数据一致性的要求需要根据具体业务需求决定,是允许缓存可以稍微的跟数据库偶尔有不一致的情况还是严格要求 “缓存+数据库” 必须保持一致性
  • 如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,可以采取更新数据时,先删除缓存,然后去修改数据库,但此时存在读写冲突问题,仍会引起缓存不一致
  • 如果严格要求 “缓存+数据库” 必须保持一致性,采取读请求和写请求串行化,读操作需等待对应的写操作完成后再进行。当然性能会更差,如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话最好不要做这个方案

(1) 为什么是删除缓存,而不是更新缓存?

很多时候缓存数据并不是直接从一张表就能够查到的,有时需要关联多张表才能查询到数据,并且有时写操作很多,读操作很少,导致频繁更新缓存,却又很少使用缓存,代价太高得不偿失,而删除缓存则只可保证只要在使用时需要进行一次更新缓存操作,其实是采用Lazy思想,只有缓存真正被使用的时候才去做具体工作,可以避免重复计算,重复更新问题

(2) 为什么先删除缓存在去更新数据库而不采用先更新数据库在删除缓存?

如果先删除缓存然后更新数据库,理论上是无论删除缓存删除失败还是数据库更新失败,数据库与缓存数据都会保持一致。而先更新数据库在删除缓存,当更新数据库成功,删除缓存失败,则数据库与缓存数据不一致

(3) 先删除缓存再去更新数据库的读写冲突问题?

写操作删除完缓存后,准备更新数据库的时候,如果一个读请求过来查询数据,缓存不存在,查询数据库中的旧数据,更新旧数据到缓存中。此时就会出现读写冲突的问题。那么如何解决这一方案出现的问题那?

解决方案:采取读写操作串行化,读操作等待写操作完成后再进行

更新数据的时候,根据更新的Key,将写操作路由,发送到对应的内部队列中。并且一个队列对应一个工作线程,每个工作线程拿到对应的操作,然后一条一条的执行。执行时,先删除缓存,然后再去更新数据库,

但若正准备更新时一个读请求过来,读取数据的时候,发现数据不在缓存中,根据Key路由之后,发送同一个内部队列中,并同步等待对应的写队列缓存全部更新完成,其他的读请求如果看到队列里面已经有一个读请求在排队了,那么他们就不入队列,而是在外面轮询一段时间看看缓存中是否有数据了,比如每隔10ms轮询一次,最多轮询10次,如果有则直接返回,如果读请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值。

高并发的场景下,该解决方案要注意的问题

该解决方案最大的风险点在于说,可能数据更新很频繁,导致队列中积压了大量更新操作在里面,然后读请求会发生大量的超时,最后导致大量的请求直接走数据库。务必通过一些模拟真实的测试,看看更新数据的频率是怎样的。并且估计读请求最多hang多少时间,可能需要部署多个服务,每个服务分摊一些数据的更新操作。

如果一个内存队列里居然会挤压 100 个商品的库存修改操作,每个库存修改操作要耗费 10ms 去完成,那么最后一个商品的读请求,可能等待 10 * 100 = 1000ms = 1s 后,才能得到数据,这个时候就导致读请求的长时阻塞。一定要做根据实际业务系统的运行情况,去进行一些压力测试,和模拟线上环境,去看看最繁忙的时候,内存队列可能会挤压多少更新操作,可能会导致最后一个更新操作对应的读请求,会 hang 多少时间,如果读请求在 200ms 返回,如果你计算过后,哪怕是最繁忙的时候,积压 10 个更新操作,最多等待 200ms,那还可以的。如果一个内存队列中可能积压的更新操作特别多,那么你就要加机器,让每个机器上部署的服务实例处理更少的数据,那么每个内存队列中积压的更新操作就会越少。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值