分布式系统开发(5)——整合所有组件

发布时间:2026/6/3 10:18:47

分布式系统开发(5)——整合所有组件 系列文章分布式系统开发1——MinIO 对象存储分布式系统开发2——Redis 缓存与分布式锁分布式系统开发3——RabbitMQ独立模块分布式系统开发4——DubboZookeeperRPC服务分布式系统开发5——整合所有组件分布式系统开发6——项目打包部署与Nginx代理前端本文在上文分布式系统开发4——DubboZookeeperRPC服务的基础上进行修改。我们完成一个比较真实的业务场景用户上传头像 → 存储到 MinIO → 缓存 URL 到 Redis → 发送消息到 RabbitMQ → 通过 Dubbo 调用 Provider 更新数据库。最终通过一个 HTTP 接口完成整个分布式链路。上文项目结构如下1.创建common模块我们把前文提到的公共服务抽离出来放到common模块中右击父模块选择“新建“然后点击”模块“左侧选择”Java“右侧名称为common构建系统选 MavenJDK选17然后选择”创建“创建完后开始创建本模块的项目结构。右击”新建“然后选择”软件包“软件包名为com.guo.common右击刚才创建的common文件夹选择”新建“然后选”软件包“软件包名为com.guo.common.config然后右击common文件夹然后选择”新建“再选择”软件包“软件包名为com.guo.common.service2.修改RabbitMQ模块前面做测试的时候只简单验证了RabbitMQ功能从模块化的角度来说十分建议把下列功能进行模块化。右击ds-rabbit模块中的mq文件夹然后选择”新建“再选择”软件包“软件包名为com.guo.mq.producer右击刚才创建的producer文件夹选择”新建“然后选”Java类“类名为MessageProducer参考代码如下importcom.guo.mq.config.RabbitMQConfig;importorg.springframework.amqp.rabbit.core.RabbitTemplate;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;Component public class MessageProducer{Autowired private RabbitTemplate rabbitTemplate;public void send(String message){rabbitTemplate.convertAndSend(RabbitMQConfig.HELLO_QUEUE, message);System.out.println([mq发送] Sent message: message);}}创建完后项目结构如下注意因为其他地方可能也会用到RabbitMQ所以找到ds-rabbit模块下的config文件夹下的RabbitMQConfig中的下面这段配置改成true。是因为原来只有子模块声明队列 testMQdurablefalse整合父项目一起启动后父项目或其他模块也声明了同一个 testMQ 队列durabletrue两个模块对同一个队列的持久化配置不一致先启动的模块创建队列后后启动的模块就会报 406错误。2.修改minio模块找到common模块的配置pom.xml文件增加下面的依赖文件dependenciesdependencygroupIdio.minio/groupIdartifactIdminio/artifactId/dependency/dependencies然后刷新依赖mvn clean install然后我们把ds-minio模块中config文件夹下的的MinioConfig拖到我们创建的common模块中的config文件夹下面。再把ds-minio模块的service文件夹下的MinIOService拖到common模块下的service文件夹然后先移除ds-minio模块再删除ds-minio文件夹同时在父模块的pom.xml中删除ds-minio模块3.修改redis模块找到common模块的配置pom.xml文件增加下面的依赖文件dependencies!-- SpringDataRedis--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency!--连接池--dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId/dependency/dependencies然后刷新依赖mvn clean install然后我们把ds-redis模块中config文件夹下的的RedisConfig拖到我们创建的common模块中的config文件夹下面。再把ds-redis模块的utils文件夹下的RedisUtil拖到common模块下的service文件夹再右击ds-redis模块点击”移除模块“然后右击ds-redis文件夹选择”删除“再打开父模块的pom.xml然后删除掉父模块的ds-redis4.修改consumer模块打开ds-consumer模块的配置文件增加下面的内容参考如下server:port:8084# 消费者 HTTP 服务端口dubbo:application:name:demo-consumerqos-enable:false# 禁用 QoS 服务避免端口冲突registry:address:zookeeper://localhost:2181consumer:check:false# 启动时不检查服务提供者是否存在避免启动报错minio:endpoint:http://localhost:9000access-key:minioadminsecret-key:minioadminbucket:online-file# 默认桶名称可自定义connect-timeout:60swrite-timeout:60sread-timeout:60sspring:data:redis:host:localhostport:6379timeout:5000mslettuce:pool:max-active:8max-idle:8min-idle:0rabbitmq:host:localhostport:5672username:guestpassword:guestvirtual-host:/然后打开ds-consumer的启动类修改启动类增加包扫描主要是rabbitmq、common、consumerimportorg.apache.dubbo.config.spring.context.annotation.EnableDubbo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.annotation.ComponentScan;SpringBootApplicationEnableDubboComponentScan(basePackages{com.guo.dubbo.comsumer,com.guo.mq,com.guo.common})publicclassConsumerApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ConsumerApplication.class,args);}}5.测试启动minio启动redis启动RabbitMQ启动zookeeper启动provider生产者再启动consumer消费者我们使用下面的内容(保存成html运行)进行上传注意下面的代码的地址和端口号是不是和你consumer模块的端口号一致。!DOCTYPEhtmlformmethodpostactionhttp://localhost:8084/api/user/avatarenctypemultipart/form-data用户IDinputtypetextnameuserIdrequiredbrbr选择文件inputtypefilenamefilerequiredbrbrbuttontypesubmit上传到 MinIO/button/form上面的html运行后界面如下:然后输入用户ID再选择文件。选择完后点击”上传到MinIO“然后返回下面的内容:在IDEA中消费者的控制台对应输出内容了我们打开minio也能发现数据上传成功了。注上面的教程中有个单词consumer手滑打成了comsumer拼错了,最新代码已经修改了本文源代码下载ds-demo5.zip链接:https://pan.baidu.com/s/1vq3YfjoX5HSdknySqpLX1Q?pwdcff16.后记分布式是指系统在运行时由多个独立部署的进程组成这些进程通过网络通信协作完成业务功能。对于本项目来说分布式特征本项目中的体现说明多进程MinIO、Redis、RabbitMQ、ZooKeeper、Dubbo Provider、Dubbo Consumer 各自是一个独立的进程每个中间件或服务都可以单独启动、停止、升级互不影响网络通信Dubbo Consumer 通过 HTTP 接收请求然后通过 Dubbo RPCTCP调用 Provider通过 RabbitMQ 发送消息通过 HTTP 调用 MinIO 和 Redis所有交互都走网络协议localhost 或远程 IP服务注册与发现ZooKeeper 作为注册中心Provider 启动时注册自己的地址IP端口Consumer 从 ZooKeeper 获取地址再发起调用实现了动态寻址不硬编码 IP负载均衡Dubbo 默认提供随机/轮询负载均衡若启动多个 Provider 实例Consumer 会自动分发请求分布式的水平扩展能力异步解耦RabbitMQ 消息队列将上传头像的通知与处理逻辑分离分布式系统中常见的异步模式独立数据存储MinIO 存储文件Redis 存储缓存Provider 可对接独立数据库未演示但可扩展数据分散在不同存储系统中为什么感觉不到分布式因为在一台机器上运行所有进程并且代码写在一个父工程下容易产生“还是单体”的错觉。但实际上单体应用所有功能在同一个进程内方法调用直接走内存不需要网络。您的系统功能被拆分为多个独立进程进程间通过 TCP/HTTP 通信任何一个进程崩溃不会导致整个系统瘫痪例如 MinIO 挂了上传功能受影响但 Consumer 还能响应其他请求。这种进程级隔离和网络通信正是分布式系统的本质。假设你把 Provider 和 Consumer 分别放到两台不同的电脑上电脑 A运行 ProviderIP 192.168.1.10电脑 B运行 ConsumerIP 192.168.1.20ZooKeeper 可以放在电脑 C 上此时Consumer 调用 Provider 时网络包会从 192.168.1.20 发到 192.168.1.10这就是最典型的分布式 RPC。而您的代码中 DubboReference 无需修改任何配置只要 ZooKeeper 地址可访问这就是注册中心带来的位置透明性。后续应该做什么后续应该把项目打包部署包括前端页面简单美化使用nginx代理前端网站来访问后端服务。

相关新闻