1分钟了解响应式编程 | dubbo框架下响应式官例

作者:Mars酱

声明:本文章由Mars酱编写,部分内容来源于网络,如有疑问请联系本人。

转载:欢迎转载,转载前先请联系我!

前言

上篇搜了一堆概念,拼凑了一些例子,现今我们的应用已经不是单例架构,一般都是分布式微服务架构,微服务架构情况下框架也很多,SpringCloud、Dubbo等等

我的工程是dubbo的,那我们看看Dubbo官方示例给出的响应式编程的例子,毕竟我看Dubbo官文说天然支持流式编程,好了,继续。

Dubbo对流式处理的支持

协议 性能 网关友好 流式通信 多语言支持 编程API 说明
triple 支持,客户端流、服务端流、双向流 支持(Java、Go、Node.js、JavaScript、Rust) Java Interface、Protobuf(IDL) 在多语言兼容、性能、网关、Streaming、gRPC 等方面最均衡的协议实现,官方推荐。
dubbo 不支持 支持(Java、Go) Java Interface 性能最高的私有协议,但前端流量接入、多语言支持等成本较高
rest 不支持 支持 Java Interface rest 协议在前端接入、互通等方面具备最高的灵活性,但对比 rpc 存在性能、弱类型等缺点。注意,rest 在 dubbo3 中仅是 triple 协议的一种发布形式

从官方的文档中找到,Dubbo是支持流式编程的,但是需要使用triple协议,而不是其他协议。

从git上下载Dubbo Samples

bash 复制代码
# 从git上下载 dubbo的官方示例,这是示例的git地址
https://github.com/apache/dubbo-samples.git

下载之后,导入到你的idea中,知道了triple协议支持流式通信,那么从导入好的idea中找到triple的stream相关的代码,如下图:

Dubbo服务端支持的两种流式处理

Dubbo通过triple协议支持了两种流式处理,一种是服务端流,另一种是双向流。

服务端流

首先我们看服务端流的示例代码,代码位置在dubbo-samples-triple-streaming工程中的GreeterImpl这个文件,我抽取了服务端流的方式,如下:

java 复制代码
@Override
public void serverStream(GreeterRequest request, StreamObserver<GreeterReply> responseObserver) {
	LOGGER.info("receive request: {}", request.getName());
	for (int i = 0; i < 10; i++) {
		GreeterReply reply = GreeterReply.newBuilder().setMessage("reply from serverStream. " + i).build();
		responseObserver.onNext(reply);
	}
	responseObserver.onCompleted();
}

可以看到serversStream方法是没有void,没有返回值的,它通过GreeterRequest对象传递参数,然后把业务逻辑数据依次循环写入到StreamObserver对像中。

GreeterRequest对象可以是我们自己定义的业务请求对象,StreamObserver对象是dubbo框架对于流式处理的接口定义,如图:

响应结果被封装在这个接口对象中,实现了流式数据写入到消费者端的业务场景。

双向流

这是双向流的官方示例:

java 复制代码
@Override
public StreamObserver<GreeterRequest> biStream(StreamObserver<GreeterReply> responseObserver) {
	return new StreamObserver<GreeterRequest>() {
		@Override
		public void onNext(GreeterRequest data) {
			GreeterReply resp = GreeterReply.newBuilder().setMessage("reply from biStream " + data.getName()).build();
			responseObserver.onNext(resp);
		}

		@Override
		public void onError(Throwable throwable) {

		}

		@Override
		public void onCompleted() {

		}
	};
}

可以看到,双向流方法 binStream 的参数和返回值都是 StreamObserver 类型。

但需要注意的是,它与我们传统方法定义中参数是请求值、返回值是响应的理解是反过来的,在这里,函数的入参 StreamObserver responseObserver 是响应,跟之前一样,是在业务逻辑中不停的写数据到 回响应中。

这个函数也通过new了一个 StreamObserver 不断的在onNext函数中写入了请求流数据,而且这里 请求流 与 响应流 是独立的,我们在写回响应流数据的过程时,随时可能有请求流到达,对于每个流而言,值都是有序的。

Dubbo客户端的调用示例

dubbo对于两种流的处理方式是不同的调用实现

服务端流的客户端调用

调用 serverStream() 传入能够处理流式响应的 SampleStreamObserver 对象,调用发起后即快速返回,之后流式响应会不停的发送到 SampleStreamObserver 。

java 复制代码
private static void serverStream(Greeter greeter) {
	GreeterRequest request = GreeterRequest.newBuilder().setName("server stream request.").build();
	greeter.serverStream(request, new SampleStreamObserver());
}

// 声名上面调用类的SampleStreamObserver实现
private static class SampleStreamObserver implements StreamObserver<GreeterReply> {

	@Override
	public void onNext(GreeterReply data) {
		LOGGER.info("stream <- reply:{}", data);
	}

	@Override
	public void onError(Throwable throwable) {
		LOGGER.error("stream onError", throwable);
		throwable.printStackTrace();
	}

	@Override
	public void onCompleted() {
		LOGGER.info("stream completed");
	}
}

双向流的客户端调用

java 复制代码
private static void biStream(Greeter greeter) {
	// SampleStreamObserver的定义在 '服务端流的客户端调用示例' 中已经给出
	StreamObserver<GreeterRequest> requestStreamObserver = greeter.biStream(new SampleStreamObserver());
	for (int i = 0; i < 10; i++) {
		GreeterRequest request = GreeterRequest.newBuilder().setName("name-" + i).build();
		requestStreamObserver.onNext(request);
	}
	requestStreamObserver.onCompleted();
}

调用 greeter.biStream() 方法会立即返回一个请求流 requestStreamObserver 对象,同时,需要为方法传入一个能处理响应的 observer 对象new SampleStreamObserver()。

接下来,我们就可以用才刚才返回值中得到的 requestStreamObserver 持续发送请求 requestStreamObserver .onNext(reqeust), 此时,如果有响应返回,则会由 SampleStreamObserver 对象接收处理,

官例好像有问题

其实没有任何问题,只是dubbo支持的是observer的流式处理,这是一种无背压方式的流式处理。背压是一种流控机制 ,dubbo 的 StreamObserver 不提供内置背压支持

  • 它的 onNext 方法是通过官方的示例就知道它属于阅后即焚风格;
  • 调用 onNext 会立即把数据写入网络缓冲区(或本地队列),不会等待消费者处理完成
  • 如果消费者消费得太慢,而 producer 持续高速发送,有没有可能 导致 OOM 或者其他问题?没试过,存疑

这与 Reactive Streams 规范 貌似不同,并没有背压特征,但是RxJava框架不也是支持背压、无背压方式的吗?所以,应该根据自己的场景来选择是否需要背压方式,超时了,下个1分钟看怎么用dubbo处理背压特征的响应式编程吧。

相关推荐
毕设源码-朱学姐11 小时前
【开题答辩全过程】以 日程管理系统为例,包含答辩的问题和答案
java
a努力。11 小时前
京东Java面试被问:双亲委派模型被破坏的场景和原理
java·开发语言·后端·python·面试·linq
小毛驴85012 小时前
Maven同时配置阿里云仓库和私有仓库
java·阿里云·maven
刘975312 小时前
【第25天】25c#今日小结
java·开发语言·c#
不如打代码KK12 小时前
Springboot如何解决跨域问题?
java·spring boot·后端
豆沙沙包?12 小时前
2026年--Lc330-394. 字符串解码(栈)--java版
java·开发语言
蓝程序12 小时前
Spring AI学习 程序接入大模型
java·人工智能·spring
nice_lcj52012 小时前
数据结构之树与二叉树:重点梳理与拓展
java·数据结构
毕设源码-钟学长12 小时前
【开题答辩全过程】以 助学贷款管理系统为例,包含答辩的问题和答案
java
亓才孓12 小时前
任意大小的整数和任意精度的小数的API方法
java