您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    硬核干货!7600字带你学会 Redis 功用优化点(2)
    时间:2020-05-08 21:07 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    在大数据量的状况下,有些操作的执行时间会相对长,比如 KEYS *,LRANGE mylist 0 -1,以及其他算法复杂度为 O(n) 的指令。由于 Redis 只用一个线程来做数据查询,假设这些指令耗时很长,就会阻塞 Redis,形成少量延时。

    虽然官方文档中说 KEYS *的查询挺快的,(在普通笔记本上)扫描 1 百万个 key,只需 40 毫秒(参见:https://redis.io/commands/keys),但几十 ms 关于一个功用要求很高的系统来说,曾经不短了,更何况假设有几亿个 key(一台机器完全能够存几亿个 key,比如一个 key 100字节,1 亿个 key 只要 10GB),时间更长。

    所以,尽量不要在消费环境的代码运用这些执行很慢的指令,这一点 Redis 的作者在博客[8]中也提到了。另外,运维同窗查询 Redis 的时分也尽量不要用。甚至,Redis Essential 这本书建议应用rename-command KEYS ''来制止运用这个耗时的指令。

    除了这些耗时的指令,Redis 中 transaction,script,由于可以兼并多个 commands 为一个具有原子性的执行进程,所以也能够占用 Redis 很长时间,需求留意。

    假设你想找出消费环境运用的「慢指令」,那么可以应用 SLOWLOG GET count来查看最近的 count 个执行时间很长的指令。至于多长算长,可以经过在 redis.conf 中设置 slowlog-log-slower-than 来定义。

    除此之外,在很多中央都没有提到的一个能够的慢指令是 DEL,但 redis.conf 文件的注释[9]中倒是说了。长话短说就是 DEL 一个大的 object 时分,回收相应的内存能够会需求很长时间(甚至几秒),所以,建议用 DEL 的异步版本:UNLINK。后者会启动一个新的 thread 来删除目的 key,而不阻塞原来的线程。

    更进一步,当一个 key 过时之后,Redis 普通也需求同步的把它删除。其中一种删除 keys 的方式是,每秒 10 次的反省一次有设置过时时间的 keys,这些 keys 存储在一个全局的 struct 中,可以用 server.db->expires拜访。反省的方式是:

    从中随机取出 20 个 keys

    把过时的删掉。

    假设刚刚 20 个 keys 中,有 25% 以上(也就是 5 个以上)都是过时的,Redis 以为,过时的 keys 还挺多的,继续重复步骤 1,直到满足参加条件:某次取出的 keys 中没有那么多过去的 keys。

    这里关于功用的影响是,假设真的有很多的 keys 在同一时间过时,那么 Redis 真的会不断循环执行删除,占用主线程。

    对此,Redis 作者的建议[10]是警觉EXPIREAT这个指令,由于它更容易产生 keys 同时过时的现象。我还见到过一些建议是给 keys 的过时时间设置一个随机波动量。最后,redis.conf 中也给出了一个办法,把 keys 的过时删除操作变为异步的,即,在 redis.conf 中设置lazyfree-lazy-expire yes。

    优化数据结构、运用正确的算法

    一种数据类型(比如 string,list)停止增删改查的效率是由其底层的存储结构决议的。

    我们在运用一种数据类型时,可以适当关注一下它底层的存储结构及其算法,避免运用复杂度太高的办法。举两个例子:

    ZADD的时间复杂度是 O(log(N)),这比其他数据类型添加一个新元素的操作更复杂,所以要小心运用。

    若 Hash 类型的值的 fields 数量有限,它很有能够采用 ziplist 这种结构做存储,而 ziplist 的查询效率能够没有同等字段数量的 hashtable 效率高,在必要时,可以调整 Redis 的存储结构。

    除了时间功用上的思索,有时分我们还需求节省存储空间。比如下面提到的 ziplist 结构,就比 hashtable 结构节省存储空间(Redis Essentials 的作者辨别在 hashtable 和 ziplist 结构的 Hash 中插入 500 个 fields,每个 field 和 value 都是一个 15 位左右的字符串,结果是 hashtable 结构运用的空间是 ziplist 的 4 倍。)。但节省空间的数据结构,其算法的复杂度能够很高。所以,这里就需求在详细成绩面前做出权衡。欢迎关注群众号:朱小厮的博客,回复:1024,可以支付redis专属材料。

    如何做出更好的权衡?我觉得得深挖 Redis 的存储结构才能让本人安心。这方面的内容我们下次再说。

    以上这三点都是编程层面的思索,写顺序时应该留意啊。下面这几点,也会影响 Redis 的功用,但处置起来,就不只是靠代码层面的调整了,还需求架构和运维上的思索。

    思索操作系统和硬件能否影响功用

    Redis 运转的外部环境,也就是操作系统和硬件显然也会影响 Redis 的功用。在官方文档中,就给出了一些例子:

    CPU:Intel 多种 CPU 都比 AMD 皓龙系列好

    虚拟化:实体机比虚拟机好,主要是由于部分虚拟机上,硬盘不是本地硬盘,监控软件招致 fork 指令的速度慢(耐久化时会用到 fork),尤其是用 Xen 来做虚拟化时。

    内存管理:在 linux 操作系统中,为了让 translation lookaside buffer,即 TLB,可以管理更多内存空间(TLB 只能缓存有限个 page),操作系统把一些 memory page 变得更大,比如 2MB 或许 1GB,而不是通常的 4096 字节,这些大的内存页叫做 huge pages。同时,为了方便顺序员运用这些大的内存 page,操作系统中完成了一个 transparent huge pages(THP)机制,使得大内存页对他们来说是透明的,可以像运用正常的内存 page 一样运用他们。但这种机制并不是数据库所需求的,能够是由于 THP 会把内存空间变得紧凑而延续吧,就像mongodb 的文档[11]中明白说的,数据库需求的是稀疏的内存空间,所以请禁掉 THP 功用。Redis 也不例外,但 Redis 官方博客上给出的理由是:运用大内存 page 会使 bgsave 时,fork 的速度变慢;假设 fork 之后,这些内存 page 在原进程中被修正了,他们就需求被复制(即 copy on write),这样的复制会消耗少量的内存(毕竟,人家是 huge pages,复制一份消耗成本很大)。所以,请制止掉操作系统中的 transparent huge pages 功用。

    (责任编辑:admin)