【译】antirez:Redis6将支持客户端缓存

本文翻译自Redis作者antirez的一篇博客,原文地址是:http://antirez.com/news/130

纽约Redis日已经结束了,我仍然与意大利时区同步,早上5点30起床,并立即走上了曼哈顿的街道,我很喜欢这里的风景,并且享受着成为这里的一部分。当时我正在考虑发布Redis 6的release版本,这是在未来一段时间最重要的事了。新版本的Redis协议(RESP3)推进得还很慢,如果没有一个好的理由,明智的人是不会更换工具的。但我为什么要坚持提升协议呢?有两个主要的原因,一是需要给客户端提供更加具有语义的回复,二是提供一个旧版本不能实现的新功能:客户端缓存。

时间倒回一年前,我到达圣安东尼奥的Redis Conf 2018。当时公司就有一个共识是客户端缓存是Redis在未来非常重要的事情。如果我们需要更快的存储和更快的缓存,我们就需要在客户端存储一部分信息。这是提供低延迟和大规模数据服务的很自然的想法。事实上,基本上每个大公司也都是这样做的,因为这是唯一的办法。然而Redis没有办法在这一过程中协助客户。一个巧合让Ben Malec想要在Redis Conf上做一些关于客户端缓存的演讲,他只使用Redis提供的工具和一些非常聪明的想法。

作者注:演讲地址是https://www.youtube.com/watch?v=kliQLwSikO4

Ben的演讲启发了我,为了实现Ben的设计,其中有两个关键点。第一个是使用Redis Cluster的“hash slot”的概念,把key分成了16k个组。采用这种方式使得客户端不需要追踪每一个key的位置,可以使用一个简单的元数据来定位key所在的group。Ben使用Pub/Sub模式来通知key的改变,所以他需要应用程序的一些帮助,然而这种模式是很固定的。要修改一个key?还需要发布失效消息。在客户端是否缓存了key呢?要记住缓存每个key和收到失效消息时的时间戳,记住每个slot的失效时间。当使用一个缓存的key时,先做一个懒清除,通过检查缓存key的时间戳是否早于slot收到失效信息的时间戳。这种情况下,这个key就是过时的数据,你可以再次访问服务器。

在看完演讲之后,我意识到这是一个在服务器内使用的好主意,为了让Redis能够为客户端做一部分工作,是客户端缓存更加简单高效,所以我回到家写下了我的设计文档:https://groups.google.com/d/msg/redis-db/xfcnYkbutDw/kTwCozpBBwAJ

但为了实现我的设计,我必须专注于修改Redis协议使它变得更加完善,所以我开始编写RESP3和Redis 6的其他特性(比如ACL)的规范和代码,客户端缓存是Redis许多迭代想法中的一种,有些想法因为时间不够放弃了。

当时我在纽约街头思考这个想法。后来和一些朋友去吃午饭喝咖啡。当我返回酒店房间后,距离第二天起飞还有一整晚的时间,所以我开始按照一年前写的提案来写Redis 6的客户端缓存的实现。

Redis服务器助理客户端缓存,最终叫做“tracking”(我也可能改主意),是一个由几个关键想法组成的非常简单功能。

key空间被分割到”caching slots“,但他们比Ben使用的hash slots要多得多。我们使用CRC64的24位输出,所以有超过1600万个不同的slot。为什么这么多呢?因为我认为你想要有一个1亿key的服务器。然而一个失效信息影响的key不应该多于客户端缓存中的key。Redis中失效表占用130M的内存:8字节的指针指向16M的条目。这对我来说是可以接受的,如果你想要使用新功能,你将充分利用你在客户端的所有内存,所以使用130MB在服务器端是好的,你可以获得更细粒度的失效。

客户端使用“opt in”方法开启这个功能,只需要一个简单的命令:

CLIENT TRACKING on

服务器总是返回+OK,从这时起,每个命令都在命令表中被标记为“只读”,不再给调用者返回keys,并记住客户端请求的所有的key。保存这种信息时非常简单的,每个Redis客户端都有自己的唯一ID,所以如果ID是123的客户端发送了MGET命令,需要从slot 1,2和5获取key,那么失效表中我们就需要记录如下信息:

1 -> [123]
2 -> [123]
5 -> [123]

接着,ID为444的客户端也需要到slot5请求key了,那么表信息将变成:

5 -> [123,444]

现在其他客户端修改了slot 5中的某个key,Redis将会检查失效表,发现客户端123和444都缓存了这个slot上的key。我们将会给这些客户端发送失效信息,然后会记录下slot最后的失效时间戳,并在以后懒检查缓存对象的时间戳,并对照后判断是否失效。此外,客户端可以回收表中缓存的指定slot的对象。这种具有24位hash函数的方法不是问题,因为我们即使缓存几千万的key,也不会有很长的列表。发送了失效信息后,我们就可以删除失效表中的项,这样直到这些客户端不再读这些slot的key,我们就不再向他们发送失效消息。

需要注意的是,客户端不必强制使用24位hash函数。也可能使用20位,然后移动Redis发送的失效消息的slot。不确定是否有很多很好的理由这样做,但是内存受限时,这可能是一种想法。

如果你密切关注我说的话,你会开始考虑同一连接既会接收到正常的客户端回复,又会接收失效消息。这可以通过RESP3实现,因为失效作为“推送”消息类型发送。如果客户端是一个阻塞类型的,并且不是事件驱动类型的客户端,就会变得比较复杂:

应用程序需要一些方法来不时读取新数据,这看起来既复杂又脆弱。在这种情况下,为了接收失效消息,使用另一个应用程序线程和不同的客户端可能会更好。所以你可以使用以下命令来允许这样的操作:

CLIENT TRACKING on REDIRECT 1234

基本上我们可以说我们使用当前连接获得的所有key,并希望失效消息发送到客户端1234。在连接池的情况下多个客户端可能会要求将失效消息重定向到单个客户端。你需要做的就是创建特殊连接以接收失效消息,调用CLIENT ID以了解此客户端连接哪个ID,然后启用跟踪。

现在只剩下一个问题了:如果我们失去了失效连接怎么办?我们可能因为不能接收到失效消息而陷入麻烦。通常,应用会检测连接,尝试重连,并清除缓存。为了确保失效连接处于连接状态,不时地向服务器发送ping请求可能是一个更好的主意。然而,为了降低过期数据的风险,Redis也将开始通知客户端将失效消息重定向到其他客户端,只要使用特殊的推送消息:下一个请求就会使客户端知道连接已经断开。

我刚才描述的已经合并到Redis的unstable分支。可能不是最终的处理方法,但是在第一个Redis 6发布版本之前还有几个月的时间,我们还有时间修改所有的事情:可以告诉我你的反馈。我也会再寻找其他RESP2可行的方法。这只有在重定向开启时才有效,并且客户端要进入Pub/Sub模式监听消息。通过这种方式,完全可以复用旧客户端。

我希望这足以刺激你的胃口:如果我们在Redis中运行的很好,然后记录下来,让客户端作者知道该如何支持,数据可能比以往更接近应用程序,甚至在小型团队运行的应用程序中,到目前为止还没有尝试客户端缓存。对于正在准备做的大型团队和非常大的应用程序,降低实现成本和复杂性。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,468评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,620评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,427评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,160评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,197评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,334评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,775评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,444评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,628评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,459评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,508评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,210评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,767评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,850评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,076评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,627评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,196评论 2 341

推荐阅读更多精彩内容

  • 五种数据结构简介 Redis是使用C编写的,内部实现了一个struct结构体redisObject对象,通过结构体...
    彦帧阅读 6,923评论 0 14
  • 包含的重点内容:JAVA基础JVM 知识开源框架知识操作系统多线程TCP 与 HTTP架构设计与分布式算法数据库知...
    消失er阅读 4,285评论 1 10
  • NOSQL类型简介键值对:会使用到一个哈希表,表中有一个特定的键和一个指针指向特定的数据,如redis,volde...
    MicoCube阅读 3,956评论 2 27
  • TCP 与 HTTP http1.0 和 http1.1 有什么区别。 HTTP 1.0主要有以下几点变化: 请求...
    冷枫abc阅读 461评论 0 0
  • 1、拍人像 拍人长焦大圈先(AV光圈优先自动曝光模式,长焦大光圈浅景深,宜于突出主题虚化背景,通常F5.6及以上)...
    明先森吖阅读 1,481评论 20 90