From b39db9446a1d8913341a5aa928a176dfce7f82e7 Mon Sep 17 00:00:00 2001 From: CyC2018 Date: Wed, 4 Nov 2026 22:39:57 +0800 Subject: [PATCH] Update Redis.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 I/O 线程不处理的连接类型,以及成员上千万时排行榜的拆分。 --- notes/Redis.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/notes/Redis.md b/notes/Redis.md index 95f893a7..77f6b637 100644 --- a/notes/Redis.md +++ b/notes/Redis.md @@ -374,6 +374,10 @@ ZREVRANK rank:likes article:1001 -- 第几名,从 0 开始 分值相同时,Redis 按成员名的字典序排列,而业务上通常要求先达到这个分数的排在前面。可以把时间编进分值:分值 = 点赞数 × 1010 + (1010 − 达到这个点赞数的秒级时间戳)。例如 article:1001 和 article:1002 都是 520 个赞,时间戳分别为 1793000000 和 1793000300,分值为 5208207000000 和 5208206999700,先达到的 article:1001 排在前面。需要注意的是,分值是双精度浮点数,只能精确表示 253 以内的整数,这种写法下点赞数不能超过约 90 万,更大时要缩短时间部分的位数。 +成员上千万时,一个有序集合就成了[大 Key](缓存.md#大-key-与热-key),按 100 万个约 105 MB 估算,1000 万个约 1 GB。可以按分数段拆成多个有序集合,名次等于分数更高的各段的成员数之和,加上在本段中的名次,加分跨段时把成员移到新的段。 + +只需要显示“超过了约百分之多少的用户”时,可以按分数区间计数,用户换分时把旧区间的计数减 1、新区间的加 1,不必把每个成员都放进有序集合。同一区间内谁高谁低无从得知,结果是近似值,区间分得越细越准。 + 排行榜被大量用户同时查看时,前 10 名这个键会成为热点。前几名的变化不需要实时反映给每个用户,可以在应用的本地缓存中保存 1 秒,大部分请求不再访问 Redis,见 [多级缓存](缓存.md#多级缓存)。 ### 其它 @@ -650,7 +654,7 @@ Redis 用一个线程执行所有命令,仍然很快,原因主要有以下 Redis 6.0 加入的 I/O 多线程(io-threads,默认关闭)分担的也是这部分开销:多个 I/O 线程并行读取、解析请求和写回响应,命令仍由主线程逐条执行,不会有两个线程同时修改一个键。6.0 和 7.x 默认只把写回交给 I/O 线程,读取和解析还要打开 io-threads-do-reads,并且主线程分发完任务后要忙等所有 I/O 线程完成。 -8.0 重新实现后,每个 I/O 线程有自己的事件循环,负责普通客户端的读取、解析和写回;命令仍由主线程执行,主从复制、订阅等特殊连接的读写也由主线程处理(8.8 起主从复制的连接也交给 I/O 线程)。8.0 的 io-threads 把主线程也算作一个,例如 io-threads 4 表示主线程加 3 个 I/O 线程。 +8.0 重新实现后,每个 I/O 线程有自己的事件循环,负责普通客户端的读取、解析和写回;命令仍由主线程执行,主从复制、订阅、MONITOR 和阻塞中的连接这类特殊连接的读写也由主线程处理(8.6 起主从复制的连接在完成全量同步后也交给 I/O 线程)。8.0 的 io-threads 把主线程也算作一个,例如 io-threads 4 表示主线程加 3 个 I/O 线程。