简介:本资源为南京邮电大学大数据存储与管理课程实验一的完整报告文档,面向学习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、bionic),curl用来下载 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 格式的密钥转成二进制 keyring,signed-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 打开后重点看这几个参数:
| 参数 | 默认值 | 建议值 | 作用 |
|---|---|---|---|
bind | 127.0.0.1 | 0.0.0.0 或虚拟机 IP | 控制哪些地址能连进来 |
protected-mode | yes | no(仅实验环境) | 关闭保护模式才能远程连 |
port | 6379 | 6379 | 单机保持默认 |
daemonize | no | yes | 让 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 做 master,6389、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:文章ID,field 是标题、作者、链接等 - ZSet:存文章的时间排序和评分排序,key 是
time或score,member 是文章 key,score 是时间戳或评分
文章 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_nodes=startup_nodes, decode_responses=True) def post(articleData, redis=rc): # 文章 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_responses=True让返回结果是字符串而不是 bytes,调试时更直观。
4.3 投票、评分与分组操作
投票函数的核心逻辑:
def vote(article, user, redis=rc): # 记录用户对这篇文章的投票,防止重复投票 if redis.sadd(f'voted:{article}', user): # 投票成功,文章评分加一 redis.zincrby('score', 1, article) return True return False用 Set 存已投票用户,sadd返回 1 表示新投票,返回 0 表示重复投票。只有新投票才更新评分。
评分函数负责把文章的发布时间和投票数做加权计算:
def score(article, redis=rc): # 获取文章发布时间和当前投票数 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, redis=rc): redis.sadd(f'group:{group}', article)按评分降序取文章:
def get_top_articles(n=10, redis=rc): # zrevrange 按 score 从高到低取 return redis.zrevrange('score', 0, n - 1, withscores=True)zrevrange的withscores=True会同时返回文章 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.0,protected-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,再跑验证脚本确认读写正常,最后才去动业务代码。这个顺序帮我省了很多来回排查的时间。希望帮到你。
本文还有配套的精品资源,点击获取