五个格子表示偏移 0–4 的字节 00 FF E8 8C B6;括号将后三字节标为 UTF-8 茶,STRLEN 为 5。

Redis 字符串保存字节,不固定数据模式

Redis 字符串是在一个键下保存的一段二进制安全字节序列,可以装文本、序列化文档,也可以装十进制计数器。这里的“基础类型”描述的是对外的数据模型,不代表所有 Redis 数据结构都由字符串拼接实现。哈希、列表等类型有各自的命令、内部表示和更新规则,不能只凭字符串命令推断其他类型的行为。 先确定字节,再解释内容 SET 与 GET 能原样存取字节,包括零字节和不是有效 UTF-8 的内容。STRLEN 返回字节数,GETRANGE 的起止位置也是字节偏移,而且两端都包含在结果中,并不是按人眼看到的字符切片。因此,一个范围完全可能只取到某个多字节字符的一部分。客户端是否自动把返回值解码成文本,是另一层选择;任意二进制数据应关闭自动解码,只对应用明确知道编码的内容进行转换。 把 JSON 文本存进去,不会让这个键自动变成 Redis 哈希,也不会让哈希命令获得按字段访问 JSON 的能力。同样,整数命令是在执行时解释现有字节,并没有给这个键设置永久的数字类型约束。序列化方式、键名约定和读写双方对值类型的理解,都需要应用自己维护。文档给出的单个字符串默认上限是 512 MiB,但上限不是推荐负载大小,更不应该拿它作为每个缓存对象的设计目标。 原子自增有明确边界 INCR 把不存在的键当作零,再对十进制有符号六十四位整数执行加一。不能解释为整数的内容和越界运算都会报错,而不是回绕。INCRBY 用来改变步长;INCRBYFLOAT 遵循另一套浮点语义,如果需要精确的整数序列,就不能把它当作等价替代。 一条 INCR 消除了先 GET、再计算、最后 SET 之间的丢失更新窗口。不过,服务器已经完成自增而响应在途中丢失时,客户端重试仍可能再加一次。命令原子性不等于请求幂等,也不意味着经历删除、到期、复制故障或主从切换后还能提供持久且全局唯一的编号。下面的并发实验只验证一个正在运行的实例,不给这些跨故障场景背书。 坏掉的样子 对 JSON 字符串调用 HGET 会得到 WRONGTYPE。普通 SET 则有相反的风险:它能够把已有哈希整体替换成字符串,原来的字段随之丢失。因此需要按值的契约区分键名空间,并检查所有写入方实际使用的命令。某个键过去存过哈希,并不意味着这个名字以后会被 Redis 强制约束为哈希。 ...

一月 28, 2027 · 3 分钟 · XB Field Notes
原有实验把参数已知的 SET counter 4、INCR 和 GET 排队,依次得到 True、5 和字节串 5。普通流水线不添加 MULTI 或 EXEC,命令报错也不会取消已提交的后续命令。

Redis 流水线减少逐条命令等待

Redis 流水线允许客户端连续发送多条命令,不必等前一条回应以后再发下一条。它减少了请求与响应之间的等待,也能分摊套接字输入输出开销。但服务端仍需要执行每条命令并生成回复;批处理不代表这些命令并行运行,也不自动形成事务边界。 原有实验把参数已知的 SET counter 4、INCR 和 GET 排队,依次得到 True、5 和字节串 5。普通流水线不添加 MULTI 或 EXEC,命令报错也不会取消已提交的后续命令。 仅为原有实验示意,本轮未重跑。 少等几次,而不是少执行几条 同步循环不断重复发送一条、等待一条。流水线则先发送一个序列,再按对应顺序收取回复。把一批近似理解为一次往返,可以帮助估算延迟,但不能据此承诺只有一个 TCP 数据包、一次系统调用,或所有回应在同一时刻到达。实际传输仍受缓冲区、数据量和协议处理影响。 收益也不只出现在远程链路。把套接字读写集中起来,可以减少系统调用和调度开销,所以即使本地连接,也可能在不分片的情况下提高实际吞吐。反过来,流水线消除不了昂贵命令本身的工作和带宽上限。应先定位真实瓶颈,而不是看到单节点就断言下一步必须加分片。 普通流水线没有“不被插队”的保证。其它客户端可能在批次的命令之间执行操作,但具体某一次运行也可能碰巧全部连续完成。观察到一次连续执行,并不能把它上升为事务隔离承诺。正确性不能依赖一次测试里没有出现的调度交错。 ...

一月 20, 2027 · 3 分钟 · XB Field Notes
五个已知 Sentinel 观察者示意:quorum 二认定故障,多数三授权故障转移。

Sentinel 有两道门:示意。

Redis Sentinel 协调主节点故障转移

Redis Sentinel 监督非 Cluster 的主从部署,并提供当前主节点地址。它不存储应用数据集,也不代理应用命令。主节点失败后自动提升副本,可以帮助恢复写入可用性,但服务发现、副本数据新鲜度、客户端重连以及阻止旧写者继续写入,仍然是不同的问题,不能由“有哨兵”三个字一并保证。 故障认定与选举授权是两道门 一个 Sentinel 在足够长时间收不到可接受回复后,会把实例标记为主观下线;达到配置的 quorum 都认为主节点不可达,才形成客观下线判断。这个故障判定阈值不等于故障转移领导者获得授权所需的多数。选举还必须达到配置的 quorum,因此将 quorum 设置得更高,也可能进一步提高授权门槛。 例如五个已知 Sentinel 配置 quorum 为二,两个观察者可以同意主节点发生故障,但授权提升仍需要三个构成多数。反过来,quorum 为一也不意味着三个已知观察者只剩一个时,它能独自授权。SENTINEL CKQUORUM 会检查这两项可达性条件;某个 Redis 进程看上去健康,并不能证明观察者满足条件。 稳健部署至少需要三个处在独立故障范围内的 Sentinel。同一台笔记本上的三个进程能测试协议行为,却会随整台机器一起失效。每个 Sentinel 还需要可写的配置文件,持久保存发现的拓扑与纪元状态;这些不是随时可以丢弃的普通静态配置,也应保护其中可能存放的认证材料。 提升副本不会阻止所有旧连接写入 Redis 使用异步复制,被选中的副本可能没有收到旧主已经确认的一条写入。网络分区时,留在旧主一侧的客户端甚至可能继续向它写入,而另一侧已经提升替代节点。Sentinel 协调选举,并不等于撤销所有旧连接的写权限,更不会把 Redis 自动变成强一致存储。 min-replicas-to-write、min-replicas-max-lag 等设置可以在复制健康度下降时限制写入,同时牺牲部分可用性;它们不是通用的隔离旧写者协议。仍需独立备份和明确的应用恢复规则。网络分区、复制落后和单纯杀死一个进程应分别验证,不能用其中一个结果替代其他情形。 客户端需要重新发现并建立连接 支持 Sentinel 的客户端先查询观察者拿到主节点地址,再直接连接 Redis。因此,它要处理暂时发现不到主节点、连接断开和角色改变。只认旧地址的客户端,不会因为某个哨兵已经更新答案就自动恢复;同样,写请求超时也不能证明操作从未执行。 下面的代码在发现新的主节点后,明确断开应用的旧连接池,再检查新连接。这样能够单独验证重连环节,而不是承诺故障转移对调用方完全不可见。切换窗口内不能盲目重复非幂等写操作,节点提升并没有替业务提供去重机制。 ...

一月 9, 2027 · 4 分钟 · XB Field Notes