1、实验环境
硬件:4C/1G/20G
软件:Centos7/Docker19/Redis6
2、实验步骤
2.1 初始准备
$ swapoff -a # 临时关闭交换内存
$ echo never > /sys/kernel/mm/transparent_hugepage/enabled # 临时禁用 THP
$ echo never > /sys/kernel/mm/transparent_hugepage/defrag
$ mkdir -p /usr/local/redis && chmod 666 /usr/local/redis && cd /usr/local/redis
$ vi redis.conf # 添加如下内容
appendonly no # 不开户实例化,以提高性能
maxmemory 8M # 最大使用内存
maxmemory-policy allkeys-lru # 当used_memory达到maxmemory时的数据驱逐策略,删除最近最少用数据
protected-mode no # 开启其他机器访问
$ vi import.lua # 批量添加数据Lua脚本
local count = tonumber(ARGV[1])
local expire_time = tonumber(ARGV[2]) -- 过期时间(秒)
redis.call("SELECT", 0) -- 确保选择数据库 0
for i = 1, count do
local key = "key" .. i
local value = "value" .. i
redis.call("SET", key, value)
redis.call("EXPIRE", key, expire_time)
if i % 10000 == 0 then
redis.log(redis.LOG_NOTICE, "Inserted and set expiration for " .. i .. " keys")
end
end
2.2 运行docker
$ docker run --name redis --restart=always -d \
-p 6379:6379 \
-v /usr/local/redis/redis.conf:/usr/local/etc/redis/redis.conf \
-v /usr/local/redis/import.lua:/data/import.lua \
-v /usr/local/redis/data:/data redis:6.0.8 \
redis-server /usr/local/etc/redis/redis.conf
$ docker ps
\CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d007736e7bdd redis:6.0.8 "docker-entrypoint.s…" 16 seconds ago Up 15 seconds 0.0.0.0:6379->6379/tcp redis
2.3 实验1:设置最大内存与数据过期时间
使用top命令 ,看一下当前内存占用情况
再开一个SSH窗口,检查一下配置参数是否生效
$ docker exec -it redis /bin/bash
root@d007736e7bdd:/data# redis-cli config get maxmemory
1) "maxmemory"
2) "8000000"
root@d007736e7bdd:/data# redis-cli config get maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
检查一下初始内存分配情况
root@d007736e7bdd:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:844.73K
used_memory_rss_human:4.26M
used_memory_peak_human:844.73K
used_memory_lua_human:37.00K
used_memory_scripts_human:0B
参数说明:
used_memory:Redis 分配器分配的内存总量
used_memory_rss:进程从操作系统分配的内存总量
used_memory_peak:Redis 分配器分配的内存峰值
写20万数据,设置10分钟过期
root@d007736e7bdd:/data# redis-cli info keyspace # 当前数据库为空
# Keyspace
root@d007736e7bdd:/data# redis-cli --eval import.lua , 200000 600
(nil)
root@a3222c70b966:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:7.63M # 应该内存已经用尽了
used_memory_rss_human:30.89M # 实际占用内存已经远超8M了
used_memory_peak_human:215.92M
used_memory_lua_human:74.00K
used_memory_scripts_human:552B
root@a3222c70b966:/data# redis-cli info keyspace
# Keyspace
db0:keys=30625,expires=30625,avg_ttl=538500 # 已经触发清除策略,只剩下3万条
过10分钟后再检查
root@a3222c70b966:/data# redis-cli info keyspace # 数据已完全过期
# Keyspace
root@a3222c70b966:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:846.61K
used_memory_rss_human:9.52M # 实际占用内存已经下降了
used_memory_peak_human:215.92M
used_memory_lua_human:74.00K
used_memory_scripts_human:552B
从下图可以看到,虽然数据都被清理了,但实际占用内存还是增长了
2.4 实验2:设置最大内存,不设置数据过期时间
$ docker stop redis && docker rm redis
redis
redis
$ rm -f import.lua
$ vi import.lua
for i = 1, count do
redis.call("SET", "key" .. i, "value" .. i)
end
$ docker run --name redis ........ (参考前面)
回到第2个窗口
$ docker exec -it redis /bin/bash
root@0fce85341f7e:/data# redis-cli --eval import.lua , 200000
(nil)
root@0fce85341f7e:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:7.63M
used_memory_rss_human:20.59M # 实际占用内存比有过期设置的要少
used_memory_peak_human:16.55M
used_memory_lua_human:60.00K
used_memory_scripts_human:216B
root@0fce85341f7e:/data# redis-cli info keyspace
# Keyspace
db0:keys=70001,expires=0,avg_ttl=0 # 剩下7万条
因为没有设置过期时间,这里将数据库手动清空
root@0fce85341f7e:/data# redis-cli FLUSHALL
OK
root@0fce85341f7e:/data# redis-cli info keyspace
# Keyspace
root@0fce85341f7e:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:845.52K # used_memory 恢复了
used_memory_rss_human:7.55M # 系统分配内存也降下来了
used_memory_peak_human:16.55M
used_memory_lua_human:60.00K
used_memory_scripts_human:216B
2.5 实验3:不设置最大内存与数据过期时间
$ docker stop redis && docker rm redis
redis
redis
$ sed -i "s/max/#max/" redis.conf
[root@localhost redis]# cat redis.conf
appendonly no
#maxmemory 8M
#maxmemory-policy allkeys-lru
protected-mode no
$ docker run --name redis ........ (参考前面)
再到第二个窗口
$ docker exec -it redis /bin/bash
root@8e6f924f76df:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:844.73K
used_memory_rss_human:4.25M
used_memory_peak_human:844.73K
used_memory_lua_human:37.00K
used_memory_scripts_human:0B
root@8e6f924f76df:/data# redis-cli --eval import.lua , 200000 # 写20万条
(nil)
root@8e6f924f76df:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:16.55M
used_memory_rss_human:21.59M
used_memory_peak_human:16.55M
used_memory_lua_human:60.00K
used_memory_scripts_human:216B
root@8e6f924f76df:/data# redis-cli info keyspace
# Keyspace
db0:keys=200000,expires=0,avg_ttl=0 # 全部定入
直接写200万条试下
root@8e6f924f76df:/data# redis-cli --eval import.lua , 2000000
(nil)
root@8e6f924f76df:/data# redis-cli info keyspace
# Keyspace
db0:keys=2000000,expires=0,avg_ttl=0
root@8e6f924f76df:/data# redis-cli info memory | grep used_memory|grep human
used_memory_human:154.15M
used_memory_rss_human:161.43M
used_memory_peak_human:154.15M
used_memory_lua_human:58.00K
used_memory_scripts_human:216B
写2000万条
[root@localhost ~]# docker ps # 可以看到docker已经重启了( Up 7 seconds )
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8e6f924f76df redis:6.0.8 "docker-entrypoint.s…" 8 minutes ago Up 7 seconds 0.0.0.0:6379->6379/tcp redis
3、实验结论
由上述实验可以看出:
- 不设置maxmemory时可以最大保证数据的完整性,但有可能导致docker程序因内存占用过大而被系统重置;
- 在已经设置了maxmemory的情况下,不主动配置数据过期时间可以较完整地保存数据,若配置了配置数据过期时间则可以减少内存开销;
- maxmemory并不等于redis占用系统实际内存的值,当有大批量数据写入时,后者的值有可能比前者大得多,因此这个值要合理设置。