- 文档
- 教程
- 后端
【免费下载链接】CodeGuide
:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助,请给予支持(关注、点赞、分享)!
本篇是 Lottery 分布式抽奖系统"系统运维"篇章的第 3 节实战指南。核心目标是在云服务器上借助 Docker 容器化技术安装并配置 Kafka 消息中间件(含其依赖的 Zookeeper),在 Kafka 后台为抽奖系统创建所需的 Topic 主题,并最终在本地程序中完成消息的生产与消费联调测试。读完本文,你将掌握从镜像拉取、容器启动、主题创建到 SpringBoot 程序验证的完整 Kafka 部署链路,并理解这套 MQ 环境如何在抽奖系统中承担"抽奖与发货流程解耦"的关键职责。
在 Lottery 抽奖系统(基于 DDD 领域驱动设计的四层架构实践)中,Kafka 是连接抽奖与发奖两个领域的关键纽带——抽奖完成后通过 MQ 异步触达奖品发货流程,避免流程过长导致用户长时间等待。本部署章节(与 Part-2 第 15、16 节的代码实现章节相互呼应)所搭建的 Kafka 环境,正是为了让这套 MQ 机制真正跑起来。文档原文见 第03节:部署环境 Kafka。
一、为什么抽奖系统需要 Kafka 消息中间件
在动手部署之前,先明确这套环境在项目中的定位。Lottery 项目的核心技术栈包含 SpringBoot、MyBatis、Dubbo、MQ、Redis、MySQL、ELK、分库分表等(见 Lottery 抽奖系统介绍),其中 MQ 选型在项目初期采用 Kafka,正如 第15节:搭建MQ消息组件Kafka服务环境 中所说明的:"MQ 消息的使用不非得局限于 Kafka,也可以使用 RocketMq",但 Kafka 本身具备非常突出的特性:
- 可靠性:Kafka 是分布式、分区、复制且容错的,消息在集群内复制以防止数据丢失;
- 可扩展性:消息系统可以轻松横向扩展且无需停机;
- 耐用性:Kafka 使用分布式提交日志(commit log),消息会尽可能快地持久化到磁盘上;
- 性能:对于消息的发布和订阅都具有高吞吐量,即使存储了大量消息也能保持稳定性能。
而 Kafka 在架构上构建在 Zookeeper 同步服务之上,因此部署 Kafka 必然要一并部署 Zookeeper——这也是本部署章节第一步先启动 Zookeeper 的原因。Zookeeper 在 Kafka 集群中承担 broker 注册发现、控制器(Controller)选举、Topic/分区元数据维护等协调职责。
在 Lottery 面试技能与问题汇总 中,针对"为什么使用 MQ 解耦发奖流程"给出了清晰的项目答案:把抽奖和发奖用 MQ 消息串联起来,避免一个流程太长,导致用户一直等待。这也正是本章节部署 Kafka 的最终业务价值所在。
二、下载 Kafka 与 Zookeeper 镜像
在 Docker 容器中安装 Kafka 的第一步是拉取镜像。原文档选用的是wurstmeister组织维护的 Kafka 与 Zookeeper 镜像,可以在 Docker Hub 官网镜像市场搜索对应镜像名称获取详细信息。
在云服务器终端执行如下两条命令,分别拉取 Kafka 与 Zookeeper 镜像:
docker pull wurstmeister/kafka docker pull wurstmeister/zookeeper部署前提:本文以"云服务器 + Docker 容器"为部署环境。在 第01节:在云服务器部署 Docker 中已经完成了 Docker 的安装与 Portainer 运维面板的部署。如果你的服务器拉取 Docker Hub 镜像时报错(如
error response from daemon: Get "https://registry-1.docker.io/v2/...),可以参考该节中配置registry-mirrors国内镜像加速的daemon.json写法后重启 Docker 再拉取。
命令参数说明:
| 参数 | 含义 |
|---|---|
pull | 从 Docker Hub 拉取指定镜像到本地 |
wurstmeister/kafka | Kafka 镜像,包含 Kafka Server 与配套脚本 |
wurstmeister/zookeeper | Zookeeper 镜像,用于支撑 Kafka 集群协调 |
三、启动 Zookeeper 容器
Kafka 依赖 Zookeeper 完成集群元数据管理,因此必须先于 Kafka 启动 Zookeeper。原文档给出的启动命令如下:
docker run -d --name zookeeper -p 2181:2181 -t wurstmeister/zookeeper命令逐项拆解:
| 参数 | 含义 |
|---|---|
-d | 以守护进程(后台)方式运行容器,容器日志可通过docker logs zookeeper或 Portainer 查看 |
--name zookeeper | 为容器命名,后续管理、停止、删除都可通过该名称操作 |
-p 2181:2181 | 端口映射,将容器内 2181 端口映射到宿主机的 2181 端口,供 Kafka 与外部客户端访问 |
-t | 分配一个伪终端(TTY),便于查看交互式输出 |
wurstmeister/zookeeper | 使用的镜像名称 |
启动后,Zookeeper 的默认监听端口即为 2181(客户端连接端口)。由于后续 Kafka 容器需要与 Zookeeper 通信,且本地程序联调时也可能直接访问 Zookeeper,这个端口映射至关重要。
注意:如果容器间需要互相通信,Kafka 容器内访问 Zookeeper 既可以使用宿主机 IP(如
192.168.x.x:2181),也可以让 Kafka 与 Zookeeper 处于同一 Docker 网络(--network)下通过容器名互访。云服务器部署场景下,为了让本地程序能够远程连接,还需要确保云厂商安全组中放行 2181、9092 等端口。
四、启动 Kafka 容器并完成配置
启动 Zookeeper 后,即可创建并启动 Kafka 容器。由于 Kafka 容器需要感知集群信息与外部访问地址,启动命令中需要注入关键环境变量:
docker run -d --name kafka \ -p 9092:9092 \ -e KAFKA_BROKER_ID=0 \ -e KAFKA_ZOOKEEPER_CONNECT=你的云服务器IP:2181 \ -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://你的云服务器IP:9092 \ -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \ wurstmeister/kafka核心环境变量说明:
| 环境变量 | 作用 |
|---|---|
KAFKA_BROKER_ID | Broker 唯一标识,单机部署可设为 0 |
KAFKA_ZOOKEEPER_CONNECT | 指定 Kafka 连接的 Zookeeper 地址,指向上面启动的 Zookeeper 容器(宿主机 IP:2181) |
KAFKA_ADVERTISED_LISTENERS | 对外公布的监听地址,必须配置为客户端(本地程序)能够访问到的 IP,否则本地程序会因拿到容器内部地址而连接失败 |
KAFKA_LISTENERS | Broker 实际监听的地址,0.0.0.0:9092表示监听宿主机所有网卡的 9092 端口 |
启动完成后,可以通过 Portainer 运维面板直观地查看 kafka 容器的运行状态与日志,例如 Kafka 的 GroupCoordinator(消费者组协调器)会持续输出消费者组加入、退出等协调日志。下图展示了 Portainer 中 kafka 容器日志页面,日志中记录了抽奖系统lottery消费者组成员变化情况,这正是后续本地测试程序接入消费后的真实运行痕迹:
原文档以运维日志形式记录了这一部署环节:"在 Docker 容器中安装和配置 Kafka 环境"、"在 Kafka 后台添加抽奖系统需要的 Topic 主题,并在本地程序中进行测试"。部署到这一步,Kafka 环境已经具备承载 Topic 的能力。
五、在 Kafka 后台创建抽奖系统需要的 Topic
Kafka 中的消息以 Topic(主题)为单位组织,生产者向 Topic 写入消息,消费者从 Topic 拉取消息。抽奖系统需要为"发货单消息"创建专属主题。
在 第16节:使用MQ解耦抽奖发货流程 中明确说明:"启动 kafka 新增 topic:lottery_invoice 用于发货单消息,当抽奖完成后则发送一个发货单,再异步处理发货流程,这个部分就是 MQ 的解耦流程使用"。
对应 Topic 创建命令如下(本地 Kafka 安装包方式启动时的标准写法):
# 启动 Zookeeper(若使用本地安装包而非 Docker) bin/zookeeper-server-start.sh -daemon config/zookeeper.properties # 启动 Kafka bin/kafka-server-start.sh -daemon config/server.properties # 创建抽奖系统发货单主题 bin/kafka-topics.sh --create --zookeeper localhost:2181 \ --replication-factor 1 --partitions 1 --topic lottery_invoice参数说明:
| 参数 | 含义 |
|---|---|
--create | 创建新主题 |
--zookeeper localhost:2181 | 指定 Zookeeper 地址,主题元数据由 Zookeeper 管理 |
--replication-factor 1 | 副本因子为 1,单机部署时无需多副本 |
--partitions 1 | 分区数为 1,单机场景下足以支撑抽奖系统的消息收发 |
--topic lottery_invoice | 主题名称,即抽奖发货单消息主题 |
如果 Kafka 运行在 Docker 容器中,也可以进入容器执行同样的脚本,例如:
docker exec -it kafka bin/kafka-topics.sh --create \ --zookeeper 你的云服务器IP:2181 \ --replication-factor 1 --partitions 1 --topic lottery_invoice创建完成后,可通过bin/kafka-topics.sh --list --zookeeper localhost:2181验证主题是否已存在。
六、本地程序测试:SpringBoot 整合 Kafka 验证生产与消费
环境就绪后,需要在本地程序中完成消息的生产与消费联调验证。这一部分对应 第15节:搭建MQ消息组件Kafka服务环境 的分支211023_xfg_mq_kafka,其核心工作是:"搭建 Kafka 环境,配置消息主题"、"SpringBoot 整合 Kafka,验证消息的生产和消费"。
1. 配置生产者与消费者
在 SpringBoot 工程中引入 Kafka 依赖后,主要配置分为三块:
- 生产者配置:
bootstrap.servers指向你的云服务器IP:9092(即上文KAFKA_ADVERTISED_LISTENERS中公布的地址);key.serializer与value.serializer配置为StringSerializer,将消息对象序列化为字符串发送。 - 消费者配置:同样指向
bootstrap.servers,key.deserializer与value.deserializer配置为StringDeserializer;group.id指定消费者组,例如lottery(Portainer 日志中出现的lottery组即来源于此);enable.auto.commit决定是否自动提交消费位点。 - Topic 确认:消费者监听
lottery_invoice主题,收到发货单消息后进入发奖流程处理。
2. 验证消息生产与消费
本地程序启动后,向lottery_invoice主题发送一条消息,此时应能在消费者端日志中看到消息被成功接收。同时,在 Portainer 的 kafka 容器日志页面中,可以看到 GroupCoordinator 输出消费者组的加入与退出记录(如前面 3-02 截图所示),这是确认"本地程序已成功接入 Kafka 集群"的最直观证据。
常见联调问题与排查方向:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 生产/消费超时 | 云服务器安全组未放行 9092 端口 | 检查安全组入站规则 |
| 消费者连不上 Broker | ADVERTISED_LISTENERS配成了容器内地址 | 改为云服务器公网可达 IP |
| 主题不存在 | 未提前创建lottery_invoice | 按第五节命令创建主题 |
七、抽奖系统中的 MQ 应用:解耦抽奖与发货流程
Kafka 环境验证通过后,抽奖系统便真正具备了异步解耦能力。在 第16节:使用MQ解耦抽奖发货流程 中,这套机制在代码层面的落地点包括:
- 库表扩展:在数据库表
user_strategy_export中添加字段mq_state,用于标记 MQ 消息是否发送成功——发送成功后更新库表状态;若发送失败,则通过定时任务补偿 MQ 消息,保证消息最终可达。 - 异步发货:在
ActivityProcessImpl#doDrawProcess活动抽奖流程编排中,用户抽奖完成后发送 MQ 消息触达异步奖品发送流程,抽奖接口立即返回,用户无需等待发奖完成。 - 流程闭环:消费者收到
lottery_invoice发货单消息后,进入奖品发放的处理链路,完成从抽奖到发奖的异步闭环。
这一设计与 Lottery 面试技能与问题汇总 中的项目问答相互印证:"解耦抽奖流程,把抽奖和发奖用 MQ 消息串联起来,避免一个流程太长,导致用户一直等待";同时面试中还会考察"消息丢失怎么办"——mq_state状态字段 + 定时任务补偿正是该项目给出的答案。
八、部署验证清单
完成本章节部署后,建议按以下清单逐项自检:
docker ps中 zookeeper 与 kafka 两个容器均为 Up 状态;- Portainer 容器列表可见两个容器,kafka 日志无 ERROR 级报错;
kafka-topics.sh --list可列出lottery_invoice主题;- 本地 SpringBoot 程序向
lottery_invoice发送消息,消费者端与 Portainer 日志中均有消费记录; - 云服务器安全组已放行 2181(Zookeeper)与 9092(Kafka)端口。
至此,Lottery 抽奖系统的 Kafka 消息中间件环境搭建完成,后续的 MQ 解耦发货流程、消息补偿等业务功能均可以在此基础上继续开发与联调。
- 文档
- 教程
- 后端
【免费下载链接】CodeGuide
:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助,请给予支持(关注、点赞、分享)!
相关推荐
云服务器部署 Docker 实战:为 Lottery 抽奖系统搭建容器环境与 Portainer 面板
云服务器部署 Docker 实战:为 Lottery 抽奖系统搭建容器环境与 Portainer 面板 在 Lottery 抽奖系统(基于 DDD 四层架构的分
文档教程后端log-lottery抽奖系统技术实现与部署指南
log lottery抽奖系统技术实现与部署指南 技术架构解析 log lottery是一个基于现代前端技术栈构建的3D抽奖应用,其核心架构采用分层设计理念。前
前端桌面应用lottery抽奖系统终极部署指南:5步快速搭建活动平台
lottery抽奖系统终极部署指南:5步快速搭建活动平台 在各类企业活动、年会庆典中,如何打造一个既酷炫又高效的抽奖系统一直是活动策划者的痛点。lottery开
后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考