alibaba / alibaba-rsocket-broker

Alibaba RSocket Broker: Mesh, Streaming & IoT

Home Page:https://alibroker.info

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

broker 可以作为网桥吗 ?network bridge 或 RSocket Bridge

sdack-cloud opened this issue · comments

commented

有这样一个需求:
一台电脑可以接入 100W长链接,如果想要接入更多,需要更多电脑
如果有一个网桥 可以把他们连接起来,从A电脑进来的消息要投送至B电脑的接入者。网桥负责中间转发消息。
broker 可以作为网桥吗??? @linux-china

最好不要这样做,Broker是内部应用相互之间通讯的代理,主要用于服务之间的通讯。 如果是网关或者网桥的场景,最好使用RSocket Gateway,每一个RSocket Gateway支持100W连接,然后多增加几个Gateway服务器就可以,然后这些Gateway再作为普通应用接入到Broker就可以。 对比Broker,Gateway简单不少,最好不要将Broker作为Gateway使用。 参考一下, #196 就是使用Broker IM的接入端,也不建议这样使用。

这个其实就是Gateway和Broker的区别,这个可以在架构设计中找到两者的区别。

commented

从A电脑进来的消息要投送至B电脑的接入者。网桥负责中间转发消息。

RSocket Gateway只是 一台电脑的接入者,A电脑进来的消息要投送至N多台电脑的Gateway然后转发出去 消息需要 Bridge 介入中转。

所有的Gateway (接入者)都要注册至Bridge 和 Broker。Bridge 会知道那台电脑谁(用户)接入了,应该将消息转发给那台电脑的Gateway,Gateway在投送至用户。 Broker 是后面的服务和数据层,用来服务调用。 Bridge 也是信息中转的作用,和Broker很像

RSocket Gateway 现在并没有开源的项目,您能推荐下RSocket Gateway 好的项目吗??
我也是在学习Broker 源码来写一个Bridge

Bridge 这样的设计很缺啊。把所有电脑连接到一起的设计,Bridge 有没有开发计划啊???@linux-china

消息转发这个属于IM的范畴,这个技术已经非常成熟了,每一个用户接入到Gateway,Gateway会通过一个中间存储来保存登录用户的信息的,如用户名/ID, 登录IP,登录时间,接入的Gateway Server等,你发消息的时候,会拿到这些信息然后向指定的Gateway Server服务发送信息的,然后Gateway Server会将消息转发给登录的用户的,这种消息转发是不需要经过Broker的,直接在Gateway集群内部就完成啦,经过Broker反而有性能损失,还要维护那么多的元信息。

Gateway的设计并不复杂,你使用Spring RSocket + WebSocket协议即可。 考虑Gateway的需求各式各样,就一个安全验证,可能都有10几种方式,还有安全审计,还有多点部署等等,业务逻辑耦合非常强,当然也和机房的基础设施耦合,这个还是需要自行开发的。

Slack的架构设计网上都能查到的,下图中的Presence Server就是负责存储用户的登录后的信息的,如下图:

image

其中消息部分的设计如下:

image

简单点的设计可以如下:

  • Gateway Server启动后,对外提供RSocket连接,同时会订阅Kafka中的某一Topic,Gateway Server实例和Topic名称是1:1对应的,你可以创建一批Topic,Gateway Server使用Redis的LPOP拿也可以。 你可以将Kafka理解为上述架构图的Channel Server,就是PUB/SUB的模型。
  • 客户端通过RSocket连接后,会将登陆的信息,用户ID,名称,对应的Kafka topic名称,保存到Redis中。当然用户下线后,redis中的数据也会被删除掉。 这里的Redis其实就是Presence Server,负责保存所有登录用户的状态信息。 当然登录和下线这些也会向特定的topic发送信息,方便其他系统进行处理。
  • 如果你要给某一用户发送信息,客户端就会向其连接的Gateway Server发送一条消息,Gateway Server收到消息后会查一下redis获得目标用户对应的topic名称,然后给该topic发送消息即可
  • Gateway Server收到topic推送的消息后,当然该消息是结构化的,如json,protobuf等,再根据消息中的目标用户ID查找对应的RSocket连接,然后调用一下fireAndForget或者request/Response模型将消息发送出去就可以。 如果目标用户对应的连接没有找到,查找一下Redis获得目标用户的登录信息,然后将该消息转发到新的topic就可以啦,如果还没有找到,发送到一个特殊的topic中就可以啦,然后做离线消息处理。

借助Kafka这类消息系统,聊天消息存储,安全审计,异步存储等都可以搞定。当然你可能要做一下Gateway内部的缓存设计,不用每次都去查找用户ID和Topic的映射关系,如监听用户登录下线事件对应的topic。也不用担心这个路由100%正确 ,即便消息发错啦,Gateway Server收到非自己的消息,也会转发的。 当然我这个只是举例,具体实现细节一定不少,你自己看一下。

Scaling Slack - The Good, the Unexpected, and the Road Ahead: https://www.youtube.com/watch?v=_M-oHxknfnI

commented

网关:Gateway Server (Spring RSocket来做)

网桥:Channel Server(Kafka)

其实Kafka 就是我所说的 network bridge,它把消息分配至各各网关,不用再去写一个network bridge的东西

我理解的对吗 @linux-china

Presence Server: 这个可以使用Redis来做,就是保存登录用户的信息,方便进行消息路由。 其他诸如统计在线用户数,在线用户的分布结构等,这些都可以通过Presence Server获得。

虽然我们是在讨论RSocket,如果是IM的场景,你其实可以选择WebSocket,就是基于长连接的消息的来回发送。 如果你还需要其他一些功能,如客户端到Gateway的RPC通讯,反向通知等,这个场景下,RSocket Gateway其实就是API Gateway的功能。 如果你需要多功能,那么RSocket over WebSocket最合适,如果只是IM的场景,那么WebSocket也是合适的。

commented

RSocket 不是可以选择WebSocket 协议 还是 tcp协议的嘛?
我是想用 RSocket做 IM网络通讯协议
RSocket 在IM场景下 不可以嘛 ???
我看也推出了 rsocket-dart 。可以做 flutter 的SDK @linux-china

考虑到客户端的复杂环境、浏览器支持、防火墙等因素,建议选择WebSocket的。 RSocket当然可以做IM通讯协议,就是RSocket over WebSocket.

commented

Spring RSocket 如何测试单机能达到多少长连接 能给一些建议嘛 @linux-china

这个主要看硬件配置,RSocket底层使用Netty,你可以进行一下测试,一般的服务器,30-50W并发连接完全没有问题。

commented

我在使用 js 连接RSocket 服务器,服务器是websocket协议

let ws = new WebSocket("ws://localhost:7002");

但是连接失败,在网上也很难找到js 浏览器 连接RSocket 的示例
我知道rsocket-js

我想服务端是websocket js 与其连接不是顺其自然吗

我做这方便的尝试是 为了 微信小程序接入做准备
@linux-china

你最好看一下RSocket-JS项目,虽然RSocket-JS很简单,但是还是要知道原理的,不然贸然开发应用,以后可能有问题。 WebSocket接入样例请参考: https://github.com/rsocket/rsocket-js/blob/1.0.x-alpha/packages/rsocket-examples/src/ClientServerRequestStreamExampleWebSocket.ts

如果你想看浏览器到后端的样例,可以参考一下 https://github.com/linux-china/xtermjs-spring-boot-starter

commented

我在使用spring rsocket 和 protobuf 作通信测试

No decoder for io.pivotal.rsocketclient.data.MetaVo$Meta
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
序列化报错

客户端


    @ShellMethod("Login with your username and password.")
    public void login(String u, String p) {
        log.info("Connecting using client ID: {} and username: {}", CLIENT_ID, u);

        this.rsocketRequester = rsocketRequesterBuilder
                .setupRoute("connect")
                .setupData(CLIENT_ID)
                .rsocketStrategies(builder ->
                        {
                            builder.encoder(new ProtobufEncoder(),new SimpleAuthenticationEncoder())
                            .decoder( new ProtobufDecoder());
                        }
                )
                .connectWebSocket(URI.create("ws://localhost:7002"))
                .block();

    @ShellMethod("Send one request. One response will be printed.")
    public void requestResponse() throws InterruptedException {
        if (userIsLoggedIn()) {
            log.info("\nSending one request. Waiting for one response...  request-response");

            MetaVo.Meta.Builder builder = MetaVo.Meta.newBuilder();
            builder.setRemark("你好").setV(5.56).setAppId(888);
            MetaVo.Meta build = builder.build();
            MetaVo.Meta message = this.rsocketRequester
                    .route("toOne")
                    .data(build)
                    .retrieveMono(MetaVo.Meta.class)
                    .block();
            log.info("\nResponse was: {}", message);
        }
    }

服务端

    @MessageMapping("toOne")
    fun toOne(request: MetaVo.Meta): Mono<MetaVo.Meta> {
        return Mono.just(request)
    }

找了一圈人家怎么配置的 也没找到结果。希望您解答
@linux-china

目前Spring RSocket还不支持Protobuf,你使用json先测试一下。

commented

那这两个类是做什么的,支持Http协议
import org.springframework.http.codec.protobuf.ProtobufDecoder;
import org.springframework.http.codec.protobuf.ProtobufEncoder;
@linux-china

Spring RSocket详细的你参考一下 https://docs.spring.io/spring-framework/docs/current/reference/html/rsocket.html 你先不用在意数据序列化,先确保这个流程是可行的,然后到具体的数据序列化,这个都是可以做的。

这个是ProtobufDecoder的,这个你也是可以使用的,但是要求对应的Java对象都是Protobuf Message,然后才能从bytes转换到对应的Protobuf Message对象,详细的你查下文档。

commented

刚刚我做了尝试
将数据已 ByteArray 进行传输 能得到我想要的结果

客户端

MetaVo.Meta.Builder builder = MetaVo.Meta.newBuilder();
            builder.setRemark("你好").setV(3.5);
            MetaVo.Meta build = builder.build();
            MetaVo.Meta message = this.rsocketRequester
                    .route("toOne")
                    .data(build.toByteArray())
                    .retrieveMono(MetaVo.Meta.class)
                    .block();

服务端

    @MessageMapping("toOne")
    fun toOne(request: ByteArray): Mono<Any> {
        log.debug("收到")
        val parseFrom = MetaVo.Meta.parser().parseFrom(request)
        log.debug("收到{}",parseFrom)
        return Mono.just(request)
    }

parseFrom() 方法 提示警告 不适当的阻塞方法调用,那应该怎么使用
@linux-china

这个警告忽略就可以,没有大问题。

commented

val parseFrom = MetaVo.Meta.parser().parseFrom(request)

这个不会阻塞线程吗
@linux-china

commented

val parseFrom = MetaVo.Meta.parser().parseFrom(request)

这个不会阻塞线程吗
@linux-china

Protobuf的序列化和反序列化非常快的,而且ByteArray对应的字节流已经在内存中啦,不用担心这个阻塞。

commented

rsocket-js
使用 rsocket-websocket-client

如何传递 token 信息 建立连接
如spring

org.springframework.security.rsocket.metadata.BearerTokenMetadata
org.springframework.security.rsocket.metadata.UsernamePasswordMetadata

@linux-china

commented

不,我是说 使用 rsocket-websocket-client 如何传递 Bearer {Token}

spring-rsoccket-demo 我看懂了,只是没找到 js 这边如何传递的demo
@linux-china

安全规范 https://github.com/rsocket/rsocket/blob/master/Extensions/Security/Authentication.md 是RSocket Composite Metadata的一部分,在Composite Metadata添加一下即可,RSocket JS已经包含安全相关的metadata https://github.com/rsocket/rsocket-js/tree/1.0.x-alpha/packages/rsocket-composite-metadata/src
如何在Client/Server之间传递composite metadata,请参考:
https://github.com/rsocket/rsocket-js/blob/1.0.x-alpha/packages/rsocket-examples/src/ClientServerCompositeMetadataRouteExample.ts

commented

rsocket-dart 现在可以支持 authentication嘛?????? 我看版本是 0.1.2

我的意思是比较 开箱即用的,像spring 一样封装成对象
rsocket-dart 可以生产了吗??

rsocket-js 的案例很多是 ts的语法,有些看不懂啊

Composite Metadata

我已经引入了 npm i rsocket-composite-metadata

import {
  decodeCompositeMetadata,
  decodeRoutes,
  decodeAuthMetadata,
  encodeCompositeMetadata,
  encodeRoute,
  WellKnownMimeType,
  encodeSimpleAuthMetadata
} from "rsocket-composite-metadata";

我的服务端

    @ConnectMapping("connect")
    fun connect(requester: RSocketRequester, @Payload client: String) {
        requester.rsocket()
            ?.onClose()
            ?.doFirst {
                log.info("Client: {} CONNECTED. Count: {}", client, clients.size)
                clients[client] = requester
                log.info("connected. Count: {}", clients.size)
            }
            ?.doOnError {
                // Warn when channels are closed by clients
                log.warn("Channel to client {} CLOSED. Count: {}", client, clients.size)
                clients[client]?.rsocket()?.dispose()
                log.warn("closed. Count: {}", clients.size)
            }
            ?.doFinally {
                log.warn("Client: {} DISCONNECTED. Count: {}", client, clients.size)
                clients.remove(client)
                log.warn("disconnected Count: {}", clients.size)
            }
            ?.subscribe()


    }

我的服务端 连接 在 connect 。
js 这块怎么写?????

this.connector = new RSocketConnector({
        setup: {
          keepAlive: 120000,
          lifetime: 180000,
          dataMimeType: "application/octet-stream",
          metadataMimeType: MESSAGE_RSOCKET_COMPOSITE_METADATA.string,//message/x.rsocket.composite-metadata.v0
          payload: {
            data: Buffer.from("231211"),
            metadata: encodeSimpleAuthMetadata("user","pass"),
          }
        },
        transport: new WebsocketClientTransport({
          debug: true,
          url: "ws://localhost:7002",
          wsCreator: (url) => new WebSocket(url),
        }),
      });
      this.rsocket = await this.connector.connect();

我也在 github 上 找了 js demo看看。 他们版本 太低了0.0.19 ,当前 1.0.0-alpha.1
使用方式也变了

https://github.com/viglucci/rsocket-js-examples
版本 是0.0.25,好久不更新了

@linux-china