ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Docker部署Redis从入门到实战:容器化部署、持久化配置与高可用集群

Docker部署Redis从入门到实战:容器化部署、持久化配置与高可用集群 别的不说先问一句你是不是也在Windows或者Mac上直接装过Redis下载Windows版本来回找补丁环境变量配了半天版本搞乱了还得卸载重来碰到换台电脑又得重新折腾一遍。我老早以前也这么干直到把Redis放进Docker容器里才发现这玩意儿能省下太多破事。这篇文章不扯什么云原生高大上的概念就聊最实在的事用Docker把Redis跑起来。通过这篇文章你会搞清楚为什么容器化部署Redis是明智的选择并且一步步完成从拉取镜像、配置持久化、挂载配置文件、设置密码到解决常见问题和扩展集群的完整流程。适合刚接触Docker的人也适合有一定经验但被各种细节坑过的同学照着抄作业就行。1. 为什么我推荐把Redis放进DockerRedis这东西本身不算难装官网甚至在没法直接安装时有Windows移植版本但问题恰恰出现在“你的机器环境”和“你需要的Redis版本”之间的各种组合关系上。很多团队里一人开发用Windows后期上线是Ubuntu中间还夹着macOS的同事各人电脑上装的Redis版本还不统一。用Docker后这一切都有了一个确定性的答案镜像是什么版本容器里的Redis就是什么版本不管你在哪台机器上跑行为完全一致。这意味着你在本地开发环境测试通过的缓存逻辑和Lua脚本上了服务器不会被“版本差异”摆一道。1.1 版本隔离和快速切换在宿主机上全局安装Redis版本是固定的想测一下Redis 6和Redis 7在高版本数据结构或命令上的区别你得卸载重装或者折腾多版本共存。这种操作不只是麻烦还有可能污染系统环境。在Docker里换个容器就是换一个版本拉取对应版本的镜像运行即可用完删掉不会在你的电脑上留垃圾。比如我本地同时跑过Redis 6.2和Redis 7.0做对比命令就两行docker run -d --name redis-6 -p 6379:6379 redis:6.2 docker run -d --name redis-7 -p 6380:6379 redis:7.0瞬间起来两个实例端口还不冲突测试完哪个不要了就删哪个。这体验比在机器上装两个原生Redis清爽太多。1.2 不存在“能否安装成功”的焦虑Windows用户最清楚我说的意思——Redis官方压根不维护Windows版本所谓的Windows版只是微软或者其他个人开发者为了内部测试搞的。碰到生产环境或者特定版本要求这些非官方版本就开始出幺蛾子。而官方Docker镜像在Docker Hub上一直有更新无论你用什么宿主机系统只要装了Docker就能用上官方维护的Redis。再加上如果你用Docker Compose以后不光redismysql、nginx、后端服务都能一整套编排一条命令全部启动。虽然这篇文章只围绕Redis但容器化的思路一旦打通受益的是整个技术栈。2. 安装前的准备Docker环境与镜像源所有容器化操作的前提是先有Docker环境。对于Windows和macOS最简单的方式是安装Docker Desktop它自带图形界面和命令行工具适合绝大多数开发场景。Linux用户可以选择安装Docker Engine然后通过命令行管理。2.1 Windows / macOS 安装 Docker Desktop这件事本身不难但有一个坑必须提前讲Docker Desktop在Windows上依赖WSL2Windows Subsystem for Linux很多人安装到最后一步发现“Virtualization support not detected”之类的报错其实就是两个原因一是BIOS里的虚拟化没开二是根本没启用WSL。安装前先去任务管理器-性能-CPU看一下“虚拟化”是否显示“已启用”。如果没启用需要重启进BIOS把Intel VT-x或AMD-V打开。启用WSL的在PowerShell管理员模式下执行wsl --install这里提醒一下执行完大概率会要求重启所以最好在装Docker Desktop之前先把WSL2弄好。然后下载Docker Desktop安装包双击装完打开Docker Desktop会自动启动引擎。等到右下角小鲸鱼图标不再转圈说明Docker环境OK了。2.2 Linux 命令行安装Linux服务器上没有图形界面直接用包管理器。以Ubuntu/Debian系为例常规操作是更新apt索引、安装依赖、添加官方仓库然后再安装。不过很多人会图省事直接用apt install docker.ioUbuntu自带的这个包版本可能偏旧但作为新手完全够用。建议的方式是通过官方脚本一键安装简单但有些人不放心所以这里推荐一下更透明的仓库安装法sudo apt update sudo apt install ca-certificates curl gnupg lsb-release sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin安装完成后意味着Docker命令需要sudo权限才能执行。如果想当前用户免sudo直接敲docker命令把用户加入docker用户组然后重新登录终端sudo usermod -aG docker $USER2.3 镜像加速配置这是国内用户绕不开的问题。如果直接用默认源拉取redis镜像速度随缘运气不好能卡到怀疑人生。热搜词里就有“docker镜像下载慢”和“docker镜像源”这点我深有体会。解决办法就是给Docker配置镜像加速器。Docker Desktop在设置里能找到Docker Engine选项Linux用户在/etc/docker/daemon.json里写入如下格式的内容{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.mirrors.ustc.edu.cn ] }注意加速器地址不定期变动建议以当前可用的为准。改完配置必须重启Docker Desktop或执行sudo systemctl restart docker。配置好之后拉取Redis官方镜像docker pull redis:7.03. 最基础的Redis容器启动与参数拆解很多新手第一次敲docker run命令看到一堆参数头皮发麻。别慌核心参数就那么几个搞懂含义以后就能举一反三。3.1 最简单的一行命令docker run -d --name redis-test -p 6379:6379 redis:7.0这行命令做了什么我拆开讲docker run创建并启动一个新容器。-ddetach模式容器在后台运行不会霸占终端。--name redis-test给容器起个名字。以后删容器、看日志、进容器都靠这个名字引用比记一串随机ID省心太多。-p 6379:6379端口映射宿主机6379端口映射到容器内6379端口。Redis容器本身监听它内部的6379端口宿主机上的应用要访问Redis就得通过这个映射。左边是宿主机端口右边是容器内部端口。redis:7.0指定用哪个镜像启动容器。执行完成后测一下是否成功开启docker ps能看到redis-test在列表里就说明Redis容器已经在跑了。再用客户端测试连接docker exec -it redis-test redis-cli ping返回PONG一切正常。3.2 容器间通信与host网络模式这里补充一个容易被忽略的点如果宿主机上直接跑后端代码通过-p映射没问题。但如果后端应用也容器化了再通过宿主机端口访问Redis就多了一层无谓的跳转虽然能用但性能上有点浪费。更合理的做法是让应用容器和Redis容器都加入同一个自定义网络应用直接用容器名访问Redis。创建网络和指定网络的命令如下docker network create app-net docker run -d --name redis --network app-net -p 6379:6379 redis:7.0后续启动应用容器时也带上--network app-net应用里Redis的host直接填redis而不是127.0.0.1因为Docker内置的DNS会把容器名解析成对应IP。这也是生产环境里推荐的部署方式之一。还有一个更极端的做法是--network host让容器直接使用宿主机网络此时不需要-p端口映射Redis监听的就是宿主机的6379端口。这种方式性能损耗最小但隔离性也变差了容易和宿主机上其他服务冲突。日常开发用桥接网络就够了生产环境如果追求极高性能可以再考虑host网络。3.3 给Redis设置密码Redis刚启动时默认没有密码如果直接暴露在公网或内网里就会被扫描工具盯上分分钟被人写入crontab挖矿木马。与其事后补救不如从第一步就加固。设置密码有两条路第一种启动时用命令参数传入docker run -d --name redis-auth -p 6379:6379 redis:7.0 --requirepass yourpassword注意在redis:7.0镜像后面跟的任何内容都会被当作Redis服务器参数传递进去。但这种方式有个问题密码会出现在docker inspect和shell历史里多人协作环境下容易泄露。第二种也是我更推荐的方式使用Redis配置文件也就是把自定义配置写进一个本地文件然后挂载进容器。这样密码、持久化策略、日志级别等都在同一个文件里管理新增配置项一目了然也符合“基础设施即代码”的理念。4. 配置文件挂载与数据持久化实战很多人用Docker装Redis只顾着起个容器结果容器删了数据全没了后悔得直拍大腿。这不是Redis的锅是没做持久化和配置管理。4.1 持久化原理与必要性先说结论Redis默认开启RDB快照但触发条件比较宽松如果Redis异常退出或者容器被强制删除最近几分钟的数据可能没来得及生成快照于是丢数据。要想数据不丢还得开启AOFAppend Only FileRedis会把每个写命令追加到AOF文件。重启时Redis会重新执行AOF文件里的所有命令把数据恢复回来。开启AOF的方法就是把配置写进redis.conf。但问题在于容器里的Redis使用的是镜像自带的默认配置就算你在容器里执行config set appendonly yes重启容器那个配置也没了。所以正确做法是把redis.conf放到宿主机上然后挂载到容器里让Redis启动时读取这个文件。4.2 准备宿主机的redis.conf从零开始写一份完整的redis.conf对新手不友好最靠谱的方式是从redis官方仓库下载对应版本的配置文件放到宿主机指定目录里。比如我习惯把所有配置文件放在/mydata/redis/conf/redis.conf运行以下命令mkdir -p /mydata/redis/conf cd /mydata/redis/conf curl -o redis.conf https://raw.githubusercontent.com/redis/redis/7.0/redis.conf文件下载下来后至少要修改这几个关键项# 开启AOF持久化 appendonly yes appendfilename appendonly.aof # RDB快照文件名 dbfilename dump.rdb # 工作目录AOF和RDB文件都会写到这里 dir /data # 密码 requirepass yourpassword # 允许所有IP访问容器环境下如果不设置会只监听127.0.0.1 bind 0.0.0.0 # 保护模式需要关闭否则有密码也连不上 protected-mode no这里最容易被忽略的是bind和protected-mode。Redis 7.0的默认配置里bind的是127.0.0.1意思只有本机能连。虽然容器里跑着Redis但如果不改配置宿主机的应用通过映射端口访问时会被拒之门外。修改完保存然后用挂载配置文件的方式启动Redisdocker run -d \ --name redis \ -p 6379:6379 \ -v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \ -v /mydata/redis/data:/data \ redis:7.0 redis-server /etc/redis/redis.conf这里我解释一下-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf把宿主机上的配置文件挂载到容器内相当于覆盖容器内的默认配置。-v /mydata/redis/data:/data把宿主机上的数据目录挂载到容器内的/data目录Redis的RDB和AOF文件都会写在这里容器删了文件还在。redis-server /etc/redis/redis.conf告诉容器里的Redis启动时使用这个配置文件。重点来了所有数据持久化文件的位置都要和配置里的dir路径对应上。如果配置里dir是/data就必须给/data挂载数据卷。两者不匹配Redis虽然能跑起来但数据文件写在了容器可写层容器一删数据照样没。4.3 验证持久化是否生效启动后先写几条测试数据docker exec -it redis redis-cli -a yourpassword 127.0.0.1:6379 set name docker-redis 127.0.0.1:6379 save OK然后强制重启容器再检查数据是否还在docker restart redis docker exec -it redis redis-cli -a yourpassword get name如果返回docker-redis说明RDB恢复生效了。再测试AOF随意再写几个key不手动save直接重启用docker stop和docker startAOF会把追加的命令回放一遍数据一样不丢。这两个持久化机制都开着的场景下如果把容器干脆删了再重新建一个还是用同一套数据卷挂载数据依然在这才是容器化部署Redis最爽的地方重装Redis跟玩似的数据毫发无伤。5. 容器运维与日常管理的核心命令容器化部署的运维方式和原生方式不完全一样。原生Redis你可能只关心redis-cli和pid文件Docker里多了不少容器层级的操作这些命令必须烂熟于心。5.1 查看日志与容器状态Redis出问题时第一步是看日志Docker查看容器日志的命令docker logs redis只查看最近100行并且持续跟踪输出加-f参数docker logs -f --tail 100 redis这个命令还挺常用特别是后面配置了哨兵或集群看选举日志、切换日志都得靠它。日志里如果出现“Cant handle RDB format version”说明版本不兼容应该检查一下当前Redis镜像版本和之前的rdb文件版本。5.2 进入容器与执行Redis命令除了通过redis-cli从外部连有时需要进入容器内部查看一些进程信息。Docker的exec系列命令就是干这个的docker exec -it redis bash进入容器后你面对的是一个极其精简的Linux环境里面只有Redis运行时需要的工具。可以直接执行redis-cli也可以查看容器内的系统状态。不过我的建议是日常只用redis-cli不用没事进容器翻文件毕竟是容器不是你的常规服务器。5.3 资源限制与端口防冲突容器这东西有个特点默认情况下它只限制你为它配置的资源。如果一个Redis容器内存爆炸理论上可能影响到同主机的其他服务。所以生产环境部署一定要加内存限制docker run -d --name redis \ -p 6379:6379 \ -m 512m \ -v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \ -v /mydata/redis/data:/data \ redis:7.0 redis-server /etc/redis/redis.conf-m参数是内存限额超过这个值后容器会被内核杀进程这就是Docker的OOM机制。给Redis设置512m或1g取决于你的数据量预估别拍脑袋随便填结合maxmemory配置一起用更稳妥。另外端口防冲突也是老生常谈。启动容器时报“port is already allocated”99%是宿主机的6379端口被占了。查看占用端口的进程netstat -tlnp | grep 6379或者ps查看有没有之前残留的redis进程。在Windows上也可以执行netstat -ano | findstr 6379。如果确实端口冲突可以换映射端口比如-p 6380:6379这代表宿主机6380端口映射到容器内6379外部应用连接时就用6380。5.4 容器生命周期管理最后再整理一下最常用的生命周期命令不分场景直接背下来docker ps查看运行中的容器加-a查看所有容器含已退出。docker start redis启动已存在的容器。docker stop redis优雅停止容器会发出SIGTERM信号给Redis。docker restart redis重启容器相当于stop再start。docker rm redis删除容器需要先stop。有三个特别注意的地方第一停止容器不等于删除容器。如果只是stop容器还在数据卷挂载也还在启动后数据还在。如果rm删了容器没了但挂载到宿主机目录里的数据文件还在重新run一个挂载相同目录的容器就能找回数据。第二不要在容器运行的时候直接rmDocker会拒绝必须先stop。第三如果想彻底把数据也删了除了rm容器还要把宿主机上挂载的数据目录也删了。6. 可视化客户端连接与Spring Boot集成整个容器部署在服务器上然后本地开发时怎么连绝大多数人还是会选个可视化客户端工具来观察数据、debug问题。这节把连接方式和常见的框架集成坑一起讲了。6.1 Redis Desktop Manager类的工具连接很多开发者的第一反应是Redis Desktop ManagerRDM不过它现在已经不太活跃了。社区里很多人转向了Another Redis Desktop Manager简称ARDM界面清爽功能免费跨平台。这些工具本质上做的事情都是一样的通过TCP连接到Redis实例登录验证密码然后可视化查看key、value和TTL。连接配置非常简单填三个信息Redis所在机器的IP或主机名、端口、密码。唯一要注意的是如果Redis容器通过-bind 0.0.0.0监听且密码存在从外部连接没问题但如果配置错了连不上的现象会非常模糊客户端一直转圈但从服务器本地又能连上。这种时候不要急着怀疑工具检查两件事服务器的防火墙或安全组有没有放行6379端口。Redis配置里有没有设bind和protected-mode有密码的情况下如果再把protected-mode设成yes外部连接会直接拒绝。6.2 Java / Spring Boot 里连接Redis容器的坑Java项目里最常用的方式是Spring Data Redis也就是RedisTemplate。搜索引擎热搜词有一条“java中redis使用redistemplate的increment()报错不是integer or out of range”这其实跟Docker本身没直接关系但我在实际使用中确实被这个错误卡过而且最终是在容器里排查才发现的。这个报错的起因是Redis的increment命令要求value是整数如果你之前往同一个key里set了一个字符串“abc”或者一个很大的浮点数再调用increment时Redis就报“ERR value is not an integer or out of range”。Spring里的Increment()调用时会把这层错误包装出来导致很多人以为Redis配置错了。检查办法很简单进Redis容器里看一下这个key的value类型docker exec -it redis redis-cli -a yourpassword type keyname返回string、hash或者非int的value基本上就是数据本身的问题。只要删掉旧key或者改换key名increment就能正常工作。更大的坑在于RedisTemplate的序列化机制。默认的JdkSerializationRedisSerializer会把key序列化成二进制乱码在Redis Desktop Manager里看起来就像一堆\xAC\xED开头的乱码非常难排查。更严重的是不同服务如果序列化方式不统一会互相读不到数据。我建议在项目里统一配置StringRedisSerializerkey用字符串value用JSON序列化器这样至少可视化工具里能看到明文。Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.afterPropertiesSet(); return template; }至于yml里Redis连接池怎么配这里不展开细说但核心的host、port、password千万别填错。尤其是容器里Redis的密码通过配置文件挂载设置的Spring连接时password那一项必须和容器内实际生效的密码一致而不是你以为的密码。7. 从单机到高可用主从复制、哨兵与Docker Compose只跑一个Redis单机容器对开发环境够用了但生产环境一定会面临单点问题。容器化让主从搭建变得异常简单我建议所有服务端开发掌握主从复制原理并且会搭哨兵。7.1 Docker下搭建Redis主从复制传统方式搭主从要准备多台服务器但在Docker里只需要在一台宿主机上把多个Redis容器跑起来配置主从关系即可。假设现在有一个主Redis在6379端口起一个新容器作为从节点端口6380执行命令docker run -d --name redis-slave1 \ -p 6380:6379 \ -v /mydata/redis-slave1/conf/redis.conf:/etc/redis/redis.conf \ -v /mydata/redis-slave1/data:/data \ redis:7.0 redis-server /etc/redis/redis.conf --replicaof 主节点IP 6379也可以修改从节点的redis.conf加上replicaof行效果一样。然后写一个主数据从节点会自动同步。在主节点验证一下docker exec -it redis redis-cli -a yourpassword info replication输出里能看到connected_slaves:1从节点ID和端口都会显示。从节点上默认只读不能写这是Redis复制的硬性约束不需要感到意外。7.2 哨兵容器与故障转移主从复制解决了读扩展的问题但主节点挂掉后整个集群还是不可用。因此引入了哨兵Sentinel。哨兵负责监控主节点的健康状态发现主节点挂了就从从节点中选举一个新主节点实现自动故障转移。用Docker部署哨兵更多依赖配置文件。哨兵配置文件sentinel.conf里至少要有sentinel monitor mymaster 主节点IP 6379 1 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000 sentinel auth-pass mymaster yourpassword然后启动哨兵容器docker run -d --name redis-sentinel \ -p 26379:26379 \ -v /mydata/redis-sentinel/conf/sentinel.conf:/etc/redis/sentinel.conf \ redis:7.0 redis-sentinel /etc/redis/sentinel.conf手动把主节点stop掉等几秒再看sentinel日志docker logs redis-sentinel日志里会出现“switch-master”说明故障转移成功选出了新主节点。整个过程容器化后哨兵监控的是容器映射到宿主机的端口如果换成自定义网络里用容器名访问配置文件写法要同步调整。7.3 用Docker Compose一键编排整套环境手敲这么多docker run命令容易记错参数不说管理和扩展性也差。项目级基础设施一般用Docker Compose管理它把多个容器的配置写在一个yaml文件里一条命令启动全部。比如我经常用的一套配置包含一个Redis容器和一个哨兵容器version: 3.8 services: redis: image: redis:7.0 container_name: redis restart: always ports: - 6379:6379 volumes: - /mydata/redis/conf/redis.conf:/etc/redis/redis.conf - /mydata/redis/data:/data command: redis-server /etc/redis/redis.conf sentinel: image: redis:7.0 container_name: redis-sentinel restart: always depends_on: - redis ports: - 26379:26379 volumes: - /mydata/redis-sentinel/conf/sentinel.conf:/etc/redis/sentinel.conf command: redis-sentinel /etc/redis/sentinel.conf保存为docker-compose.yml然后执行docker compose up -d所有容器就都起来了。查看状态docker compose ps停止全部服务docker compose down这套组合拳适合开发环境快速起一套Redis高可用也适合在公司内部演示和评审时快速验证方案。8. 常见问题与排查技巧实录到了全文最实战的一节。这些坑我基本都踩过有的是配置问题有的是参数问题按套路排查能省很多时间。8.1 启动容器失败或反复重启启动容器后docker ps看不到docker ps -a看到状态是exited。先看日志docker logs redis大多数情况是配置文件有问题。比如redis.conf里的dir目录不存在导致Redis没法写持久化文件或者配置文件的权限有问题容器内Redis用户读不了也或者映射的宿主机目录没创建Docker帮你建了一个root用户的目录导致容器内用户写不进去。解决办法把所有要挂载的宿主机目录提前建好比如mkdir -p /mydata/redis/conf /mydata/redis/data chmod -R 755 /mydata/redis然后用docker run时不要加-d改成前台模式观察输出docker run --rm --name redis-test -p 6379:6379 -v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf -v /mydata/redis/data:/data redis:7.0 redis-server /etc/redis/redis.conf日志会直接打在终端里定位问题比看docker logs还快。8.2 容器能启动但从外部连不上Redis这个问题典型表现是docker exec进容器执行redis-cli ping能通但宿主机或其他机器就是连不上。排查路径如下检查端口映射docker ps看PORTS列是否显示0.0.0.0:6379-6379/tcp如果只有一个IP绑定或者没映射检查-p参数。检查Redis是否只监听了127.0.0.1用redis-cli连上后执行config get bind如果返回127.0.0.1说明配置文件里的bind覆盖生效了。需要改成bind 0.0.0.0。检查云服务器的安全组阿里云、腾讯云这些环境光开Docker端口还不够安全组规则里必须放行6379端口。8.3 Redis内存越来越大宿主机磁盘也被占满Redis是内存数据库所有数据都放内存里内存占用随数据量增长是正常的。但如果担心OOM需要同时配置maxmemory和内存淘汰策略。在redis.conf里加maxmemory 256mb maxmemory-policy allkeys-lru这里maxmemory表示Redis最大可用内存超过后按照allkeys-lru策略淘汰最久未使用的key。注意maxmemory一定不能大于容器的-m限制否则Redis还没触发淘汰容器OOM已经被杀了。宿主机磁盘被占满多半是持久化文件没管理好。RDB快照和AOF文件都会持续增长尤其AOF rewrite没开启的情况下AOF文件会膨胀到非常夸张。务必在redis.conf里开启auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb当AOF文件超过上次rewrite后大小的一倍且大于64mb时自动触发rewrite压缩文件体积。8.4 时区问题导致日志和过期时间不准容器默认时区是UTC和本地时间差8小时。虽然对Redis本身功能没影响但如果你用expireat设置key在某个具体时间过期就会因为时区错乱把时间算错。在redis.conf里设置时区不方便最好在启动时把宿主机的timezone挂载进去-v /etc/timezone:/etc/timezone:ro -v /etc/localtime:/etc/localtime:ro这样就完全跟随宿主机时区了。Windows下没有这两个文件可以直接在容器环境变量里设置TZ-e TZAsia/Shanghai设置完重启容器date看看时间是否正常。这个细节在排查询问“为什么我的key提前过期了”的时候能帮你少熬一宿。8.5 Redis日志看不到排错像瞎子摸象很多人的Redis容器日志非常安静就几条启动信息。这不一定正常很多时候是日志级别设置得过高。如果排查问题需要详细日志在redis.conf里把loglevel改成debugloglevel debug然后重启容器再用docker logs -f redis可以看到每条命令的执行记录和内部日志。查完问题再改回notice这玩意儿的debug日志量非常大生产环境别开着。9. 容器里跑Redis的性能损失到底有多大这是很多人犹豫不决的核心问题Docker对Redis这种高性能内存数据库的性能损耗到底值不值得换取部署便利官方给出的结论是Docker的NAT网络模式相对于宿主机直连网络延迟有轻微增加尤其是小包高频场景差距大约在毫秒级别。但Redis本身操作耗时通常在微秒量级所以很多人担忧的“容器会大幅拖慢Redis”并不成立前提是你用对了网络模式。9.1 网络模式对性能的影响默认bridge网络下所有容器流量都要经过Docker创建的虚拟网桥和iptables规则。对于单次操作这个开销在微秒级别但如果你做的是benchmark或者超高频读写累积差距才会显现。调整方式是使用host网络直接用宿主机网络栈不走iptables转发。启动命令docker run -d --name redis --network host redis:7.0这种模式下不需要-p映射端口Redis监听的6379端口就是宿主机的6379。好处是性能几乎无缝接近原生坏处是没法映射端口如果你想要让Redis监听多个端口做多实例host模式配置麻烦。另外一个真实的性能损耗点是持久化频率。RDB快照短周期执行时fork子进程如果数据量很大会消耗内存并短暂卡顿。用Docker部署时云服务器内存有限这个问题被放大了。解决思路是调大RDB触发阈值或者让AOF的everysec模式兜底该卡的时候让它卡别在高峰期频繁触发fork。9.2 Redis数据类型的合理使用前面全程没展开讲Redis的数据类型但热搜词里有“redis数据类型”这里补充几句。Redis提供的5种基本类型string、list、hash、set、zset不只是存缓存用很多业务场景离了它们还真没法干string常规缓存、计数器、分布式锁的value存续都用它。list适合做消息队列的简易实现lpush加brpop的经典组合。hash存储对象比把整个对象序列化成一个string更省内存也能单独操作字段。set做去重、共同好友、标签系统这些集合运算一行sinter就能求出交集。zset排行榜首选按score排序天然支持还能做延迟队列和时间窗口限流。Docker部署Redis时数据结构不受影响但maxmemory策略的选择直接影响哪一种类型先被淘汰比如allkeys-lru适合缓存场景volatile-lru适合只淘汰设置了过期时间的key的场景。这个属于业务设计不展开细说。10. 快手脚本用Redis实现分布式锁和缓存治理热搜词里出现了“redis分布式锁”和“redis缓存治理”说明很多人的实际需求不止装完就行还想用它解决业务问题。如果你用的正是Docker里的Redis下面这些场景可以直接落地。10.1 分布式锁的正确打开方式分布式锁的实现方式有很多最简单且不依赖第三方库的方式是Redis官网推荐的SETNX EXPIRE组合在Redis 7.0中已经封装为一条原子命令SET lock_key unique_value NX PX 30000这条命令的含义是只有当lock_key不存在时才设置成功并且自动带上30秒过期时间。NX保证互斥PX防止持有锁的服务宕机后死锁。释放锁时要用Lua脚本比较value是不是自己设置的只有是自己设置的才能删除if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end为什么搞这么复杂因为如果释放锁时直接把key删了可能误删别人刚获取的锁。这种问题在单机Redis部署里都会出现在Docker多副本部署时尤其明显。容器化以后Redis实例经常切换网络锁的续期机制更加重要。生产环境建议直接用Redisson它把看门狗续期和重入都封装好了不要自己造轮子。10.2 缓存穿透、击穿和雪崩的应对缓存穿透请求一个不存在的keyRedis查不到就会直接打到数据库。解决方案是布隆过滤器或者在缓存里存一个值为空的短TTL的key。缓存击穿某个热点key过期瞬间大量请求同时打到数据库。解决方案是热点数据互斥锁或者让热点key永不过期只更新value。缓存雪崩大量key同时过期数据库直接打挂。解决方案是过期时间加随机值别让key成群结队地过期。这些治理方案在Docker部署的Redis上都不会有什么特殊差异唯一要注意的是内存监控。多容器场景下Redis内存和CPU指标必须采集不然缓存治理做了半天内存爆了都不知道。11. 一些我的经验之谈最后再聊几句掏心窝的话。从我个人的实操体会来看用Docker安装Redis最大的意义并不是“快”而是“干净”。每次为了一个Redis把系统环境搞乱是最亏的。有了容器你随时可以起一个最新版Redis试功能用完即焚不留一点痕迹。其次在所有配置里优先级一定不要把配置文件放太随意。挂载配置文件的路径、数据目录的路径建议从第一天就规划好别图省事把数据卷丢在home目录下或者/tmp。规范化后缀至少做到哪台机器上看到同样的路径就能找到Redis的数据这一点对团队协作帮助很大。如果再往前走一步后续看Docker的存储卷和网络配置会发现容器编排是比命令管理更高级的工具。Docker Compose能把Redis、Redis主从、哨兵这些配置全部纳入版本管理谁改动了一目了然这又比手动敲docker run高一个层级。这篇文章写的都是我在实际部署中踩过的坑和总结下来的高效操作。你先照着跑通一遍再按照自己的场景调整参数很快就能真正驾驭容器里的Redis。
返回列表