Docker容器化部署Node+Redis应用时client.get调用卡住问题排查
问题背景
基于Node + Express + Postgres + Redis技术栈的应用完成Docker容器化部署后,应用可正常向Postgres、Redis写入数据,但执行Redis客户端client.get方法时会卡住无响应,相同逻辑在非容器化环境下可正常运行。
出问题的业务代码片段:
await client.get(collarId, (err, data) => { }
已完成的验证项:
- Redis持久化配置正常,挂载目录下可找到
dump.rdb文件,新写入的记录可在持久化文件中查到 - Redis服务的docker-compose配置如下:
cache: container_name: cache image: 'redis:latest' restart: always ports: - "6379:6379" expose: - 6379 command: redis-server --save 20 1 --loglevel warning --requirepass redis --appendonly yes volumes: - ./redis-vol:/data networks: - my-network
可行排查步骤
- 先排查客户端API写法混用问题:当前代码同时使用
await和回调函数参数,主流Node.js Redis客户端(如node-redis v4+版本)如果传入回调函数,不会返回可等待的Promise对象,会导致await等待一个永远不会变更状态的pending Promise,表现为代码卡住。先改为纯Promise写法测试:const data = await client.get(collarId),移除回调参数,优先排除依赖版本差异带来的API兼容问题——容器内安装的依赖版本如果和本地非容器环境不一致,很容易触发这类写法兼容故障。 - 验证连通性与鉴权配置:
- 进入应用容器内部,安装redis-cli工具,执行
redis-cli -h cache -a redis ping,确认返回PONG,排除跨容器网络连通故障 - 核对应用侧Redis客户端配置,确认已正确配置连接密码
redis。未鉴权的连接发送命令时,Redis不会主动断开连接,若客户端未监听错误事件,会表现为命令一直等待无响应;写入操作若为无等待的发后即忘模式,可能不会立刻暴露鉴权问题 - 在应用容器内直接执行
redis-cli -h cache -a redis get 提前写入的测试key,确认Redis服务本身可正常响应读请求
- 进入应用容器内部,安装redis-cli工具,执行
- 检查容器网络配置:
- 确认应用服务在docker-compose配置中同样加入了
my-network网络,否则无法通过服务名cache直接访问Redis容器 - 若应用侧配置的Redis地址为
localhost,需修正为Redis容器服务名cache:容器网络模式下localhost指向当前容器自身,不会映射到宿主机或其他容器的端口 - 检查客户端连接参数,确认未配置过长或为0的
connectTimeout、commandTimeout值,避免超时逻辑失效导致命令永久挂起
- 确认应用服务在docker-compose配置中同样加入了
- 排查Redis服务端阻塞问题:
- 进入Redis容器执行
redis-cli -a redis info clients,查看当前连接数是否达到maxclients上限,是否有大量空闲占满连接池导致新命令无法被处理 - 执行
redis-cli -a redis slowlog get 10,查看是否存在慢查询阻塞Redis单线程处理流程,导致GET命令排队无法执行 - 执行
docker logs cache查看Redis运行日志,排查是否存在内存超限被系统限制、持久化fork操作阻塞进程、权限异常等服务端报错
- 进入Redis容器执行
- 校验运行环境一致性:
- 对比容器内安装的Redis客户端npm包版本和本地非容器环境版本,node-redis v3与v4版本的异步逻辑、API规范差异极大,版本不一致时很容易出现异步逻辑异常
- 对比容器内Node.js运行时版本和本地版本,排除版本差异导致的异步调度异常
内容的提问来源于stack exchange,提问作者kzaiwo
相关产品推荐
相关产品推荐

