Redis集群搭建与文章投票后端实战:从单机到三主三从 简介本资源为南京邮电大学大数据存储与管理课程实验一的完整报告文档面向学习Redis与大数据存储技术的高校学生及自学者帮助解决Redis单机与集群环境搭建、以及基于Redis开发实际应用的问题。资源包内含1个doc文件约933KB为实验报告正文涵盖实验目的、环境配置、操作步骤与结果分析等模块。内容围绕Ubuntu 16.04下Redis的安装与配置展开详细记录了单机环境部署、六节点集群搭建含三主三从以及利用String与Sorted Set构建文章投票网站后端的完整流程并附有投票、评分、分组等关键代码与运行结果截图。目前已有324人学习适合需要参考实验报告结构、排错思路与集群配置细节的读者可据此快速复现实验并理解Redis在实际场景中的应用方式。1. 从单机到集群一份能跑通的 Redis 实验拆解很多人第一次接触 Redis 集群都是在课程实验里被cluster-enabled和 slot 分配折腾得够呛。这份大数据存储与管理实验一核心就三件事在 Ubuntu 上装好单机 Redis、搭一个三主三从的集群、再用 Python 写一个文章投票网站的后端。它适合正在学 Redis 但卡在集群配置这一步的人也适合想找一个完整小项目练手数据建模的开发者。我拆完这套流程后发现真正花时间的不是写代码而是配置文件里那几个参数和集群初始化时的 slot 分配。下面按实操顺序把每一步讲透包括我踩过的坑和绕过去的办法。2. 单机 Redis 安装与远程连接从 apt 源到桌面客户端2.1 为什么用官方 apt 源而不是系统自带包Ubuntu 自带的apt install redis-server能装但版本往往偏旧而且配置文件路径和官方源不一致后面搭集群时容易出玄学问题。实验里走的是 Redis 官方 apt 源步骤多一点但版本可控、配置模板统一。先装依赖sudo apt install lsb-release curl gpg这三个包分别负责lsb-release用来识别当前 Ubuntu 的代号比如 xenial、bioniccurl用来下载 GPG 密钥gpg用来把密钥转成 apt 能识别的格式。缺一个后面加源就会报错。接着导入官方签名密钥并写入 apt 源列表curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg 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--dearmor是把 ASCII 格式的密钥转成二进制 keyringsigned-by告诉 apt 用哪个密钥验证这个源。$(lsb_release -cs)会自动替换成当前系统代号不用手写。更新索引并安装sudo apt-get update sudo apt-get install redis装完后 Redis 默认不会自动启动需要手动拉起/etc/init.d/redis-server start提示如果提示权限不够先sudo -i切到 root后续改配置和重启都方便。2.2 改配置文件时到底改了什么配置文件在/etc/redis/redis.conf用 vim 打开后重点看这几个参数参数默认值建议值作用bind127.0.0.10.0.0.0 或虚拟机 IP控制哪些地址能连进来protected-modeyesno仅实验环境关闭保护模式才能远程连port63796379单机保持默认daemonizenoyes让 Redis 后台运行改完重启/etc/init.d/redis-server restart然后用ifconfig查虚拟机 IP记下来桌面客户端连接时要用这个地址不是 127.0.0.1。2.3 桌面客户端连不上的排查顺序用 Another Redis Desktop Manager 连接时如果报ECONNREFUSED 127.0.0.1:6379按这个顺序查确认 Redis 进程在跑ps -ef | grep redis确认bind不是只绑了 127.0.0.1确认protected-mode已关闭确认客户端填的 IP 是虚拟机 IP不是本地回环确认虚拟机防火墙没拦 6379 端口实验报告里提到“关闭安全模式没解决改 IP 后成功”本质就是客户端填了 127.0.0.1而 Redis 跑在虚拟机里回环地址指向的是客户端本机自然连不上。3. 三主三从集群搭建配置文件与 slot 分配3.1 集群目录规划和配置文件模板集群不能共用单机的配置文件需要单独建目录、单独写配置。先建目录结构mkdir -p /opt/redis/cluster/log cp /etc/redis/redis.conf /opt/redis/cluster/ cd /opt/redis/cluster然后为每个节点创建独立配置文件。以 6379 为例touch redis-6379.conf vi redis-6379.conf每个节点配置文件的核心参数如下以 6379 为例其他节点只改端口和路径port 6379 daemonize yes pidfile /var/run/redis_6379.pid logfile /opt/redis/cluster/log/redis_6379.log dir /var/lib/redis/6379 cluster-enabled yes cluster-config-file nodes-6379.conf cluster-node-timeout 15000 appendonly yes这里有几个参数是集群专属的单机配置里没有cluster-enabled yes开启集群模式不开这个后面cluster create会直接报This instance has cluster support disabledcluster-config-file每个节点自己维护的集群状态文件不要手动改cluster-node-timeout节点心跳超时时间单位毫秒实验环境 15000 够用六个节点端口分配6379、6380、6381 做 master6389、6390、6391 做 slave。每个节点的dir目录要提前建好否则启动会报路径不存在。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-server 进程每个后面跟着对应的配置文件路径。如果少了去看对应节点的日志文件通常在/opt/redis/cluster/log/下。3.3 合成集群与 slot 分配逻辑六个节点都起来后用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。Redis 集群一共 16384 个 slot三主均分后每个 master 负责约 5461 个。命令执行后会提示你确认 slot 分配方案输入yes继续。合成后进入任意节点查看集群状态redis-cli -p 6379 cluster nodes cluster infocluster nodes会列出所有节点及其角色master/slave、slot 范围和节点 ID。cluster info看整体状态cluster_state:ok才算正常。注意如果之前在这台机器上跑过单机 Redis 并且写过数据合成集群时可能报Slot 671 is already busy。原因是旧的 slot 数据没清干净。4. 文章投票后端数据模型与 Python 实现4.1 用哈希和有序集合建模文章投票网站的核心数据就两类文章内容和投票排序。Redis 里用两种结构配合Hash存文章详情key 是article:文章IDfield 是标题、作者、链接等ZSet存文章的时间排序和评分排序key 是time或scoremember 是文章 keyscore 是时间戳或评分文章 ID 用INCR article生成自增 ID保证唯一。发布文章时同时写 Hash 和 ZSet投票时更新 ZSet 的 score。4.2 发布文章与初始投票的代码实现先装集群客户端库pip install redis-py-cluster核心发布函数import time from rediscluster import RedisCluster # 集群节点列表启动时至少给一个可用节点 startup_nodes [{host: 127.0.0.1, port: 6379}] rc RedisCluster(startup_nodesstartup_nodes, decode_responsesTrue) def post(articleData, redisrc): # 文章 ID 自增保证唯一 articleId str(redis.incr(article)) article article articleId # 用 Hash 存文章字段 for k, v in articleData.items(): redis.hset(article, k, v) # 记录发布时间用于按时间排序 post_time time.time() redis.zadd(time, {article: post_time}) print(即将为自己投初始票!, articleData[poster]) # 发布者自动投一票 vote(article, articleData[poster], True) score(article, redis) return article逻辑说明incr(article)是原子操作多个客户端同时发布不会撞 ID。hset逐个写入字段zadd把文章加入时间有序集合。最后调用vote给发布者自己投一票再调用score更新评分。参数说明articleData是字典至少包含title、link、poster三个字段。decode_responsesTrue让返回结果是字符串而不是 bytes调试时更直观。4.3 投票、评分与分组操作投票函数的核心逻辑def vote(article, user, redisrc): # 记录用户对这篇文章的投票防止重复投票 if redis.sadd(fvoted:{article}, user): # 投票成功文章评分加一 redis.zincrby(score, 1, article) return True return False用 Set 存已投票用户sadd返回 1 表示新投票返回 0 表示重复投票。只有新投票才更新评分。评分函数负责把文章的发布时间和投票数做加权计算def score(article, redisrc): # 获取文章发布时间和当前投票数 post_time redis.zscore(time, article) votes redis.zscore(score, article) or 0 # 简化评分公式投票数 时间衰减因子 article_score votes post_time / 1000000 redis.zadd(score, {article: article_score})分组操作用 Set 实现把文章 ID 加入对应分组def add_to_group(group, article, redisrc): redis.sadd(fgroup:{group}, article)按评分降序取文章def get_top_articles(n10, redisrc): # zrevrange 按 score 从高到低取 return redis.zrevrange(score, 0, n - 1, withscoresTrue)zrevrange的withscoresTrue会同时返回文章 key 和评分方便前端展示。5. 避坑排查集群实验里最容易翻车的四个点5.1 客户端连不上ECONNREFUSED 127.0.0.1:6379现象桌面客户端填 127.0.0.1 连接报连接被拒绝。原因Redis 跑在虚拟机里客户端在宿主机上127.0.0.1 指向的是宿主机自己不是虚拟机。解决用ifconfig查虚拟机 IP客户端填这个 IP。同时确认bind参数包含该 IP 或设为 0.0.0.0protected-mode设为 no。5.2 集群创建报错cluster support disabled现象执行cluster create时提示ERR This instance has cluster support disabled。原因配置文件里cluster-enabled还是默认的 no或者前面有#被注释掉了。解决打开每个节点的配置文件找到cluster-enabled去掉注释值改为 yes重启该节点。六个节点都要改漏一个都会失败。5.3 Slot 被占用Slot 671 is already busy现象集群合成时提示某个 slot 已经被占用。原因之前在这台机器上跑过 Redis 并写过数据旧的 slot 分配信息残留在节点里。解决登录每个节点执行清理redis-cli -p 6379 flushall cluster reset六个节点都执行一遍然后重新cluster create。flushall清数据cluster reset清集群状态。5.4 桌面客户端连集群报 connection is close现象单机连上了切到集群模式后报stream on error: connection is close或cluster is ended。原因集群模式下客户端需要感知所有节点普通 TCP 连接拿不到完整的节点拓扑。解决客户端连接方式改用 SSH 隧道加集群模式或者在代码里用RedisCluster类而不是普通Redis类。桌面客户端一般有 cluster 连接选项勾上后填任意一个节点地址即可。6. 从实验到可用把投票后端跑成可验证的闭环实验代码能跑通发布和投票但离“可验证”还差一步你需要一个能重复执行的测试流程确认数据真的写对了。我一般会写一个小的验证脚本按顺序执行发布、投票、分组、排序然后断言结果。def test_flow(): # 发布两篇文章 a1 post({title: Redis集群实践, link: http://example.com/1, poster: userA}) a2 post({title: 大数据存储选型, link: http://example.com/2, poster: userB}) # userB 给文章1投票 vote(a1, userB) # userA 给文章2投票 vote(a2, userA) # 把两篇文章加入同一个分组 add_to_group(tech, a1) add_to_group(tech, a2) # 验证分组内容 group_articles rc.smembers(group:tech) assert a1 in group_articles and a2 in group_articles, 分组写入失败 # 验证评分排序 top get_top_articles(2) assert len(top) 2, 排序结果数量不对 # 验证重复投票被拦截 assert vote(a1, userB) is False, 重复投票未被拦截 print(全部验证通过) test_flow()这个脚本的价值在于每次改完代码或配置跑一遍就知道数据模型有没有被破坏。断言里的vote返回 False 是验证防重复投票的关键——如果这里返回 True说明 Set 的去重逻辑失效了可能是 key 拼写错了或者用了错误的命令。参数调优上cluster-node-timeout在实验环境设 15000 毫秒够用但如果节点多、网络抖动大可以调到 30000。appendonly yes会牺牲一点写入性能换持久化实验阶段建议开着方便重启后数据还在。还有一个容易忽略的点redis-py-cluster库对 Python 版本有要求Python 3.10 以上可能需要换用redis库自带的集群支持。如果pip install redis-py-cluster后 import 报错先确认 Python 版本再考虑用redis.cluster.RedisCluster替代。从那以后我每次搭集群都会先跑一遍cluster info确认cluster_state:ok再跑验证脚本确认读写正常最后才去动业务代码。这个顺序帮我省了很多来回排查的时间。希望帮到你。本文还有配套的精品资源点击获取