Dubbo框架的1个核心设计点

news/2024/11/13 10:41:19/文章来源:https://www.cnblogs.com/mangod/p/18413225

Java领域要说让我最服气的RPC框架当属Dubbo,原因有许多,但是最吸引我的还是它把远程调用这个事情设计得很有艺术。

1、Dubbo优点较多,我只钟情其一

1.1、优点

业内对于微服务之间调用的框架选择较多,主流是Spring Cloud的Rest方式 和 Dubbo方式,我使用Dubbo方式居多。Dubbo工业级可用,稳定又高效,深受各大公司研发同学的喜爱。

Dubbo的优点较多,比如:

  • 高性能:Dubbo 使用的是基于 Netty 的自定义通信协议,提供了高效的二进制数据传输,使得远程服务调用性能大幅提升。
  • 模块化设计:Dubbo 的架构非常模块化,主要由五大核心模块组成:远程调用模块(RPC)、集群模块、负载均衡模块、容错模块和注册中心模块。
  • 每个部件都支持多协议:每个部件都支持多种协议,比如注册中心,支持ZK、Redis、Nacos等等。
  • 负载均衡和容错:Dubbo 提供了多种容错机制,比如失败重试、失败转移等。还支持多种负载均衡,比如随机、轮询、一致性哈希等。
  • 服务注册和发现:Dubbo引入了注册中心的概念,实现了服务的自动注册和发现。
  • SPI 扩展机制:在背八股文场景下,Dubbo被提及最多的就是使用了类似Java的SPI机制,提高了扩展性,这一点仁者见仁智者见智吧。

1.2、钟情其一

但是,Dubbo最吸引人的,半支烟觉得反而倒是它的RPC调用。Dubbo的定位是一个RPC框架,这是它的核心和立足之地,所以Dubbo将RPC的调用过程透明化,使得开发者可以专注于业务逻辑,而不用关注底层通信问题。

一个RPC框架只有聚焦于先做好它的RPC调用过程这个模块,才会有人关注,其余的优点都是在这之后,慢慢迭代而来。

作者将RPC调用的这个过程,抽象成一种协议消息的传输机制,再通过控制好线程的等待和唤醒,来实现远程方法调用。这一设计思路真是美妙,充分体验了作者的智慧。

2、RPC简易示例

学Dubbo,首先就是要学习作者这种设计理念和思路。基于此,来实现一个简易的远程方法调用,将Dubbo的RPC过程简易化。

2.1、示例步骤

简易的RPC过程步骤如下,大致分5步,依旧使用Netty作用Socket通讯工具。

  1. 使用2个Java进程来模拟2个系统之间的调用,A进程 和 B进程。
  2. A进程的某个方法,使用网络请求调用B进程的某个方法。
  3. 然后A进程的方法就处于等待状态。
  4. 等B进程的方法执行完之后,在利用网络通知到A进程。
  5. 然后A进程的方法被唤醒,继续往下执行。

2.2、示例代码

  • B进程作为服务端,启动网络服务
public class BProcessServer {private final int port;public BProcessServer(int port) {this.port = port;}public void start() throws InterruptedException {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new BProcessServerHandler());}});ChannelFuture future = bootstrap.bind(port).sync();System.out.println("B启动了服务,端口号: " + port);future.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void main(String[] args) throws InterruptedException {new BProcessServer(8088).start();}
}
  • B进程接受网络请求参数,反序列化之后,执行对应的方法,再将执行结果返回:
public class BProcessServerHandler extends SimpleChannelInboundHandler<ByteBuf> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {String reqData = msg.toString(CharsetUtil.UTF_8);System.out.println("B进程接受到了请求数据: " + reqData);executeMethod(ctx);}/*** 执行方法** @param ctx* @throws InterruptedException*/private void executeMethod(ChannelHandlerContext ctx) throws InterruptedException {// TODO 将请求消息按照某种规则解析成方法名、方法参数等,其实就是反序列化的过程。System.out.println("对接受的数据做反序列化,然后开始执行 消息体里指定的方法...");// 模拟方法执行Thread.sleep(2000);System.out.println("执行完毕,返回结果...");// 将结果 通知给 A 进程ByteBuf dataByteBuf = ctx.alloc().buffer().writeBytes("Task completed".getBytes(CharsetUtil.UTF_8));ctx.writeAndFlush(dataByteBuf);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}
  • A进程启动Netty客户端,建立与B进程的通信,然后发起远程调用,处于等待状态。
public class AProcessClient {private final String host;private final int port;private final Object lock = new Object();  // 监视器对象public AProcessClient(String host, int port) {this.host = host;this.port = port;}public void start() throws InterruptedException {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new AProcessClientHandler(lock));}});ChannelFuture future = bootstrap.connect(host, port).sync();System.out.println("A进程与B进程建立了通信连接");Channel channel = future.channel();// 发起远程调用callRemoteMethod(channel);channel.closeFuture().sync();} finally {group.shutdownGracefully();}}/*** 执行方法** @param channel* @throws InterruptedException*/private void callRemoteMethod(Channel channel) throws InterruptedException {//TODO 此处需要将调用的方法和参数,按照协议进行序列化。这次暂且省去此过程。System.out.println("A进程将 请求的方法和参数 进行序列化,然后向B进程发起网络调用...");ByteBuf dataByteBuf = channel.alloc().buffer().writeBytes("Start call method".getBytes(CharsetUtil.UTF_8));channel.writeAndFlush(dataByteBuf);// 使用wait等待B进程通知synchronized (lock) {System.out.println("A进程等待B进程的响应...");lock.wait();  // 等待通知}System.out.println("A进程收到了B进程的响应通知,继续往下...");}public static void main(String[] args) throws InterruptedException {new AProcessClient("localhost", 8088).start();}
}
  • A进程接受B进程的响应,同时被唤醒,然后以上lock.wait()以后的代码得以继续执行。
public class AProcessClientHandler extends SimpleChannelInboundHandler<ByteBuf> {private final Object lock;public AProcessClientHandler(Object lock) {this.lock = lock;}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {String resData = msg.toString(CharsetUtil.UTF_8);System.out.println("A进程接受到了响应数据: " + resData);// B 进程任务完成,使用 notify 唤醒等待的线程synchronized (lock) {lock.notify();  // 唤醒 A 进程}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}

3、总结

Dubbo的优秀设计思路有许多,我只钟情其一,那就是RPC的调用过程。以上是一个简易的RPC远程调用的示例,用于理解Dubbo的原理和源码,希望对你有帮助!

本篇完结!欢迎 关注、加V(yclxiao)交流、全网可搜(程序员半支烟)

原文链接:https://mp.weixin.qq.com/s/J0fzDH-iqGnnnjqaXMLs-A

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/796853.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读构建可扩展分布式系统:方法与实践03分布式系统要点

分布式系统要点1. 通信基础 1.1. 每个分布式系统都包含通过网络进行通信的软件组件 1.2. 硬件1.2.1. 全球互联网就是一台异构机器,由不同类型的网络通信通道和设备组成,它们每秒将数百万条消息通过网络传送到预定目的地1.2.2. 对于单个光纤链路,可以提供每秒超过70 Tbps的总…

Windows Server 2025 中文版、英文版下载 (Inside Preview, updated Sep 2024) - 下一代 Windows 11 Server

Windows Server 2025 中文版、英文版下载 (Inside Preview, updated Sep 2024) - 下一代 Windows 11 ServerWindows Server 2025 中文版、英文版下载 (Inside Preview, updated Sep 2024) - 下一代 Windows 11 Server Windows Server 2025 LTSC 正式版发布在即 请访问原文链接:…

国内第三方支付工作原理

国内第三方支付工作原理

信息收集第一波

情境参加了培训的第四次课, 涉及到了几个信息收集的工具, 感觉没有学得很懂, 蒙蒙的, 萌萌的, 很不专业, 一点都不优雅…… 😅😂🤣🙃 😹 🙈🙉🙊 💫💤👉👻 这里是第四课的作业题, 及我的解答. (注: 仅使用本地虚拟机, 10.0.0.154是centos9的IP, 10.0.0.…

软件工程第二次个人作业

这个作业属于哪个课程 软件工程这个作业要求在哪里 作业要求这个作业的目标 了解游戏开发的大致流程学号 052205144项目名称:抓肥羊🐑 github主页链接:poetry-joy (github.com) github作业链接:[软工作业](git_demo/软件工程 at master poetry-joy/git_demo (github.com)…

延迟退休来了,如何应对“老龄化”的自己?

延迟退休终于还是来了,比相像中要来得更快一些。当下的就业环境对毕业生来说已经是很严峻了,这个时候再实行延迟退休,有点雪上加霜的感觉,时机上总有点不太合适。 如果我们注定要在岗位上待更长的时间,以下几点可能需要提前准备。 1、健康的身体 建立良好的生活习惯,坐息…

解决Spring Data JPA Hibernate的N+1问题的最佳方法

最佳方法:定制@NamedEntityGraph、定制查询和定制VO,可以做到按照需要最佳查询,需要注意的地方:定制VO的字段一定要等于或小于实际查询的字段,才不会复制的时候触发N+1查询。 1 问题复现 1.1 项目结构 1.2 entitypackage com.xkzhangsan.jpa.entity;import lombok.Getter;…

全网最适合入门的面向对象编程教程:48 Python函数方法与接口-位置参数、默认参数、可变参数和关键字参数

在 Python 中,函数可以接受多种不同类型的参数,包括位置参数、默认参数、可变参数和关键字参数等,理解这些参数类型对于编写灵活且可维护的代码非常重要。全网最适合入门的面向对象编程教程:48 Python 函数方法与接口-位置参数、默认参数、可变参数和关键字参数摘要: 在 P…

软工作业-个人介绍

一、自我介绍 我是广东工业大学大三的学生,我的爱好是打游戏 二、快速阅读软件工程教材之后的问题 软件工程中的需求分析如何做到全面而准确? 软件设计的原则有哪些,如何在实际项目中灵活运用? 软件测试的方法有哪些,如何确保测试的有效性? 项目管理在软件工程中的重要性…

浙江理工大学24软件技术基础第一次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/rjjc/这个作业的目标 介绍自己并发表对课程学习的期望姓名-学号 李想-2021330301036浙江理工大学24软件技术基础第一次作业 一、自我介绍 (一)、基本信息 大家好!我是22级自动化2班的李想,来自广东。我的爱好是动…

海贼女帝3D打印模型免费分享

链接:https://pan.quark.cn/s/fbe6cb7fd476

碧蓝航线-山城-猫娘3D打印模型免费分享

下载链接:https://pan.quark.cn/s/4c64df8eb54e