Why Redis 4.0?

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
简介: 社区最新GA版本Redis 4.0推出已近一年,阿里云数据库Redis 4.0版也上线近半年,之前关于Redis 4.0的系列文章从源码实现来分析这些新功能,本文旨在从用户角度出发,让Redis的用户能够快速了解并使用Redis 4.0带来的福利。

前言

Redis作为时下最火爆的NoSQL数据库以性能强悍、数据结构丰富著称,同时其成长的脚步也从未停止,自诞生伊始已经历多次蜕变不断推出新功能。

社区最新GA版本Redis 4.0推出已近一年,阿里云数据库Redis 4.0版也上线近半年,之前关于Redis 4.0的系列文章从源码实现来分析这些新功能,本文旨在从用户角度出发,让Redis的用户能够快速了解并使用Redis 4.0带来的福利。

Lazyfree

大key删除的问题想必很多用户都遇到过,Redis除string外还支持list、set、hash和sorted set等复杂数据结构,这些数据结构丰富了Redis的用法,但是如果使用不当造成单key体积过大的话就会引起一些问题。

举个简单的例子,假如某社交网站有一个大V,有上百万的粉丝,我们可以用set集合类型的数据结构来存储他的粉丝ID,存储粉丝集合的key叫做funs好了,我们来看下粉丝数:

127.0.0.1:6379> SCARD funs
(integer) 6320505

的确是大V,有600多万的粉丝,但是很不幸的有一天这个大V注销了,这时就要删除他的信息,我们用DEL命令来删除这个key:

127.0.0.1:6379> DEL funs
(integer) 1
(3.11s)
127.0.0.1:6379> slowlog get
1) 1) (integer) 4
   2) (integer) 1528169923
   3) (integer) 3104812
   4) 1) "DEL"
      2) "funs"
   5) "127.0.0.1:48398"
   6) ""
  • 小插曲:Redis 4.0扩展了slowlog的返回结果,展示了产生慢日志的客户端IP:PORT以便追本溯源。

可以看到删除这个动作居然耗时3秒多,也就意味着这3秒内Redis无法执行其他命令,这对于线上业务来讲是有伤害的,那么如何避免删除大key时的阻塞问题呢?Redis 4.0推出了Lazyfree这一功能,使用UNLINK命令来删除大key,主线程只负责把key从数据库中"摘除",真正的释放动作放在了BIO后台线程去做,我们来看下效果:

127.0.0.1:6379> UNLINK funs
(integer) 1
(3.11s)
127.0.0.1:6379> slowlog get
(empty list or set)

可以看到UNLINK执行很快没有产生slowlog。

Lazyfree一共有3个命令:

  1. UNLINK:异步删除key
  2. FLUSHDB ASYNC:异步清空当前DB
  3. FLUSHALL ASYNC:异步清空所有DB

以及4个配置项:

  1. lazyfree-lazy-expire:异步删除过期key
  2. lazyfree-lazy-eviction:异步淘汰key
  3. lazyfree-lazy-server-del:隐式删除时采取异步删除,比如rename a b,若b存在则需删除b
  4. slave-lazy-flush:全量同步时,slave异步清空所有DB

对于源码实现有兴趣的读者可以阅读《Redis 4.0之Lazyfree》

Lua脚本支持随机操作

Redis内嵌了Lua环境来支持用户扩展功能,但是出于数据一致性考虑,要求脚本必须是纯函数的形式,也就是说对于一段Lua脚本给定相同的参数,重复执行其结果都是相同的。

为什么要有这个限制呢?原因是Redis不仅仅是单机版的内存数据库,它还支持主从复制和持久化,执行过的Lua脚本会复制给slave以及持久化到磁盘,如果重复执行得到结果不同,那么就会出现内存、磁盘、slave之间的数据不一致,在failover或者重启之后造成数据错乱影响业务。

还是以具体例子来看,假设有这么一段Lua脚本,目的很简单就是想记录下当前时间:

local now = redis.call('time')[1]

redis.call('set','now',now)

return redis.call('get','now')

这里使用了Redis的TIME命令来获取时间戳,然后存储到名为now的key中,但是其执行时会报错:

$redis-cli --eval escript
(error) ERR Error running script (call to f_cfba5ec6a699dad183456f19d1099d8dabfdb80c): 
@user_script:3: @user_script: 3: Write commands not allowed after non deterministic commands. 
Call redis.replicate_commands() at the start of your script in order to switch to single commands replication mode.

错误提示也很明显,如果执行过非确定性命令(也就是TIME,因为时间是随机的),Redis就不允许执行写命令,以此来保证数据一致性。那如何才能实现随机写入呢?刚才的错误提示也给出了答案,使用redis.replicate_commands(),在执行redis.replicate_commands()之后,Redis就不再是把整个Lua脚本同步给slave和持久化,而是把脚本中调用Redis的写命令直接去做复制,那么slave和持久化也可以得到确定的结果。

脚本修改如下:

redis.replicate_commands()

local now = redis.call('time')[1]

redis.call('set','now',now)

return redis.call('get','now')

再执行就可以实现随机写入了:

$redis-cli --eval escript
"1528191578"

$redis-cli --eval escript
"1528191804"

基于LFU的热点key发现机制

LFU是Redis 4.0新增的一类内存逐出策略,提供了更精确的内存淘汰算法,其本质是记录了一段时间内key的访问频率,同时也带来了额外的福利就是热点key的发现。

LFU简单来讲就是用0-255来表示key的访问频率,值越大说明访问频率越高,并且这里对频率的计数采用的是基于对数的概率增长,LFU为255可以代表100W次的访问,关于LFU的实现有兴趣的读者可以参考《Redis 4.0之基于LFU的热点key发现机制》

使用OBJECT FREQ命令即可获取指定key的访问频率,不过需要首先把内存逐出策略设置为allkeys-lfu或者volatile-lfu:

127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"
127.0.0.1:6379> object freq counter:000000006889
(error) ERR An LFU maxmemory policy is not selected, access frequency not tracked. Please note that when switching between policies at runtime LRU and LFU data will take some time to adjust.

127.0.0.1:6379> config set maxmemory-policy allkeys-lfu
OK
127.0.0.1:6379> object freq counter:000000006889
(integer) 3

使用scan命令遍历所有key,再通过OBJECT FREQ获取访问频率并排序,即可得到热点key。为了方便用户使用,Redis自带的客户端redis-cli也提供了热点key发现功能,执行redis-cli时加上--hotkeys选项即可,示例如下:

$./redis-cli --hotkeys

# Scanning the entire keyspace to find hot keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).

[00.00%] Hot key 'counter:000000000002' found so far with counter 87
[00.00%] Hot key 'key:000000000001' found so far with counter 254
[00.00%] Hot key 'mylist' found so far with counter 107
[00.00%] Hot key 'key:000000000000' found so far with counter 254
[45.45%] Hot key 'counter:000000000001' found so far with counter 87
[45.45%] Hot key 'key:000000000002' found so far with counter 254
[45.45%] Hot key 'myset' found so far with counter 64
[45.45%] Hot key 'counter:000000000000' found so far with counter 93

-------- summary -------

Sampled 22 keys in the keyspace!
hot key found with counter: 254    keyname: key:000000000001
hot key found with counter: 254    keyname: key:000000000000
hot key found with counter: 254    keyname: key:000000000002
hot key found with counter: 107    keyname: mylist
hot key found with counter: 93    keyname: counter:000000000000
hot key found with counter: 87    keyname: counter:000000000002
hot key found with counter: 87    keyname: counter:000000000001
hot key found with counter: 64    keyname: myset

MEMORY内存分析命令

分析内存可以优化Redis的使用方式,全新的MEMORY命令可以帮助用户来实现这一操作。

MEMORY命令一共有5个子命令,可以通过MEMORY HELP来查看:

127.0.0.1:6379> memory help
1) "MEMORY DOCTOR                        - Outputs memory problems report"
2) "MEMORY USAGE <key> [SAMPLES <count>] - Estimate memory usage of key"
3) "MEMORY STATS                         - Show memory usage details"
4) "MEMORY PURGE                         - Ask the allocator to release memory"
5) "MEMORY MALLOC-STATS                  - Show allocator internal stats"

关于各个子命令的详细使用方式可以参考《Redis 4.0之MEMORY命令详解》

开始体验Redis 4.0

作者简介

赵钊,花名仲肥,阿里云技术专家,专注于阿里云数据库Redis版的开发工作,活跃于Redis开源社区,致力让开发者使用最好的云数据库服务。

欢迎加入:阿里云-技术专家-KVstore

目录
相关文章
|
存储 数据库 虚拟化
无缝过渡:企业级服务器迁移的策略与最佳实践
【10月更文挑战第4天】随着企业数字化转型的加速,服务器迁移成为企业IT基础设施升级的重要环节。本文从架构与规划的视角,探讨了企业级服务器迁移的策略与最佳实践,旨在帮助企业实现无缝过渡,降低迁移风险,提高迁移效率。
927 4
|
关系型数据库 分布式数据库 数据库
【阿里云云原生专栏】云原生时代的数据库选型:阿里云RDS与PolarDB对比分析
【5月更文挑战第24天】阿里云提供RDS和PolarDB两种数据库服务。RDS是高性能的在线关系型数据库,支持MySQL等引擎,适合中小规模需求;而PolarDB是分布式数据库,具备高扩展性和性能,适用于大规模数据和高并发场景。RDS与PolarDB在架构、性能、弹性伸缩、成本等方面存在差异,开发者应根据具体需求选择。示例代码展示了如何通过CLI创建RDS和PolarDB实例。
1525 0
|
计算机视觉
【YOLOv8改进】动态蛇形卷积(Dynamic Snake Convolution)用于管状结构分割任务
YOLO目标检测专栏介绍了DSCNet,它针对血管和道路等管状结构的分割任务进行优化。DSCNet采用动态蛇形卷积(DSConv)聚焦细长结构,多视角融合策略增强全局形态理解,且通过持久同调的连续性约束损失改善拓扑连续性。DSConv在2D和3D数据集上表现优于传统方法,实现更高精度和连续性。该技术已应用于yolov8,提升对管状结构的检测效果。
|
JavaScript Java 测试技术
基于SpringBoot+Vue的河北任丘非物质文化遗产数字化传承的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的河北任丘非物质文化遗产数字化传承的详细设计和实现(源码+lw+部署文档+讲解等)
211 0
|
Linux
Linux定时任务:详解crontab与crond
Linux定时任务:详解crontab与crond
461 0
|
SQL 分布式计算 大数据
MaxCompute操作报错合集之执行sql时,出现Cannot read properties of undefined (reading 'start')错误提示,该怎么办
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
576 0
|
Unix Perl
`sed`命令替换文本中的单词
`sed`命令替换文本中的单词
363 3
|
Oracle 关系型数据库 Java
Mybatis JdbcType与Oracle、MySql数据类型对应列表
Mybatis JdbcType与Oracle、MySql数据类型对应列表
502 0
|
Shell 开发工具 git
TortoiseGit安装教程
TortoiseGit安装教程
412 0
|
数据挖掘
ENVI:分类后处理_小斑块去除_Majority/Minority处理、聚类处理、过滤处理等
ENVI:分类后处理_小斑块去除_Majority/Minority处理、聚类处理、过滤处理等
1542 0