来源:Redislabsredis
做者:Kyle Davis安全
翻译:Kevin (公众号:中间件小哥)服务器
Redis 4.0给Redis生态带来了一个惊人的功能:Modules(模块)。Modules是Redis的一大转变,它是Redis内部自定义数据类型和全速计算的开放环境。可是,尽管对该版本的大多数关注都集中在Modules上,但新版本还引入了一个很是重要的命令,它就是游戏规则的改变者:UNLINK。网络
您可使用redis-cli链接redis-server执行info命令,去查看当前redis版本中是否可使用UNLINK命令。info响应将告诉您有关服务器的全部信息。在第一部分(#Server)中,返回结果有一行值为redis_version。若是该值大于4.0,则可使用UNLINK命令。并不是全部Redis提供商都保持最新版本,所以最好在更改代码以前检查redis版本。数据结构
让咱们回顾一下Redis的关键架构功能之一:“单线程”。Redis在大多数状况下是一个单线程应用程序。它一次只作一件事,这样能够把这些事作的更快。多线程有点复杂,而且引入了锁和其余可能下降应用程序速度的问题。尽管Redis(最高4.0版)经过多线程方式执行了少许操做,但它一般在启动另外一个命令以前先要完成一个命令。多线程
相比于快速读写,您可能会以为使用DEL命令去删除一个键值不须要考虑太多,可是在不少状况下,删除数据一样很重要。与Redis中的大多数命令同样,DEL命令在单个线程中运行,若是您获取一个几千字节的键值,花费不到一毫秒的时间,这是您所感知不到的。然而,当您获取的键值大小是兆字节、100兆字节或者500兆字节会发生什么呢?哈希、排序、列表等数据结构会随着时间的推移而添加更多的数据进去,这样会生成一个数GB大小的数据集。而后用DEL命令去删除大Key时会发生什么呢?因为Redis是单线程操做的,处理这种请求时整个服务都处于等待中,须要等待该命令执行完成才能执行其它操做。同时,咱们考虑更复杂的一种场景,这些键中保存的数据可能已经包含数以千万个微小请求,所以应用程序或操做员可能没法真正了解删除这些数据须要花费多长时间。架构
理智会告诉咱们不要在拥有100万元素的排序集上运行以下这样的命令:性能
> ZRANGE some-zset 0 -1线程
可是,在上面的some-zset集合中执行DEL命令将花费和上面同样的时间-中间没有传输开销,可是它会一直去分配内存,并且您会一直卡死在CPU繁忙中。在使用UNLINK以前,您可能会结合SCAN命令采用非原子性的方法进行一些少许删除,去避免这种持续分配内存的噩梦。上面不管使用哪一种方式,都是让人没法接受的。翻译
您可能已经猜到了,就是使用UNLINK命令来替换DEL!从语法上讲,UNLINK与DEL相同,但UNLINK提供了更为理想的解决方案。首先,它将键值从整个键值空间中删除。而后,在另外一个线程中,它开始回收内存。从多线程的角度来看,这是一种安全的操做,由于它(在主线程中)从键空间中删除了该项,从而使Redis其它命令没法访问。
若是你有一个快速增加的键值-无论键值的大小如何,UNLINK都是O(1)操做(每一个键;在主线程中)。使用DEL删除一个大值可能须要几百毫秒或更长时间,而UNLINK将在不到一毫秒的时间内完成(包括网络往返)。固然,您的服务器仍将须要花一些时间在另外一个线程中从新分配该值的内存(其中的工做是O(N),其中N是已删除值的分配数),可是主线程的性能不会被另外一个线程中正在进行的操做严重影响到。
所以,您是否应该用UNLINK命令替换代码中的全部DEL命令?固然,在少数状况下,DEL正是您所须要的。这里我能够想到两点:
一、 在MULTI / EXEC或pipeline中,在添加和删除大值时DEL命令是一种理想选择。在这种状况下,UNLINK不会当即释放空间,而且在处理繁忙的状况下(若是内存已满),您可能会遇到麻烦。
二、 在更紧急的状况下,在无快速响应驱逐数据下您能够写入数据。
在没有极端内存限制的理想环境中,很难想到不使用UNLINK的状况。UNLINK将提供更一致的行为,整体上具备更好的性能,而且代码更改很是小(若是能够在客户端中重命名命令,则无需更改)。若是UNLINK适合您的应用程序,请就此将您的DEL更改成UNLINK,而后查看它的性能提升。
更多优质中间件技术资讯/原创/翻译文章/资料/干货,请关注“中间件小哥”公众号!