领先一步
VMware 提供培训和认证,以加快您的进度。
了解更多时间:大约 15 分钟。
在多样化的微服务世界中,HTTP 是代理间通信的无可争议的领导者。它成熟、完善且无处不在。但在某些情况下,HTTP 请求-响应可能很繁琐。如果您需要超越传统请求-响应的通信模式,例如即发即弃或流式传输怎么办?如果您想双向发送消息怎么办?
使用 HTTP,有一些方法可以实现这一点,但这并非该协议的构建目的。许多解决方案都伴随着额外的权衡或缺点。此外,没有规定说“你应该始终使用 HTTP”,像 AMQP 这样的消息协议已经证明了这一点。因此,了解您的选择很重要,并且偶尔向您的列表中添加一些新技术也很有益。这篇文章就是关于这样一个替代方案——RSocket。
RSocket 是一种新的消息协议,旨在解决一些常见的微服务通信挑战。使用 RSocket,您可以获得一个灵活的协议,该协议可在 TCP 或 WebSockets 上运行。这意味着您可以进行二进制消息而无需转换。您可以获得诸如多路复用、背压、恢复和路由之类的现代控制,并且您可以获得多种消息模式,包括即发即弃、请求-响应和流式传输。RSocket 也是完全响应式的,因此非常适合您的高吞吐量微服务应用程序。早期采用者包括 Netflix、Pivotal、阿里巴巴和 Facebook——它们都是提供可扩展的基于互联网的服务的专家。
在这篇文章中——这是本系列的第一篇文章——您将学习如何开始使用 RSocket。您将熟悉它的工作原理,并体验它的一些强大功能。在本系列结束时,您将 RSocket 添加到您的技能集中,以便下次您确定选项时,您将有更多协议可供选择。
由于请求-响应对于大多数 Web 开发人员来说是熟悉的领域,因此我们将从这种模式开始我们的 RSocket 之旅。请求-响应的语义相当简单明了,您发送一个请求,您会得到一个响应。HTTP 基于这种基本的交互,而且非常常见。
在本教程中,您将了解如何使用 Spring Boot 作为服务器和终端应用程序作为客户端来使用 RSocket 进行请求-响应。
请求-响应只是 Spring 和 RSocket 支持的四种交互模型之一。我们将在以后的文章中介绍其他模型。
按照以下步骤操作时,您会注意到使用 Spring Boot 构建 RSocket 服务器所需的代码量非常少。此处已为您提供代码,但如果您愿意,也可以在几分钟内自己编写代码。
首先,检查您是否已安装以下先决条件
如果您是 Windows 用户,请切换到 Microsoft 的 Windows 子系统 Linux。Microsoft 有关如何执行此操作的说明在此处。
现在,在终端中将下载的项目文件夹设为当前目录
cd spring-rsocket-demo
接下来,将 Toshiaki Maki 编写的优秀的 RSocket 客户端 CLI 下载到已克隆或解压缩代码的 rsocket-server
文件夹中。在其他地方还有一个官方的 RSocket CLI 此处,但 Toshiaki 的 CLI 更易于使用。在终端中,按如下方式下载 JAR 文件
cd rsocket-server
wget -O rsc.jar https://github.com/making/rsc/releases/download/0.4.2/rsc-0.4.2.jar
您稍后将使用此客户端与 RSocket 服务器进行通信,但现在,请通过调用 help 命令来测试它是否正常工作,如下所示
java -jar rsc.jar --help
您应该看到如下所示的输出(我已截断),解释了命令的用法和选项。
usage: rsc Uri [Options]
Non-option arguments:
[String: Uri]
Option Description
------ -----------
--channel Shortcut of --im REQUEST_CHANNEL
-d, --data [String] Data. Use '-' to read data from
...
保持此终端窗口打开,您稍后将需要它。
在您的 IDE 中打开 rsocket-server 项目并检查代码。如您所见,在 Spring Boot 中启动 RSocket 服务器所需的代码量很少。以下是一些重点
在项目的 pom.xml
文件中,您可以看到 Spring Boot RSocket 服务器所需的 <dependencies>
。使用 Spring Boot 版本 2.2.5.RELEASE
,因为在撰写本文时,此版本具有最成熟的 RSocket 功能。该项目还依赖于 lombok
和 spring-boot-starter-rsocket
库。Lombok 为 Java 数据类添加了构造函数、getter、setter 和 equals,并且还简化了对日志等内容的访问。RSocket 的 Spring Boot Starter 将 RSocket 与 Spring Boot 集成,并在运行时自动为您配置一些 RSocket 基础结构。
在 application.properties
文件中,RSocket 服务器的 TCP 端口设置为 7000
,并且 Spring Boot 的延迟初始化功能已启用。
spring.rsocket.server.port=7000
spring.main.lazy-initialization=true
第一个需要详细查看的类称为 Message.java
。此 Lombok @Data
类用于建模客户端和服务器之间(或您喜欢的“请求者”和“响应者”)的请求和响应消息。该类如下所示……
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
private String origin;
private String interaction;
private long index;
private long created = Instant.now().getEpochSecond();
public Message(String origin, String interaction) {
this.origin = origin;
this.interaction = interaction;
this.index = 0;
}
public Message(String origin, String interaction, long index) {
this.origin = origin;
this.interaction = interaction;
this.index = index;
}
}
使用此类,您可以说明消息的来源 (origin
)、它打算使用的消息传递样式 (interaction
) 以及消息在一个消息序列中的序列号 (index
)。Lombok 通过提供构造函数、getter、setter、toString 和 hashcode 实现来简化代码。
RSocket 服务器控制器代码可以在RSocketController.java
文件中找到。此类被注解为 Spring 的@Controller
,这意味着它声明了服务端点——在本例中是 RSocket 端点。
@Controller
public class RSocketController {
@MessageMapping("request-response")
Message requestResponse(Message request) {
log.info("Received request-response request: {}", request);
// create a single Message and return it
return new Message(SERVER, RESPONSE);
}
}
在类中,有一个名为requestResponse()
的方法,它接受单个Message
对象(请求)并返回单个Message
对象(响应)。
你会注意到,这个requestResponse()
方法用@MessageMapping("request-response")
注解修饰。此注解声明任何元数据包含 RSocket 路由request-response
的消息都应由此方法处理。稍后在从客户端发送请求消息时,将使用此路由。
你注意到这与 Spring 的 REST 控制器略有不同吗?对于 REST 控制器,使用类似
/hello
的 URL 路径映射将 HTTP 调用与其处理程序方法关联。
代码部分就到这里。让我们试试看。
保持现有终端窗口打开,在第二个终端窗口中,将rsocket-server
文件夹设置为当前目录。然后使用以下命令构建并运行 RSocket 服务器:
./mvnw clean package spring-boot:run -DskipTests=true
或者,如果您愿意,也可以使用 Java IDE 中的“构建”和“运行”命令。
接下来,您将使用在步骤 1 中下载和测试的 RSocket 客户端rsc.jar
向正在运行的服务器发送消息。返回到您拥有--help
文本的原始终端窗口,并发出以下命令:
java -jar rsc.jar --debug --request --data "{\"origin\":\"Client\",\"interaction\":\"Request\"}" --route request-response tcp://127.0.0.1:7000
你会注意到,该命令声明了一个 RSocket 消息路由(这是通过添加--route
选项并指定路由名称来实现的)。在本例中,路由是request-response
,它与RSocketController.java
中请求响应处理程序方法中声明的@MessageMapping
匹配。
命令运行时,您将在终端窗口中看到一些调试信息,解释请求响应交互期间发生的情况。它看起来像这样:
2020-02-27 11:20:21.806 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : sending ->
Frame => Stream ID: 1 Type: REQUEST_RESPONSE Flags: 0b100000000 Length: 69
Metadata:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 10 72 65 71 75 65 73 74 2d 72 65 73 70 6f 6e 73 |.request-respons|
|00000010| 65 |e |
+--------+-------------------------------------------------+----------------+
Data:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 43 6c 69 65 6e |{"origin":"Clien|
|00000010| 74 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |t","interaction"|
|00000020| 3a 22 52 65 71 75 65 73 74 22 7d |:"Request"} |
+--------+-------------------------------------------------+----------------+
2020-02-27 11:20:21.927 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : receiving ->
Frame => Stream ID: 1 Type: NEXT_COMPLETE Flags: 0b1100000 Length: 81
Data:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 53 65 72 76 65 |{"origin":"Serve|
|00000010| 72 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |r","interaction"|
|00000020| 3a 22 52 65 73 70 6f 6e 73 65 22 2c 22 69 6e 64 |:"Response","ind|
|00000030| 65 78 22 3a 30 2c 22 63 72 65 61 74 65 64 22 3a |ex":0,"created":|
|00000040| 31 35 38 32 38 30 32 34 32 31 7d |1582802421} |
+--------+-------------------------------------------------+----------------+
{"origin":"Server","interaction":"Response","index":0,"created":1582802421}
您看到的调试输出分为三个“消息帧”。第一个消息帧标记为Metadata
。在本例中,它显示发送到服务器的路由元数据 (request-response
)。第二个帧显示客户端发送到服务器的Data
消息(一个 JSON 字符串)。第三个帧显示服务器返回给客户端的响应消息(也是一个 JSON 字符串)。
在最后一行,您可以看到单独打印的来自服务器的 JSON 格式的响应,确认我们的命令消息已成功接收并被服务器确认。
{"origin":"Server","interaction":"Response","index":0,"created":1582802421}
恭喜!你完成了。您刚刚使用 RSocket 发送了请求响应消息。您现在可以通过按终端窗口中的Ctrl-C
或关闭它来停止 RSocket 服务器。如果您使用 IDE 运行 RSocket 服务器,则可以按照通常的方式在 IDE 中停止该进程。
您下载的 RSocket rsc
客户端使用 RSocket 消息传递协议向RSocketController
发送请求消息。消息通过 TCP 发送到服务器正在等待的地址tcp://127.0.0.1:7000
。
路由指令在第一个消息帧中发送。此路由指令使用 CLI 客户端的--route
选项设置,并设置为request-response
。Spring 使用此路由信息来选择要调用的正确的@MessageMapping
端点,在本例中为requestResponse(Message request)
方法。然后,该方法使用它自己的消息进行响应。CLI 客户端将整个交互作为一系列消息帧打印在终端窗口中。
如果您按照步骤操作,您将看到使用 Spring Boot 编写简单的 RSocket 服务器是多么容易。您检查了所需的 Java 代码,然后在本地启动了 Spring Boot 服务器。然后,您向 RSocket 服务器发送消息并观察响应。您还了解了如何使用 RSocket 消息路由功能在 Spring 中路由 RSocket 消息。在下一篇文章中,您将学习如何使用 Spring Boot 开始构建您自己的 RSocket 客户端。