当前位置: 首页 > news >正文

Spring Boot进阶(89):Spring Boot和Zookeeper搭建分布式系统,提高系统可靠性

📣前言


  在当今信息化时代,互联网公司在面对海量访问请求时往往需要采用分布式系统来提高系统的可扩展性和可靠性。分布式系统具有多节点、相互协作的特性,不仅可以提高系统的吞吐量,而且还能在某个节点出现故障时自动切换到其他节点,以保证系统的可靠性。

  本文主要介绍了如何使用Zookeeper作为分布式系统的协调者,并使用Spring Boot和Zookeeper来搭建一个分布式系统。本文首先介绍了Zookeeper的概念和原理,然后详细讲解了如何使用Spring Boot来集成Zookeeper,最后通过一个实际应用场景的案例,展示了如何使用Spring Boot和Zookeeper来搭建分布式系统。这将又会是干货满满的一期,全程无尿点不废话只抓重点教,具有非常好的学习效果,拿好小板凳准备就坐!希望学习的过程中大家认真听好好学,学习的途中有任何不清楚或疑问的地方皆可评论区留言或私信,bug菌将第一时间给予解惑,那么废话不多说,直接开整!Fighting!!

🌊环境说明

开发工具:IDEA 2021.3
JDK版本: JDK 1.8
Spring Boot版本:2.3.1 RELEASE
Maven版本:3.8.2


🏆本文收录于《Spring Boot从入门到精通》,专门攻坚指数提升,2023 年国内最系统+最强(更新中)。

本专栏致力打造最硬核 Spring Boot 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot教程导航帖】,你想学习的都被收集在内,快速投入学习!!两不误。

摘要

  本文主要介绍了如何使用Zookeeper作为分布式系统的协调者,并使用Spring Boot和Zookeeper来搭建一个分布式系统。本文首先介绍了Zookeeper的概念和原理,然后详细讲解了如何使用Spring Boot来集成Zookeeper,最后通过一个实际应用场景的案例,展示了如何使用Spring Boot和Zookeeper来搭建分布式系统。

正文

概述

  Zookeeper是一个分布式的协调者,可以用于在分布式系统中实现分布式应用的协调和管理。Zookeeper采用了类似于文件系统的树形结构,每个节点都可以存储一些数据,同时也可以在节点上注册一些监听器,当节点的数据发生变化时可以触发相应的事件。

  在分布式系统中,通常需要一个协调者来管理各个节点之间的状态和信息,例如:负载均衡、服务发现、配置管理等。在这些应用场景下,Zookeeper可以作为一个分布式协调者来实现。

  同时,Spring Boot是一个开发Web应用程序的框架,它简化了Java应用程序的开发过程,并提供了许多有用的功能,例如:自动配置、热部署、注解等。

搭建Spring Boot应用

  首先,我们先创建个基础的Spring Boot项目,如果还不会点这里,此处就不详细赘述啦。

Spring Boot集成教学

步骤1:引入依赖

在使用Spring Boot集成Zookeeper之前,我们需要在pom.xml文件中引入以下依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>5.1.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>5.1.0</version>
</dependency>

步骤2:创建Zookeeper客户端

在使用Zookeeper之前,我们需要创建一个Zookeeper客户端。可以通过以下方式创建:

@Configuration
public class ZookeeperConfig {@Value("${zookeeper.host}")private String host;@Value("${zookeeper.timeout}")private int timeout;@Beanpublic CuratorFramework curatorFramework() {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(host, timeout, 10000, retryPolicy);curatorFramework.start();return curatorFramework;}
}

步骤3:使用Zookeeper

在使用Zookeeper时,我们需要使用CuratorFramework对象来操作Zookeeper。例如:创建一个节点、获取节点数据、监听节点变化等操作。以下是一些常见的操作:

@Autowired
private CuratorFramework curatorFramework;public void createNode(String path, byte[] data) throws Exception {curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, data);
}public byte[] getNodeData(String path) throws Exception {return curatorFramework.getData().forPath(path);
}public void setData(String path, byte[] data) throws Exception {curatorFramework.setData().forPath(path, data);
}public void addListener(String path, NodeCacheListener listener) throws Exception {NodeCache nodeCache = new NodeCache(curatorFramework, path);nodeCache.getListenable().addListener(listener);nodeCache.start(true);
}

步骤4:启动Spring Boot应用程序

  在完成上述步骤之后,我们可以启动Spring Boot应用程序,并通过浏览器访问http://localhost:8080/来测试程序是否运行正常。

应用场景案例

以下是一个应用场景案例,它演示了如何使用Spring Boot和Zookeeper来搭建一个分布式系统:

案例背景

在这个案例中,我们将实现一个简单的在线聊天室,用户可以在聊天室中发送消息并与其他用户交流。

系统架构

我们将使用分布式系统来搭建这个聊天室,在分布式系统中,每个节点都是相互独立的,并且可以自由地加入或退出系统。

实现步骤

步骤1:创建Zookeeper客户端

  我们需要在程序中创建一个Zookeeper客户端来连接Zookeeper服务器,可以使用CuratorFramework类来实现。具体代码如下:

@Configuration
public class ZookeeperConfig {@Value("${zookeeper.host}")private String host;@Value("${zookeeper.timeout}")private int timeout;@Beanpublic CuratorFramework curatorFramework() {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(host, timeout, 10000, retryPolicy);curatorFramework.start();return curatorFramework;}
}
步骤2:创建节点

我们需要在Zookeeper中创建三个节点:

  1. /message:用于存储聊天消息
  2. /users:用于存储在线用户
  3. /sequence:用于生成唯一的序列号

以下是创建节点的代码:

@PostConstruct
public void init() throws Exception {createNode("/message", "".getBytes());createNode("/users", "".getBytes());createNode("/sequence", "0".getBytes());
}private void createNode(String path, byte[] data) throws Exception {if (curatorFramework.checkExists().forPath(path) == null) {curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, data);}
}
步骤3:处理聊天消息

在聊天室中,当用户发送消息时,我们需要将消息存储到Zookeeper中。具体代码如下:

@RestController
public class ChatController {@Autowiredprivate CuratorFramework curatorFramework;@PostMapping("/message")public void sendMessage(String message) throws Exception {long sequence = getSequence();String path = "/message/message_" + sequence;curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, message.getBytes());}private long getSequence() throws Exception {String path = "/sequence";Stat stat = curatorFramework.setData().withVersion(-1).forPath(path, "1".getBytes());return stat.getVersion();}
}
步骤4:处理在线用户

当用户进入或退出聊天室时,我们需要将他们的信息存储到Zookeeper中。具体代码如下:

@RestController
public class ChatController {@Autowiredprivate CuratorFramework curatorFramework;@PostMapping("/users")public void login(String username) throws Exception {String path = "/users/" + username;curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path);}@DeleteMapping("/users")public void logout(String username) throws Exception {String path = "/users/" + username;curatorFramework.delete().forPath(path);}}
步骤5:监听节点变化

当聊天室中有新消息或用户加入或退出时,我们需要通过监听节点变化来获取最新的聊天消息和在线用户列表。具体代码如下:

@Component
public class ChatListener {@Autowiredprivate CuratorFramework curatorFramework;@Autowiredprivate SimpMessagingTemplate messagingTemplate;@PostConstructpublic void init() throws Exception {addMessageListener();addUserListener();}private void addMessageListener() throws Exception {String path = "/message";NodeCacheListener listener = new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {byte[] data = curatorFramework.getData().forPath(path);String message = new String(data);messagingTemplate.convertAndSend("/topic/messages", message);}};addListener(path, listener);}private void addUserListener() throws Exception {String path = "/users";PathChildrenCacheListener listener = new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {List<String> users = curatorFramework.getChildren().forPath(path);messagingTemplate.convertAndSend("/topic/users", users);}};addListener(path, listener);}private void addListener(String path, CuratorListener listener) throws Exception {PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, path, true);pathChildrenCache.getListenable().addListener(listener);pathChildrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);}}
步骤6:创建WebSocket控制器

我们需要创建一个WebSocket控制器来处理客户端的WebSocket连接请求。具体代码如下:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/ws").withSockJS();}@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {registry.enableSimpleBroker("/topic");}}
步骤7:创建前端页面

最后,我们需要创建一个前端页面来展示聊天室中的消息和在线用户列表。以下是前端页面的代码:

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Chat Room</title><script src="/webjars/jquery/3.6.0/jquery.min.js"></script><script src="/webjars/sockjs-client/1.5.0/dist/sockjs.min.js"></script><script src="/webjars/stomp-websocket/2.3.3/dist/stomp.min.js"></script>
</head>
<body><h1>在线用户列表</h1><ul id="users"></ul><hr><h1>聊天消息</h1><ul id="messages"></ul><input type="text" id="message" placeholder="发送消息"><button id="send">发送</button><script>var stompClient = Stomp.over(new SockJS('/ws'));stompClient.connect({}, function (frame) {console.log('Connected: ' + frame);stompClient.subscribe('/topic/users', function (response) {console.log(response);var users = JSON.parse(response.body);console.log(users);var userHtml = '';for (var i = 0; i < users.length; i++) {userHtml += '<li>' + users[i] + '</li>';}$('#users').html(userHtml);});stompClient.subscribe('/topic/messages', function (response) {console.log(response);var message = response.body;$('#messages').append('<li>' + message + '</li>');});});$('#send').click(function () {var message = $('#message').val();stompClient.send('/app/message', {}, message);});</script>
</body>
</html>

测试步骤

这里提供一个简单的测试用例步骤:

  1. 启动Zookeeper服务;
  2. 创建一个Spring Boot项目,添加Curator和WebSocket的依赖;
  3. 编写ZookeeperConfig类,在其中创建CuratorFramework客户端;
  4. 编写ChatController类,在其中处理聊天消息和在线用户;
  5. 编写ChatListener类,在其中监听节点变化并发送消息到前端;
  6. 编写WebSocketConfig类,启用WebSocket和消息代理;
  7. 编写前端页面,并在其中连接到WebSocket并发送和接收消息;
  8. 启动Spring Boot应用,访问前端页面,在页面中输入用户名并发送消息即可。

具体实现可以参考之上的代码。

小结

  本文介绍了如何使用Spring Boot和Zookeeper来搭建一个分布式系统,并以一个在线聊天室的应用场景为例,演示了如何使用Zookeeper来实现在线用户管理和实时聊天功能。

  在实现过程中,我们使用了Zookeeper来作为分布式协调者,用于管理在线用户和聊天消息;使用了Spring Boot来简化Java应用程序的开发过程,并提供了自动配置和热部署等功能。

总结

  在当今互联网时代,分布式系统已经成为了很多企业必不可少的基础设施。Zookeeper作为一个分布式协调者,可以协助我们实现分布式应用的协调和管理,提高系统的可扩展性和可靠性。同时,Spring Boot作为一个开发Web应用程序的框架,可以简化Java应用程序的开发过程,提高开发效率和代码质量。

  结合Zookeeper和Spring Boot,可以快速地开发出高可靠、高性能的分布式系统,为企业的信息化建设提供有力的支持。

… …

  ok,以上就是我这期的全部内容啦,如果还想学习更多,你可以看看如下的往期热文推荐哦,每天积累一个奇淫小知识,日积月累下去,你一定能成为令人敬仰的大佬。

「赠人玫瑰,手留余香」,咱们下期拜拜~~

🌊 热文推荐

滴~如下推荐【Spring Boot 进阶篇】的学习大纲,请小伙伴们注意查收。

Spring Boot进阶(01):Spring Boot 集成 Redis,实现缓存自由

Spring Boot进阶(02):使用Validation进行参数校验

Spring Boot进阶(03):如何使用MyBatis-Plus实现字段的自动填充

Spring Boot进阶(04):如何使用MyBatis-Plus快速实现自定义sql分页

Spring Boot进阶(05):Spring Boot 整合RabbitMq,实现消息队列服务

Spring Boot进阶(06):Windows10系统搭建 RabbitMq Server 服务端

Spring Boot进阶(07):集成EasyPoi,实现Excel/Word的导入导出

Spring Boot进阶(08):集成EasyPoi,实现Excel/Word携带图片导出

Spring Boot进阶(09):集成EasyPoi,实现Excel文件多sheet导入导出

Spring Boot进阶(10):集成EasyPoi,实现Excel模板导出成PDF文件

Spring Boot进阶(11):Spring Boot 如何实现纯文本转成.csv格式文件?

Spring Boot进阶(12):Spring Boot 如何获取Excel sheet页的数量?

Spring Boot进阶(13):Spring Boot 如何获取@ApiModelProperty(value = “序列号“, name = “uuid“)中的value值name值?

Spring Boot进阶(14):Spring Boot 如何手动连接库并获取指定表结构?一文教会你

Spring Boot进阶(15):根据数据库连接信息指定分页查询表结构信息

Spring Boot进阶(16):Spring Boot 如何通过Redis实现手机号验证码功能?

Spring Boot进阶(17):Spring Boot如何在swagger2中配置header请求头等参数信息

Spring Boot进阶(18):SpringBoot如何使用@Scheduled创建定时任务?

Spring Boot进阶(19):Spring Boot 整合ElasticSearch

Spring Boot进阶(20):配置Jetty容器

Spring Boot进阶(21):配置Undertow容器

Spring Boot进阶(22):Tomcat与Undertow容器性能对比分析

Spring Boot进阶(23):实现文件上传

Spring Boot进阶(24):如何快速实现多文件上传?

Spring Boot进阶(25):文件上传的单元测试怎么写?

Spring Boot进阶(26):Mybatis 中 resultType、resultMap详解及实战教学

Spring Boot进阶(27):Spring Boot 整合 kafka(环境搭建+演示)

Spring Boot进阶(28):Jar包Linux后台启动部署及滚动日志查看,日志输出至实体文件保存

Spring Boot进阶(29):如何正确使用@PathVariable,@RequestParam、@RequestBody等注解?不会我教你,结合Postman演示

Spring Boot进阶(30):@RestController和@Controller 注解使用区别,实战演示

… …

  若想系统完整的从0到1的学习,可以参考这篇专栏总结《2023最新首发,全网最全 Spring Boot 学习宝典(附思维导图)》,本专栏致力打造最硬核 Spring Boot 进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中。欢迎大家订阅持续学习。

  如果想快速定位学习,可以看这篇【教程导航帖】导航目录,你想学习的都被收集在内,快速投入学习!!两不误。

  在入门及进阶之途,我必助你一臂之力,系统性学习,从入门到精通,带你不走弯路,直奔终点;投资自己,永远性价比最高,都这么说了,你还不赶紧来学??

  本文涉及所有源代码,均已上传至GitHub开源,供同学们一对一参考 GitHub传送门,同时,原创开源不易,欢迎给个star🌟,想体验下被🌟的感jio,非常感谢❗

📣文末

我是bug菌,CSDN | 阿里云 | 华为云 | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,掘金 | InfoQ | 51CTO等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

相关文章:

  • 注解配置SpringMVC
  • TypeScript - 枚举类型 -字符型枚举
  • DDOS版-超功能记事本 Ⅲ 8.8源码
  • Kafka-Java四:Spring配置Kafka消费者提交Offset的策略
  • Java架构师信息系统构建
  • 【图结构从入门到应用】图的表示和遍历,图搜索算法详解与示例
  • ubuntu 下的 使用anaconda 环境运行python 项目
  • [C++]——带你学习类和对象
  • C++入门精讲——入门看完这一篇就够了
  • Go学习第十五章——Gin参数绑定bind与验证器
  • c:变参函数:汇编解析;va_list;marco 宏:__VA_ARGS__
  • 数字孪生与智慧城市:开启未来智慧生活
  • 2023CCF中国开源大会 | 麒麟信安作为首批合作伙伴入驻全国信创开源广场
  • 计算机专业毕业设计如何选题、如何规避风险、避免入坑
  • uniapp解决iOS切换语言——原生导航栏buttons文字不生效
  • 【RocksDB】TransactionDB源码分析
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • Netty源码解析1-Buffer
  • Python语法速览与机器学习开发环境搭建
  • Sequelize 中文文档 v4 - Getting started - 入门
  • 翻译--Thinking in React
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 使用putty远程连接linux
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #每日一题合集#牛客JZ23-JZ33
  • #预处理和函数的对比以及条件编译
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (3)选择元素——(17)练习(Exercises)
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .cfg\.dat\.mak(持续补充)
  • .net 反编译_.net反编译的相关问题
  • .NET 设计模式初探
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .Net6使用WebSocket与前端进行通信
  • .NET设计模式(11):组合模式(Composite Pattern)
  • .NET性能优化(文摘)
  • .net中应用SQL缓存(实例使用)
  • [ C++ ] STL---string类的模拟实现
  • [Android] Android ActivityManager
  • [BUUCTF NewStarCTF 2023 公开赛道] week3 crypto/pwn
  • [C/C++]数据结构 深入挖掘环形链表问题
  • [CISCN2019 华东南赛区]Web4
  • [codevs 2822] 爱在心中 【tarjan 算法】
  • [Editor]Unity Editor类常用方法
  • [ERROR] ocp-server-ce-py_script_start_check-4.2.1 RuntimeError: ‘tenant_name‘