redis跟mysql性能比较
reids是基于内存的非关系性数据,而mysql的数据存在磁盘上,所以redis性能普遍高于mysql。但读写性能还受硬件、配置、数据大小、持久化策略、事务、是否集群、是否锁冲突等影响。普遍的认为单机redis一般支持10万级并发读写,mysql只到万级。对于同一热点数据(同一个key或同一行数据),redis单线程排队而mysql需要加锁阻塞,redis依旧支持万级qps而mysql只支持几百。
redis的基本命令
安装redis后,会同步安装一个客户端(reids-cli),客户端可以只接启动,然后在客户端中对redis数据库进行操作。
key操作:
# 查看key是否存在,返回1存在 0不存在 exists key # 删除key,支持多个 del key1 key2 # 设置过期时间(秒) expire key 60 # 设置过期时间(毫秒) pexpire key 60000 # 查看剩余过期秒数,-1永不过期,-2已删除 ttl key pttl key # 查看key类型 type key # 模糊匹配key,⚠️生产禁止线上用,会阻塞redis keys user* # 安全遍历key,游标迭代 scan 0 match user* count 100 # 重命名key rename old new # 持久化:把key从内存刷rdb,不用手动执行
string 字符串(最常用,缓存、计数、分布式锁)
# 设置 set k1 v1 # 设置+过期时间,原子 set k1 v1 ex 30 # 仅key不存在才设置(分布式锁nx) set k1 v1 nx ex 10 # 仅key存在才设置 set k1 v1 xx # 获取 get k1 # 批量 mget k1 k2 k3 mset k1 v1 k2 v2 # 数字自增,原子计数 incr num incrby num 10 decr num decrby num 5 # 追加字符串 append k1 "_suffix" # 获取字符串长度 strlen k1
hash 哈希(对象存储,user:{id})
# 左边插入(头) lpush list1 a b c # 右边插入(尾) rpush list1 d e # 左边弹出 lpop list1 # 右边弹出 rpop list1 # 阻塞弹出,没有数据就等待秒数,消息队列 blpop list1 10 brpop list1 10 # 指定下标取值,下标从0开始 lindex list1 0 # 区间获取 [start,end],-1代表最后一个 lrange list1 0 -1 # 裁剪list,只保留区间,用于限流队列 ltrim list1 0 99 # list长度 llen list1
set 集合,无序不重复(去重、交集并集)
# 添加 sadd set1 a b c a # 查询全部元素 smembers set1 # 判断是否存在 sismember set1 a # 删除元素 srem set1 b # 随机取元素 srandmember set1 2 # 随机弹出 spop set1 # 集合运算 sinter set1 set2 # 交集 sunion set1 set2 # 并集 sdiff set1 set2 # 差集 # 元素数量 scard set1
list 列表,双向链表(队列、栈)
# 左边插入(头) lpush list1 a b c # 右边插入(尾) rpush list1 d e # 左边弹出 lpop list1 # 右边弹出 rpop list1 # 阻塞弹出,没有数据就等待秒数,消息队列 blpop list1 10 brpop list1 10 # 指定下标取值,下标从0开始 lindex list1 0 # 区间获取 [start,end],-1代表最后一个 lrange list1 0 -1 # 裁剪list,只保留区间,用于限流队列 ltrim list1 0 99 # list长度 llen list1
zset 有序集合,score 权重(排行榜、延时队列)
# 添加 member 带score分数 zadd rank 100 user1 95 user2 98 user3 # 正序查询 [start end],从小到大 zrange rank 0 -1 # 带上分数 zrange rank 0 -1 withscores # 倒序,从大到小(排行榜) zrevrange rank 0 -1 withscores # 根据分数范围查询 zrangebyscore rank 90 100 # 删除成员 zrem rank user1 # 获取成员排名 zrank rank user2 zrevrank rank user2 # 分数自增 zincrby rank 5 user2 # zset元素总数 zcard rank # 指定分数区间数量 zcount rank 90 100
全局服务命令
# 选择数据库 0‑15,默认db0 select 1 # 清空当前库,危险 flushdb # 清空全部库,非常危险 flushall # 查看信息,cpu、内存、持久化、客户端 info info memory info stats # 查看当前连接客户端 client list # 持久化触发 bgsave # 后台生成rdb bgrewriteaof # aof重写 # 测试连通 ping
info命令查看持久化相关信息命令:info persistence
返回示例:
# persistence loading:0 rdb_changes_since_last_save:0 # 上次rdb之后改动key数量 rdb_bgsave_in_progress:0 rdb_last_save_time:1756234000 # 上次成功bgsave的时间戳 rdb_last_bgsave_status:ok # ok代表rdb成功 rdb_last_bgsave_time_sec:0 rdb_current_bgsave_time_sec:-1 rdb_enabled:1 # rdb功能是否开启(save配置是否存在) aof_enabled:0 # 0=aof关闭;1=aof开启 aof_rewrite_in_progress:0 aof_rewrite_scheduled:0 aof_last_rewrite_time_sec:-1 aof_current_rewrite_time_sec:-1 aof_last_bgrewrite_status:ok aof_last_write_status:ok aof_last_fsync:everysec # appendfsync策略:everysec / always / no
查看rdb持久化规则:config get save
127.0.0.1:6379> config get save 1) "save" 2) "900 1 300 10 60 10000" # 表示900s内改动key至少为1个 或300s内至少10个 或60s内至少10000个 则触发rdb持久化
若返回""则表示rdb 自动快照关闭,不会自动 bgsave;但你依然可以手动执行 bgsave 生成 rdb 文件。
redis bitmap(位图)
bitmap 不是独立数据类型,底层就是 string 字符串,按 bit(位)操作。一个 key 的字符串最多 512mb,对应 2^32 个 bit,约 42.9 亿位。
1 byte = 8 bit;100 万用户只需要~125kb 内存。
典型场景:用户签到、日活统计、是否访问、布尔标记、去重。
以统计用户签到为例,一个二进制位代表一个用户,每个日期存一个bitmap,统计当前日期已签到用户,已签到对应二进制位存1否则存0。若用户id已满足自增可直接使用用户id,若用户id非自增或偏移量较大(如id从1000000开始),可以考虑通过hashcode方式映射,但hash映射方式可能出现hash冲突导致统计异常。要想统计准确可以单独添加用户id和自增id的映射表,保证用id从1开始。
核心命令
1. setbit 设置位
# setbit key offset value # offset:位下标,从0开始;value只能 0 / 1 setbit sign:20260901 100 1
含义:把 offset=100 的位设置为 1,代表 id=100 用户今天签到。
offset 可以非常大,中间未设置的位默认是 0。
2. getbit 获取某一位
getbit sign:20260901 100
返回 0 / 1;判断用户 100 是否签到。
3. bitcount 统计为 1 的总数(统计签到人数)
# 统计整个key里面值为1的bit总数 bitcount sign:20260901 # 按字节范围统计,start、end 是**字节偏移**,不是bit! bitcount sign:20260901 0 100
⚠️注意:start end 单位是字节 (byte),不是 bit,不要搞错。
4. bitop 位图运算(与、或、异或、非)
做多天签到合并、多日活跃用户统计
# bitop op destkey key1 key2 ... # op: and(与) or(或) xor(异或) not(非) # or:任意一天签到过的用户,结果存入 sign:all bitop or sign:all sign:20260901 sign:20260902 sign:20260903 # and:三天全部都签到的用户 bitop and sign:all sign:20260901 sign:20260902 sign:20260903
bitop 会生成新 key,运算量大,大 bitmap 会阻塞 redis,线上谨慎。
5. bitpos 查找第一个 0/1 的位置
# 找第一个值为1的bit下标 bitpos sign:20260901 1 # 找第一个0 bitpos sign:20260901 0
hyperloglog
hyperloglog(简称 hll)是 redis 用来做基数统计的数据结构。
基数:集合中不重复元素的个数。例如集合
{1,2,2,3},基数 = 3。
核心特性
- 不存储原始数据,只存概率统计估算值;
- 空间极小:每个 hll key 只占用约 12kb 内存,最多统计 264 个元素;
- 结果是估算值,有误差:标准误差 0.81%;
- 适合大数据量去重计数,不适合要拿到原始元素的场景。
使用场景
- 统计页面 uv、每日独立访客(海量用户,不需要精确值,容忍小误差)
- 直播观看人数、活动去重访问量
- 多维度去重统计合并(
pfmerge合并多天、多渠道)
数据结构
整体结构 = hll 头(hllhdr) + 寄存器数据区,寄存器区有两种编码:稀疏编码 (sparse)、密集编码 (dense),redis 自动动态转换
struct hllhdr {
char magic[4]; // 魔术标记 "hyll",标识这是hll结构
uint8_t encoding; // 编码:0=dense密集,1=sparse稀疏
uint8_t notused[3]; // 保留3字节,预留扩展,恒为0
uint8_t card[8]; // 基数缓存,小端序;最高1bit标记缓存是否有效,低63bit存上次pfcount结果
uint8_t registers[]; // 柔性数组:寄存器数据区
};参数常量:
hll_p =14→ 桶数量 (m=214=16384) 个寄存器(桶)hll_bits=6:每个寄存器占 6bit,最大存 63,足够保存最多 50 位哈希的前导零最大值。
总大小:
(16384 ×6bit ÷8 =12288字节 =12kb)
加上头部 16 字节,完整对象约 12kb+
编码切换时机
- 初始化:默认稀疏编码
- 触发转密集:
- pfadd 导致某个寄存器值 > 32
- 稀疏编码自身占用超过阈值
底层原理简要
hyperloglog 基于伯努利试验 + 调和平均数估算基数:
- 对输入元素做 hash,得到 64bit 哈希值;
- 低 14 位用来选桶(redis hll 一共 16384 个桶,(214=16384));
- 剩余高位计算前导 0 的个数,每个桶记录该桶出现过最大前导 0 数量,(前导0越多,表明出现该数的概率越小,基数就越多。相同基数由于hash一样,选择的桶一样,前导0的个数也一样所以总的基数不会更新);
- 最后对 16384 个桶的值做调和平均,修正偏差,估算出总基数。
- 桶数量固定 16384,所以内存固定约 12kb;
- 误差来源是概率估算,标准误差 0.81%;
- redis hll 内部有稀疏、稠密两种编码:数据少时用稀疏编码占用更小,超过阈值自动转为稠密(12kb)。
使用示例
统计某个页面每天的访问次数
# 添加访问用户id pfadd uv:20260902 user1 user2 user3 user2 user1 # 统计今日uv(去重用户数) pfcount uv:20260902 # 合并两天uv到新key pfmerge uv:total uv:20260901 uv:20260902 pfcount uv:total
geo
redis 3.2 新增 geo,用于存储经纬度、计算距离、查询附近点位;底层没有新数据结构,基于 zset(有序集合)+ geohash 算法实现
典型业务场景
- lbs 业务:附近门店、附近商家、附近的人;
- 配送业务:骑手、车辆位置,计算两点距离;
- 简单地理围栏(小数据量)。
核心命令
1. geoadd 添加点位
# key 经度 纬度 member geoadd shop:geo 104.06 30.67 shop‑001 104.07 30.68 shop‑002
2. geopos 获取 member 的经纬度
geopos shop:geo shop‑001 shop‑002
3. geodist 计算两点球面距离
单位:m米 (默认)、km千米、mi英里、ft英尺
geodist shop:geo shop‑001 shop‑002 km
4. geohash 获取 geohash 字符串
geohash shop:geo shop‑001
到此这篇关于redis使用及数据结构实例详解的文章就介绍到这了,更多相关redis数据结构内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论