当前位置: 首页 > 后端技术 > Java

Spring官方RSocketBroker0.3.0发布:快速搭建你的RSocket架构

时间:2023-04-01 13:49:34 Java

简介:Spring官方RSocketBroker其实已经开发了很久。我以为它会和SpringCloud2021.0一起发布,但是并没有发生。不过SpringRSocketBroker已经发布了最新的0.3版本。虽然它仍然是预览版,但目前已经可用。考虑到官方还没有提供相应的文档,大家想要上手Demo还是比较困难的,所以这篇文章就是为了帮助大家快速上手SpringRSocketBroker,同时分析RSocketBroker的特点。作者|雷娟来源|阿里技术公众号Spring官方的RSocketBroker其实已经开发很久了。我以为它会和SpringCloud2021.0一起发布,但是并没有发生。不过SpringRSocketBroker已经发布了最新的0.3版本。虽然它仍然是预览版,但目前已经可用。考虑到官方还没有提供相应的文档,大家想要上手Demo还是比较困难的,所以这篇文章就是为了帮助大家快速上手SpringRSocketBroker,同时分析RSocketBroker的特点。一、SpringRSocketBroker架构我们先来看一下SpringRSocketBroker的架构图,如下:RSocketBroker对外提供集群服务,主要服务是应用注册和RSocket请求转发。集群中的每个Broker都维护着一个统一的全局路由表。RSocketBroker有两个监听端口:8001端口主要负责对外提供RSocket服务,比如申请到Brokers之间的长连接,然后在长连接上发送和接收RSocket请求。7001端口主要负责集群内Broker节点之间的通信,比如同步应用访问的元数据信息,保证全局服务路由表的一致性,还包括Broker之间的请求转发。当然,Brokers之间的通信协议还是RSocket。服务应用在与Broker建立连接时,会向Broker发送一些基本信息,对应的属性主要包括:路由节点ID(routeId)、服务名称(service-name)、标签(tags)。路由节点ID(routeId):这是应用于代理创建的持久连接的唯一标识符。它通常是UUID。当然,也可以由用户指定。连接的唯一性会让每个Broker集群的全局路由表的处理变得容易很多。注意routeId是长连接的标识,不是应用程序的标识。应用程序的标识符由标签标识。如果应用程序与代理创建两个持久连接,则有两个不同的routeId。当然,在这种情况下,每个连接都可以提供不同的服务名称。服务名称:这实际上是服务的DNS名称。如果其他应用程序要调用该应用程序提供的RSocket服务,则需要指定服务名称。虽然SpringRSocket提供了messageMapping,但是映射键是应用内部的,不能保证全局唯一。只有ServiceName+RSocketMappingKey才能定位到指定的服务。这符合http的原则:MappingKey类似于HTTPPath,ServiceName类似于域名。Label:Label用于标识应用程序提供的RSocket服务。当然,RSocketBroker规范也提供了一些默认的标签,比如InstanceName、ClusterName、Region、MajorVersion等,标签不仅仅是服务的元信息,还可以参与服务路由。比如可以设置服务版本、集群名称等,之前开发中比较难的定向路由可以通过标签轻松解决。比如你可以给服务打上InstanceName=app-leijuan的标签,然后在调用开发者的时候设置InsanceName。用户启动的服务实例。您不必担心基于标签的路由的性能。背后有RoaringBitMap支持,速度很快。应用程序可以向集群中的一个或多个RSocketBroker节点注册,这取决于BrokerClient的配置,我们稍后会讲到。注意:ServiceName不要只理解为JavaInterface的全称,比如com.example.user.UserService。当一个应用有多个这样的Java服务时,处理起来会很麻烦。实际上,serviceName主要用于请求路由。例如,一个服务应用包括多个服务接口,如UerService、UserExtraService。您可以将ServiceName设置为com.example.user。当然,您必须确保ServiceName是唯一的。原来的RSocket路由key调整为UserService.findUserById的Interfacename+Methodname方法,没有问题。当应用在Broker上注册后,如果应用想调用某个RSocket服务,只需要根据ServiceName+Routingkey向Broker发起RSocket调用请求,Broker就会找到服务提供者根据内部全局路由表。服务节点(RouteId),然后将请求转发给对应的服务节点,服务节点处理后返回响应给Broker,Broker返回响应给调用者。如果当前Broker节点上没有对应的服务路由访问,Broker会将请求转发给有服务节点的Broker,也就是请求转发,然后将Broker处理后的结果返回给调用者。可能有同学会问,可能会出现调用链死循环的问题。比如broker1把请求转发给broker3,broker3上的服务突然下线了。Broker3可能会发回给Broker1,然后broker1再找其他broker发送?这种情况不会发生。broker会同步申请线上线下信息,所以每个Broker维护着一个集群统一的全局路由表,所以broker1将消息转发给broker2,broker2必须有对应服务的路由连接。即使broker2出现紧急情况,服务对应的路由没有了,也会和服务一起转发给broker。当然,如果没有找到,此时请求会被broker持有,超时后会返回错误。两个SpringRSocketBroker项目示例接下来,我们将看一个真实的开发示例,三个应用程序:一个BrokerServer、一个服务提供者和一个服务调用者。SpringRSocketBroker对应的开发包已经提交到Maven仓库,可以在文末链接查看。1RSocketBrokerServerRSocketBrokerServer是一个标准的SpringBoot应用,只需要在SpringBoot应用中添加如下依赖:然后在application.yaml文件中添加如下配置:然后启动SpringBoot应用,Broker就会启动并监听7001和8001端口。可能有同学会问,为什么不提供一个独立的应用来启动RSocketBroker呢?这可能与SpringCloud项目的出发点有关。像SpringConfigServer和RegistryServer一样,它们都是嵌入在应用程序中的。主要是方便开发者自定义Broker功能,比如添加WebConsole、对接Ops系统等,灵活性会有所提升。很高。2RSocketServiceProvider接下来,我们将创建一个SpringBoot应用,对外提供RSocket服务。首先添加如下依赖:spring-boot-starter-rsocket是标准的,方便SpringBoot应用集成RSocket。另一个是rsocket-broker-client-spring,这个是BrokerSpringClient,负责完成与RSocketBroker的对接。然后在服务应用的application.yaml中添加如下BrokerClient配置。此处应解释服务名称。推荐使用上面提到的DNS命名方式,保证服务名称不会冲突。接下来是broker的地址列表,如下:接下来我们要写一个RSocket服务,就是标准的SpringRSocket,代码如下:然后我们启动服务申请,我们会在RSocketBroker的日志输出注册到Broker的信息,这样RSocket服务就完成了在Broker上的注册。3RSocketServiceConsumer接下来,我们需要创建一个应用程序来调用RSocket服务。和服务应用一样,添加同样的依赖。由于应用不对外提供RSocket服务,可以将service-name调整为Namespace+applicationname。是的,主要是不要和其他应用重名,如下:接下来就是写一个WebController来访问RSocket服务,只要注入BrokerRSocketRequesterBean,然后调用RSocket服务即可。这个类似于SpringRSocket的RSocketRequester的使用,代码如下:启动应用后,可以使用curl命令进行测试,可以看到熟悉的Helloping输出。你可能认为这个客户端调用比较原始。其实你只需要集成spring-retrosocket,然后就是你熟悉的Java接口。样例如下:关于SpringRSocketBroker的三点思考1RSocketBroker的特点SpringRSocketBroker已经开发了很长时间了是的,开发人员是SpringCloud团队的成员,Oleh在Reactive和RSocket方面非常有经验,Spencer是也是SpringCloud的核心架构师。Spencer在几个会议场合都谈到了RSocket给SpringCloud带来的变化,完全是颠覆性的。从上面的应用例子中,你也可以看到,不说Reactive的全异步性能,你不再需要服务注册,也不需要在本地启动应答端口。介入Broker转发后,各种云混杂的服务可以通过Broker进行相互调用。关于RSocketBroker的优点,SpringRSocketBroker有相应的说明,如下:路由转发用于通过broker在两个RSocket连接之间转发RSocket请求。在某些情况下,客户端和服务器之间的点对点交互就足够了,在企业环境中,将客户端和服务器彼此解耦是很有用的。为什么需要解耦的一些示例包括蓝/绿部署、负载平衡、A/B测试、功能切换等。此外,提供中介有助于提高安全性和可扩展性。最后,通过负载均衡、路由和QoS,可以实现比直接连接更好的整体应用延迟和吞吐量。2可能有同学对RSocketBroker中直接通信的解决方案有疑问。会有一定的性能损失。我的应用QPS很高,应该不会有延迟。没关系,还记得服务应用中添加了spring-boot-starter-rsocket依赖吗?我们只需要在application.yaml中添加如下配置项,开启RSocket服务监听端口,然后传入RSocketBroker提供的meta信息,然后我们使用RSocketRequester创建到目标服务的连接。有一些工作量,但是已经很小了,我们只需要使用reactor-pool自动管理直连的连接池即可。3RSocketBroker请求等待SpringRSocketBroker还有一个特性就是服务在线延迟支持。举个例子,假设在线上App-1和Service-1都正常运行,突然Service-1的所有实例都离线了。此时app-1发出的请求找不到目标节点。这个时候怎么办?处理?拒绝请求,立即返回失败:这就是我们常说的快速失败设计,在企业架构设计中经常用到。如果你使用同步通信和线程池模式,你基本上不得不使用这种设计,否则长期的线程阻塞会立即让你的服务无法响应请求。等待服务上线:Broker先保留(hold)请求,然后等待服务上线,再转发给在线服务。这种设计有时非常有用。比如在FaaS场景下,功能的存在已经在Gateway上验证过了。目前功能只是下线,触发功能上线然后请求等待即可。另外还有网络抖动的问题,会导致连接中断。这时候你也可以选择等待服务上线。另一个场景是服务发布。例如,长尾服务只有一个实例。只要能在3-5秒内重启应用,break就可以帮你hold住此时的请求,然后配合客户端的retry,即使只有一个instance也不会中断服务。比如在K8S中,把应用的图片设置为last,然后设置为获取最新,这样一个redploy按钮就可以了。当然,这个请求的等待时间不是无限的。您可以设置超时并返回错误。回到上面的场景,此时Broker-1会hold住请求。当service-1上线后,请求会立即转发到上线的节点进行处理。与同步通信不同,异步等待对Reactive系统没有系统压力,所以等待服务上线是没有问题的。当然,至于那种模式,大家可以根据实际的技术需求来选择。RSocketBroker支持这两种模式。4消息广播模型SpringRSocketBroker也支持消息广播,即将RSocket请求转发给一批服务节点。消息广播主要包括以下几种模型:fireAndForget模型:针对配置推送场景,只需要向service-name对应的服务列表发送配置更新请求即可。requestResponse模型:向多个服务发送请求,然后将第一个响应的响应返回给调用者,不管响应的结果是成功还是失败,这个类似于JavaScript的Promise.race()。Promise.race()的特性貌似没有太多的业务场景。为了方便理解,这里加了一个超时时间,转换为:“尽快在指定时间内返回正确的结果”。比如在数据同步场景下,数据会同步到多台备份服务器,但是由于各种原因,备份服务器上的数据同步可能会延迟或者丢失,所以我从多台备份服务器查询数据,一致认为如果备份服务器上没有这些数据,则在超时1秒后返回异常,以便以最快的速度从备份服务器集群中获取正确的数据。当然,在实际架构中,我们会加一层缓存支持,避免多个服务同时请求,浪费更多的资源。requestStream模型:向多个服务方发送请求,然后聚合返回的流,再将合并后的消息流返回给调用方。它在监控场景中非常有用。您希望每个服务或应用程序在5分钟内报告日志,然后进行统计。这非常有帮助。通道模型:不断向多个服务方的通道发送信息,然后聚合发送的信息。如果你有多个规范要发出来,可以使用这个模型,然后在每个应用上汇总指定应用的响应结果。从以上几款机型来看,基本可以覆盖很多播出需求。如果公司要你搭建一个配置推送的configserver,借助RSocketBroker分分钟搞定吗?借助RSocketBroker+Agent完成运维操作、日志收集等不麻烦。在Prometheus的metrics定时采集场景中,只需要发送一条命令就可以采集到所有机器上的metrics,这比向每个节点发送HTTP请求要简单的多。5Gateway和Broker网关设计大多采用主动连接方式,即网关主动连接上游服务的代理方式。当然,要连接上游服务,还需要用到服务注册与发现、智能DNS等,原理就不赘述了。Broker架构采用被动模式,即等待服务连接到Broker,即当服务就绪后,主动连接到Broker即可,然后基于与服务之间建立的长连接应用程序和代理,请求被转发。与Gateway架构相比,Broker模型要简单的多。内部不需要管理上游服务的连接池,不需要服务注册和发现。当然,对网络连通性没有特殊要求,也适用于混合云场景。RSocketBroker虽然是基于RSocket协议的,但是也可以通过Bridge桥接来支持各种协议。例如RSocketHTTPBridge可以扩展支持HTTP访问。6嵌入式RSocketBroker回答上一个问题,RSocketBroker是应用嵌入的,需要添加相应的依赖和配置,然后启动相应的应用,这个类似于SpringConfigServer等,主要是为了方便开发人员扩展Broker的相应功能并与其他系统集成。结合前面介绍的RSocketBroker的特点,我们可以通过嵌入RSocketBroker来实现一些典型的业务场景:Config/RegistryServer:由于应用已经和Broker建立了长连接,所以元信息也发送给Broker,所以RegistryServer会水到渠成。RSocketBroker支持各种消息广播模型,ConfigServer基本就绪。单个应用的配置推送是基于独立标签推送和基于ServiceName的整体推送,都没有问题。Webconsole:嵌入Broker后,开发一个webconsole,对于SpringBoot来说非常简单。DataGateway:如果要做一个DataGateway对外提供数据访问服务,所有的DataWorker节点都连接到Broker上,然后由Broker对外提供服务。Ops系统集成:这可以使用SpringBoot进行集成。其他的,比如接入应用的健康检查等,只需要向应用发送消息即可。应用和broker优雅上线和下线:通过推送broker的配置信息,应用可以连接新的broker节点,完成brokers集群的上线和下线。应用的上下线只需要在Broker集群中发送ROUTE_REMOVE消息,应用3-5天后即可下线。7SpringRSocketBrokerClient目前RSocketBroker的客户端SDK主要有Java和Node.js,其他语言的BrokerClientSDK大家不用担心。BrokerClient只是在RSocketSDK的CompositeMetadata中新增了一个message/x.rsocket.broker.frame.v0Metadata规范,借助RSocket多语言SDK,可以快速对接主流语言开发的应用给经纪人。四小结最后,有同学问RSocket现在成熟了吗?在Spring生态中,已经很成熟了。RSocketJavaSDK由Spring团队开发。SpringRSocket提供了RSocket和Spring的集成。SpringBoot有一个内置的rsocket-starter。SpringCloudFunction还添加了RSocket支持。考虑到Java开发者的习惯,还提供了spring-retrosocket。其他的Spring产品基本都支持Reactive,所以可以通过Reactive来对接。可以说RSocket的外设都已经准备好了,大家都在等待RSocketBroker的出现,这样集成和部署会更容易。另外,现在的各种服务,比如RESTAPI、GraphQL或者RPC框架,迁移到RSocket是不是很麻烦?如果用Spring来体现,就是加一个@MessageMapping的东西,然后就可以通过RSocket来访问这些服务了。对于Dubbo/HSF服务,在Interface中添加spring-retrosocket提供的Annotation,即可通过RSocket协议访问这些服务。RESTAPI可以在Controller的基础上添加@MessageMapping。至于GraphQL,不需要调整,只需要增加一个新的GraphqlController连接到GraphQL的底层服务即可。就目前的SpringRSocketBroker特性来说,对于一个中型企业来说,可以说不需要做任何调整,完全可以胜任。这是Spring配置服务器。SpringRegistryServer和SpringCloudGateway的定位是一样的。至于SpringCloud团队一直在讲RSocket对SpringCloud的影响和开发经验,相信看完这里你会有自己的判断。但还是那句老话:“天下有伯乐,后有千里马。千里马常有,伯乐不常有”。原文链接本文为阿里云原创内容,未经许可不得转载。