资讯详情

Redis从单机到集群实战:六节点搭建与投票后端开发

📅 2026/10/23 5:09:43 | 华诺云谱 👁 阅读
Redis从单机到集群实战:六节点搭建与投票后端开发
简介本资源为南京邮电大学大数据存储与管理课程实验一的完整报告文档面向正在学习Redis与大数据存储技术的高校学生及自学者帮助解决单机与集群环境搭建、后端应用开发等实操问题。压缩包内仅含1个doc文件约933KB以实验报告形式系统记录了Redis在Ubuntu 16.04下的安装配置、六节点集群搭建流程以及基于Redis构建文章投票网站后端的完整实现涵盖数据模型设计、投票与排序功能编码及运行结果分析。内容包含具体命令、配置文件示例与关键代码片段并附有实验小结与常见连接报错的处理思路便于读者对照复现实验、理解Redis的String与Sorted Set等数据结构在实际场景中的用法。目前已有324人学习适合作为课程实验参考与Redis入门实践材料。1. 从一份实验报告说起Redis 单机、集群到投票后端这套东西到底能跑出什么很多人第一次接触 Redis 都是在实验课上装完单机、敲几个set/get就交差了。但这份实验报告有意思的地方在于它把三件事串成了一条线单机安装、六节点集群搭建、再基于集群写一个文章投票网站的后端。换句话说它不是让你背命令而是让你走一遍「从零到能用的数据服务」的完整链路。如果你正在学大数据存储、需要交一份能跑起来的 Redis 实验或者想找一个最小可用的 Redis 集群 Python 应用范例这份材料基本可以照着抄作业。它用的环境是 Ubuntu 16.04 PyCharm Another Redis Desktop Manager技术栈不新但胜在每一步都有命令、有报错、有解决过程踩坑记录比正文还值钱。2. 环境准备与单机安装把 Redis 跑起来并连上桌面客户端2.1 安装依赖与配置 APT 源Ubuntu 上装 Redis 最省事的方式是走官方 APT 源而不是apt install redis-server那种老包。实验里第一步就是补依赖# 安装 lsb-release、curl、gpg后面加源和验签都要用 sudo apt install lsb-release curl gpg # 导入 Redis 官方 GPG 公钥写到 keyrings 目录 curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg # 把官方源写进 apt 列表$(lsb_release -cs) 会自动取当前系统代号 echo deb [signed-by/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main | sudo tee /etc/apt/sources.list.d/redis.list # 更新索引并安装 sudo apt-get update sudo apt-get install redis这几条命令里gpg --dearmor是把 ASCII 格式的公钥转成二进制signed-by是告诉 APT 用哪个 key 去验这个源。lsb_release -cs在 Ubuntu 16.04 上会输出xenial如果你系统版本比较新这里会自动换成对应的代号不用手改。装完之后 Redis 一般不会自动起需要手动拉一下# 启动 Redis 服务 /etc/init.d/redis-server start # 切到 root后面改配置、建目录都方便 sudo -i2.2 改配置文件与远程连接单机跑起来之后默认只监听127.0.0.1桌面客户端从宿主机连虚拟机是连不上的。实验里改了/etc/redis/redis.conf常见做法是动这几个参数vim /etc/redis/redis.conf# 监听所有网卡否则外部客户端连不进来 bind 0.0.0.0 # 关闭保护模式实验环境图方便生产别这么干 protected-mode no # 如果要用客户端连设个密码更稳妥 requirepass yourpassword # 持久化方式默认 RDB 就够实验用 save 900 1改完重启cd ~ /etc/init.d/redis-server restart # 查一下虚拟机 IP客户端要填这个地址 ifconfig然后用 Another Redis Desktop Manager 新建连接Host 填ifconfig查到的虚拟机 IP端口 6379有密码就填密码。这里有个血泪经验很多人连不上第一反应是去关protected-mode但实验报告里明确写了真正的原因是客户端里填的 IP 还是127.0.0.1改成虚拟机实际 IP 就通了。所以排查顺序应该是先确认地址再动配置。提示改完bind和protected-mode之后一定要重启服务redis-cli ping返回 PONG 只能说明本机通不代表外部能连。3. 六节点集群搭建配置文件、启动顺序与 cluster create3.1 目录规划与节点配置文件单机只是热身实验的重头戏是搭一个三主三从的集群。先建目录、复制基础配置# 建集群根目录和日志目录 mkdir -p /opt/redis/cluster mkdir -p /opt/redis/cluster/log cd /opt/redis/cluster # 拿系统自带的配置当模板 cp /etc/redis/redis.conf /opt/redis/cluster/然后为每个节点单独写配置文件。以 6379 这个 master 为例touch redis-6379.conf vi redis-6379.conf# 每个节点端口不同这是区分节点的关键 port 6379 # 开启集群模式不开的话 cluster create 会直接报错 cluster-enabled yes # 集群内部配置文件每个节点一份不能共用 cluster-config-file nodes-6379.conf # 节点超时时间毫秒 cluster-node-timeout 15000 # 数据落盘目录按端口分开避免互相覆盖 dir /var/lib/redis/6379 # 日志文件也按端口区分 logfile /opt/redis/cluster/log/redis_6379.log # 后台运行 daemonize yes # 关掉保护模式方便集群节点互通 protected-mode no其余 6380、6381、6389、6390、6391 五个文件内容一样只改port、cluster-config-file、dir、logfile这四处。这里有个容易翻车的点cluster-config-file如果六个节点写成同一个文件名集群起来之后节点信息会互相覆盖cluster nodes看到的拓扑是乱的。所以端口号一定要嵌进文件名里。3.2 启动节点与合成集群配置文件齐了之后逐个拉起来/usr/bin/redis-server /opt/redis/cluster/redis-6379.conf /usr/bin/redis-server /opt/redis/cluster/redis-6380.conf /usr/bin/redis-server /opt/redis/cluster/redis-6381.conf /usr/bin/redis-server /opt/redis/cluster/redis-6389.conf /usr/bin/redis-server /opt/redis/cluster/redis-6390.conf /usr/bin/redis-server /opt/redis/cluster/redis-6391.conf # 确认六个进程都在 ps -ef | grep redis六个都起来之后用redis-cli --cluster create把它们合成一个集群/usr/bin/redis-cli --cluster create --cluster-replicas 1 \ 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 \ 127.0.0.1:6389 127.0.0.1:6390 127.0.0.1:6391--cluster-replicas 1的意思是每个 master 配一个 slave六个节点正好三主三从。命令执行后会列出主从分配方案输入yes确认。之后进客户端验证redis-cli # 看节点拓扑应该能看到三个 master 和三个 slave cluster nodes # 看集群整体状态cluster_state 应该是 ok cluster infocluster nodes输出里master 的 id 后面跟的是 slot 范围slave 会标注它跟随的 master id。如果cluster_state显示fail大概率是某个节点没起来或者 slot 分配不全先回去看日志。3.3 集群操作里最容易卡住的两个报错实验报告里记录了两个典型错误值得单独拎出来说。第一个是ERR This instance has cluster support disabled原因是redis.conf里cluster-enabled默认是注释掉的值为 no。解决就是把cluster-enabled yes前面的#去掉重启节点。第二个是ERR Slot 671 is already busy这个通常出现在反复搭集群的场景旧数据和集群配置没清干净slot 被占用了。处理方式是登录每个节点执行redis-cli -p 6379 flushall cluster reset六个节点都清一遍再重新cluster create。这两个坑本质上都是配置状态没对齐集群对节点的初始状态很敏感搭之前最好确认每个节点的nodes-*.conf是干净的。4. 投票后端实战用哈希和有序集合把文章系统搭出来4.1 数据模型与连接方式集群搭好之后实验用它做了一个文章投票网站的后端。核心数据结构就两个文章本身用 hash 存发布时间和评分用有序集合zset存。Python 侧连集群用的是redis-py-clusterpip install redis-py-clusterfrom rediscluster import RedisCluster # 集群节点列表startup_nodes 里给任意几个可用节点即可 startup_nodes [ {host: 127.0.0.1, port: 6379}, {host: 127.0.0.1, port: 6380}, {host: 127.0.0.1, port: 6381}, ] # decode_responsesTrue 让返回结果是字符串而不是 bytes rc RedisCluster(startup_nodesstartup_nodes, decode_responsesTrue)这里startup_nodes不需要写全六个客户端会自动发现完整拓扑。decode_responses建议打开否则拿到的 key 和 value 都是bxxx调试时很烦。4.2 发文章与自动投初始票发文章的核心逻辑是自增一个全局文章 ID把文章内容写进 hash记录发布时间然后作者给自己投一票。代码长这样import time def post(articleData, redisrc): # article 计数器加 1拿到新文章 ID articleId str(redis.incr(article)) article article articleId # 把标题、链接、作者等字段写进 hash for k, v in articleData.items(): redis.hset(article, k, v) # 记录发布时间score 用时间戳方便按时间排序 post_time time.time() redis.zadd(time, {article: post_time}) print(即将为自己投初始票!, articleData[poster]) # 作者自动投一票vote 函数内部会更新 score vote(article, articleData[poster], True) score(article, redis) return articleredis.incr(article)是原子操作集群环境下多个客户端同时发文章也不会拿到重复 ID。hset把文章当成一个对象存字段可以灵活增减。zadd(time, ...)把文章 ID 和时间戳关联后面要按发布时间分页就靠这个 zset。vote传True表示这是初始票内部一般会做两件事给文章的投票集合加人、给文章的评分 zset 加分数。4.3 投票、评分与分组投票函数的常见实现是用 set 记录谁投过票防止重复用 zset 存文章评分支持按分数排序。评分规则参考《Redis in Action》里的做法一票算 432 分发布时间越早的帖子在同样票数下排名越高。def vote(article, user, is_initialFalse): # 用 set 存投票用户sadd 返回 1 表示新投票 if redis.sadd(article :votes, user): # 评分 基础分 时间衰减这里简化处理 redis.zincrby(score, 432, article) def score(article, redisrc): # 把文章评分同步到 score zset votes redis.scard(article :votes) redis.zadd(score, {article: votes * 432})分组功能用 set 实现把文章 ID 加进对应 group 的集合里def add_group(group, article): redis.sadd(group: group, article) def get_group_articles(group): # 取出分组内所有文章再按评分降序排 articles redis.smembers(group: group) return sorted(articles, keylambda a: redis.zscore(score, a), reverseTrue)smembers拿到分组里的文章 ID 列表zscore从评分 zset 里取分数Python 侧排序输出。实验里最后一步就是按评分降序打印文章验证投票和分组都生效了。5. 避坑与排查连接、集群、客户端这三处最容易翻车5.1 客户端连不上单机 Redis现象是 Another Redis Desktop Manager 报connect ECONNREFUSED 127.0.0.1:6379。原因不是 Redis 没起而是客户端里 Host 填了127.0.0.1这个地址在客户端所在机器上指向的是它自己不是虚拟机。解决就是把 Host 改成ifconfig查到的虚拟机 IP。关protected-mode不一定有用先确认地址。5.2 集群创建报 cluster support disabled现象是执行cluster create时提示ERR This instance has cluster support disabled。原因是redis.conf里cluster-enabled被注释或值为 no。解决是打开配置文件把cluster-enabled yes的注释去掉六个节点都改然后重启所有节点再创建集群。5.3 集群创建报 Slot already busy现象是ERR Slot 671 is already busy。原因是之前搭过集群nodes-*.conf和数据没清slot 分配信息残留。解决是逐个节点执行flushall和cluster reset删掉旧的nodes-*.conf再重新cluster create。5.4 桌面客户端连集群报 connection is close现象是 Another Redis Desktop Manager 连集群时提示stream on error: connection is close和cluster is ended。原因是客户端直连集群节点时节点会返回 MOVED 重定向部分客户端处理不好。解决是改用 SSH 隧道方式连接或者用支持 cluster 模式的连接配置实验里就是靠 SSH 加 cluster 连接解决的。5.5 投票分数不更新现象是投了票但scorezset 里的分数没变。原因通常是vote函数里sadd返回 0说明该用户已投过逻辑直接跳过了加分。解决是检查投票用户是否重复或者在sadd返回 0 时也走一遍分数重算保证数据一致。6. 二次开发把这套投票后端改成能用的服务实验代码是脚本式的post、vote、score都是函数直接跑在 PyCharm 里。要把它变成能对外提供服务的后端我一般会做三件事。第一把 Redis 连接抽成独立模块用连接池管理。redis-py-cluster本身支持max_connections参数集群环境下连接复用比每次新建省很多开销from rediscluster import RedisCluster startup_nodes [ {host: 127.0.0.1, port: 6379}, {host: 127.0.0.1, port: 6380}, ] rc RedisCluster( startup_nodesstartup_nodes, decode_responsesTrue, max_connections10, skip_full_coverage_checkTrue, # 节点数不足时也能连 )skip_full_coverage_checkTrue在实验环境很实用因为集群可能只有部分节点在线不开这个参数客户端会直接拒绝连接。第二把投票逻辑改成幂等的。现在vote依赖sadd的返回值判断是否新投票但分数更新和投票记录是两步操作中间失败会导致数据不一致。常见做法是用 Lua 脚本把两步包成原子操作-- vote.lua投票并更新分数原子执行 local voteKey KEYS[1] local scoreKey KEYS[2] local user ARGV[1] local article ARGV[2] local points tonumber(ARGV[3]) if redis.call(SADD, voteKey, user) 1 then redis.call(ZINCRBY, scoreKey, points, article) return 1 else return 0 endPython 侧用rc.eval调用这样投票和加分要么都成功要么都不做不会出现投了票没加分的玄学问题。第三给文章列表加分页。现在get_group_articles是全量取再排序文章多了会拖慢响应。改成用 zset 的zrevrange直接分页def get_articles_by_score(page1, page_size10): start (page - 1) * page_size end start page_size - 1 # 按分数从高到低取一页 return rc.zrevrange(score, start, end, withscoresTrue)zrevrange是集群友好的因为 score zset 的 key 固定不会跨 slot。如果按分组分页可以把分组 ID 拼进 key比如score:group1保证同一分组的文章落在同一个 slot 上。验证改造是否成功我习惯用redis-cli --cluster check看 slot 分布再用cluster info确认状态最后跑一遍发文章、投票、分页查询的完整流程。从那以后我每次搭集群都强制先清nodes-*.conf再cluster create不然 slot 冲突能折腾半天。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑