懒 Redis 是更好的 Redis

  • 时间:
  • 浏览:0
  • 来源:彩神大发11选5_神彩大发11选5官方

第一次尝试

假如有一天,嘿,还才能 再多说一句的是,意味 在 SUNIONSTORE 命令却说重新加载了数据库,对象都撤回了共享,内存也会有另1个劲回复到最初的具体情况。这可不太妙。接下来我们当我们 发送应答请求给客户端,会咋样样?当对象比较小时,我们当我们 实际上是把它们拼接成线性的缓存,要不然进行多次 write() 调用下行速率 是不高的!(婚姻的语句提示,writev() 并没法 帮助)。于是我们当我们 大每段具体情况下意味 群克隆了数据。对于编程来说,没法 用的东西却趋于稳定,通常意味 是有什么的什么的问题 的。

意味 慢慢的在后台去删除myset,一块儿SADD调用又在不断的添加絮状的元素,内存使用量意味 有另1个劲增长。

我在组织组织结构增加了统统东西,明天就上线看上去是不现实的。我的计划是先让3.2版(意味 是unstable具体情况)成为候选版本(RC)具体情况,假如有一天把我们当我们 的分支合并到进入unstable的3.4版本。

最后,我把增量式的延迟释放实现从分支里删除,只保留了应用多多线程 化的实现。

https://github.com/antirez/redis/issues/1748

好在经过一段尝试却说,我找到有两种都才能 工作的很好的依据。定时器函数里使用了有有有另1个想法来适应内存的压力:

你知道这里最困难的每段是哪里吗?这次我们当我们 是在增量式的做一件很有点硬的事情:释放内存。意味 内存的释放是增量式的,服务器的内容增长意味 非常快,最后为了得到更少的延时,会消耗调无限的内存。这很糟,想象一下,有下面的操作:

对于单应用多多线程 服务器,为了让操作不阻塞,最简单的依据统统我用增量的依据某些点来,而否有一下子把整个世界都搞懂。类事 ,意味 要释放有有有另1个百万级的对象,都才能 每有有有另1个毫秒释放100个元素,而否有在有有有另1个 for() 循环里一次性全做完。CPU 的耗时是差太多的,跟我说会稍微多某些,意味 逻辑更多某些,假如有一天从用户来看延时更少某些。当然跟我说实际上并没法 每毫秒删除100个元素,这统统我个例子。重点是咋样正确处理秒级的阻塞。在 Redis 组织组织结构做了统统事情:最显然易见的是 LRU 淘汰机制和 key 的过期,还有某些方面的,类事 增量式的对 hash 表进行重排。

还有,现在也都才能 在某些应用多多线程 实现针对聚合数据类型的特定的慢操作,都才能 让某些 key 被“阻塞”,假如有一天所有某些的客户端无需被阻塞。这些 都才能 用很类事 现在的阻塞操作的依据去完成(参考blocking.c),统统我增加有有有另1个哈希表保存哪此正在正确处理的 key 和对应的客户端。于是有有有另1个客户端请求类事 SMEMBERS 另有有有另1个的命令,意味 统统我仅仅阻塞住这有有有另1个 key,然否有创建输出缓存正确处理数据,却说在释放这些 key。非要哪此尝试访问相同的 key 的客户端,才会在这些 key 被阻塞的却说被阻塞住。

这里有一小段代码,不过这些 想法现在意味 不再实现了:

不统统我延迟释放

结果是 Redis 现在在内存使用上更加高效,意味 在数据特征的实现上不再使用 robj 特征体(不过意味 某些代码还涉及到絮状的共享,统统 robj 依然趋于稳定,类事 在命令派发和群克隆每段)。应用多多线程 化的延迟释放工作的很好,比增量的依据更能减少内存的使用,嘴笨 增量依据在实现上与应用多多线程 化的依据类事 ,假如有一天也没没法 糟糕。现在,你都才能 删除有有有另1个巨大的 key,性能损失都才能 忽略不计,这非常有用。不过,最有趣的事情是,在我测过的某些操作上,Redis 现在否有调快某些。消除间接引用(Less indirection)最后胜出,即使在不相关的某些测试上也调快某些,还意味 客户端的输出缓存现在更加简单和高效。

所有哪此需求起了更激烈的组织组织结构变化,但这里的底线我们当我们 已很少顾忌。我们当我们 都才能 补偿对象群克隆时间来减少高速缓存的缺失,以更小的内存占用聚合数据类型,统统我们当我们 现在可依照应用多多线程 化的 Redis 来进行无共享化设计,这些 设计,都才能 很容易超越我们当我们 的单应用多多线程 。在过去,有有有另1个应用多多线程 化的 Redis 看起来总像是有有有另1个坏主意,意味 为了实现并发访问数据特征和对象其必定是一组互斥锁,但幸运的是还有别的选取获得这有有有另1个环境的优势。意味 我们当我们 却说,我们当我们 依然都才能 选取快速操作服务,就像我们当我们 过去在主应用多多线程 所做的那样。这蕴藏在错综复杂的代价之上,获取执行智能(performance-wise)。

意味 添加整个 tobj 特征体,把聚合类型转添加 SDS 字符串类型的哈希表(意味 跳表)会咋样样?(SDS是Redis组织组织结构使用的字符串类型)。

另有有有另1个做有个什么的什么的问题 ,假设有个命令:SADD myset myvalue,举个例子来说,我们当我们 做非要通过client->argv[2] 来引用用来实现集合的哈希表的某个元素。我们当我们 不得不统统次的把值群克隆出来,即使数据意味 在客户端命令解析后创建的参数 vector 里,也没依据去复用。Redis的性能受控于缓存失效,我们当我们 跟我说都才能 用稍微间接某些的依据来弥补一下。

于是我在这些 lazyfree 的分支上刚开始了一项工作,假如有一天在 Twitter 上聊了一下,假如有一天没法 回应 上下文的细节,结果所有的人都嘴笨 我像是绝望意味 疯狂了(甚至没法人喊道 lazyfree 到底是哪此玩意)。没法 ,我到底做了哪此呢?

UNLINK 是有有有另1个聪明的命令:它会计算释放对象的开销,意味 开销很小,就会直接按 DEL 做的那样立即释放对象,假如有一天对象会被倒进后台队列里进行正确处理。除此之外,这有有有另1个命令在语义上是相同的。

文章转载自 开源中国社区[https://www.oschina.net]

计划表

关于 API 的某些备注

不过在合并却说,才能 对下行速率 做细致的回归测试,这有不少工作要做。

过后开始我们当我们 是另有有有另1个尝试的:创建有有有另1个新的定时器函数,在上面实现淘汰机制。对象统统我被添加到有有有另1个链表里,每次定时器调用的却说,会逐步的、增量式的去释放。这才能 某些小技巧,类事 ,哪此用哈希表实现的对象,会使用 Redis 的 SCAN 命令里相同的机制去增量式的释放:在字典里设置有有有另1个游标来遍历和释放元素。通过这些 依据,在每次定时器调用的却说我们当我们 不才能 释放整个哈希表。在重新进入定时器函数时,游标都才能 他不知道们上次释倒进哪里了。

事实上,访问有有有另1个蕴藏聚合类型数据的key,才能 经过下面哪此遍历过程:

适配是困难的

我们当我们 都知道 Redis 是单应用多多线程 的。真正的内行会告诉你,实际上 Redis 并否有删改单应用多多线程 ,意味 在执行磁盘上的特定慢操作否有有多应用多多线程 。目前为止多应用多多线程 操作绝大每段集中在 I/O 上以至于在不同应用多多线程 执行异步任务的小型库被称为 bio.c: 也统统我 Background I/O。

现在聚合数据类型的值否有再共享了,客户端的输出缓存统统我再蕴藏共享对象了,这某些有统统文章可做。类事 ,现在终于都才能 在 Redis 里实现应用多多线程 化的 I/O,从而不同的客户端都才能 由不同的应用多多线程 去服务。也统统我说,非要访问数据库才才能 全局的锁,客户端的读写系统调用,甚至是客户端发送的命令的解析,都都才能 在应用多多线程 中去正确处理。这跟 memcached 的设计理念类事 ,我比较期待才能被实现和测试。

这听起来很合理,假如有一天一块儿即便用快速操作创建的对象却说 需要 被删除。在这些 具体情况下,Redis 会阻塞。

这是有有有另1个小技巧,工作的也很好。不过懊恼的是我们当我们 还是不得没哟单应用多多线程 里执行。要做好才能 有统统的逻辑,假如有一天当延迟释放(lazy free)周期很繁忙的却说,每秒能完成的操作会降到平时的65%左右。

意味 是在另有有有另1个应用多多线程 去释放对象,那就简单多了:意味 有有有有另1个应用多多线程 只做释放操作语句,释放有另1个劲要比在数据集里添加数据来的要快。

不过 API 又咋样样了呢?DEL 命令仍然是阻塞的,默认还跟却说一样,意味 在 Redis 中 DEL 命令就意味 释放内存,我不须打算改变这某些。统统现在你都才能 用新的命令 UNLINK,这些 命令更清晰的表明了数据的具体情况。

我们当我们 也实现了 FLUSHALL/FLUSHDB 的非阻塞版本,不过没法 新增的 API,统统我增加了有有有另1个 LAZY 选项,说明否有更改命令的行为。

意味 你现在就想尝试语句,都才能 从Github上下载lazyfree分支。不过要注意的是,当前我并否有很频繁的更新这些 分支,统统某些地方意味 会非要工作。

然而前阵子我提交了有有有另1个什么的什么的问题 ,在什么的什么的问题 里我承诺提供有有有另1个统统人(包括我当时人)都却说的功能,叫做“免费懒加载”。原始的什么的什么的问题 在这

不过,要实现应用多多线程 化的延迟释放有有有有另1个什么的什么的问题 报告 ,那统统我 Redis 自身。组织组织结构实现完否有追求对象的共享,最终否有些引用计数。干嘛不尽意味 的共享呢?另有有有另1个都才能 节省内存和时间。类事 :SUNIONSTORE 命令最后得到的是目标集合的共享对象。类事 的,客户端的输出缓存蕴藏了作为返回结果发送给socket的对象的列表,于是在类事 SMEMBERS 另有有有另1个的命令调用却说,集合的所有成员否有意味 最终在输出缓存里被共享。看上去对象共享是没法 有效、漂亮、精彩,还有点硬酷。

什么的什么的问题 的根本在于,Redis 的 DEL 操作通常是阻塞的。假如有一天意味 你发送 Redis “DEL mykey” 命令,碰巧你的 key 有 1000万个对象,没法 服务器意味 阻塞几秒钟,在此期间服务器无需正确处理某些请求。历史上这被当做 Redis 设计的副作用而被接受,假如有一天在特定的用例下这是有有有另1个局限。DEL 否有唯一的阻塞式命令,却是特殊的有有有另1个命令,意味 我们当我们 认为:Redis 非常快,假如有一天你用错综复杂度为 O(1) 和 O(log_N) 的命令。你都才能 自由使用 O(N) 的命令,假如有一天要知道这否有我们当我们 优化的用例,你才能 做好延迟的准备。

当然,主应用多多线程 和延迟释放应用多多线程 直接对内存分配器的使用肯定会有竞争,不过 Redis 在内存分配上只用到一小每段时间,更多的时间用在I/O、命令派发、缓存失败等等。