apache / rocketmq

Apache RocketMQ is a cloud native messaging and streaming platform, making it simple to build event-driven applications.
https://rocketmq.apache.org/
Apache License 2.0
21.25k stars 11.7k forks source link

[Bug] proxy local mode send message failed #8904

Open VictoryAnn opened 1 week ago

VictoryAnn commented 1 week ago

Before Creating the Bug Report

Runtime platform environment

windows11

RocketMQ version

5.3.1

JDK Version

1.8

Describe the Bug

本地部署了两个local proxy,proxy1,proxy2,当作两个分片,其中proxy1创建topic: 1a,另外一个proxy2创建topic: 2b,客户端地址配置两个proxy的地址,写其中一个topic,比如 1a ,可能会失败,当请求到的proxy2的时候,客户端会报错,获取topicroute失败,导致无法发送消息。

Steps to Reproduce

image image

What Did You Expect to See?

正常应该能获取到topicRoute,因为proxy获取路由是从nameserver获取的。

What Did You See Instead?

客户端获取路由失败,终止发送消息。

Additional Context

No response

dyrnq commented 1 week ago

由于 Local 模式下 Proxy 和 Broker 是同进程部署,Proxy本身无状态,因此主要的集群配置仍然以 Broker 为基础进行即可。参考

那么两个broker是什么关系啊?

VictoryAnn commented 1 week ago

由于 Local 模式下 Proxy 和 Broker 是同进程部署,Proxy本身无状态,因此主要的集群配置仍然以 Broker 为基础进行即可。参考

那么两个broker是什么关系啊?

考虑local模式下,broker 可能会扩容,broker 扩容后有多个分片,然后创建topic可以指定broker ,就会出现现在这种情况,这个场景是预期内的吗?

dyrnq commented 1 week ago

Proxy本身无状态的,确实如此啊

VictoryAnn commented 1 week ago

所以,local 模式下,只能本地proxy 访问本地的broker 吗?我看源码proxy 是从nameserver 获取topic路由,理论上是可以转发到其他切片上?

dyrnq commented 1 week ago

不确定local模式下会不会连上namesrv,试下从broker剥离分开部署proxy,因为单独部署proxy会配置namesrvAddr这个参数

dyrnq commented 1 week ago

看以上2图,能看出点端倪来

VictoryAnn commented 6 days ago

看以上2图,能看出点端倪来

这个图有点疑问,就是client需要先获取所有topic路由,用了proxy和broker 同一个进程的话,获取到的路由地址会被proxy替换成proxy的端口,然后根据对应topic所在的proxy,客户端会选择对应的proxy地址去send message。但是现状看起来是客户端获取topic路由的时候,由于topic不在当前broker上,导致路由信息返回的message type 为 0,客户端获取不到topic路由。 image

dyrnq commented 6 days ago

确实如此了,那得要求client自行判断了

VictoryAnn commented 6 days ago

那现在的问题就是,客户端从proxy获取路由报错,Message type is not specified,是不是proxy提供的获取路由接口存在问题?期望是,proxy会返回全量的topicRoute,并且返回内容可以被客户端正确解析。

dyrnq commented 6 days ago

那现在的问题就是,客户端从proxy获取路由报错,Message type is not specified,是不是proxy提供的获取路由接口存在问题?期望是,proxy会返回全量的topicRoute,并且返回内容可以被客户端正确解析。

这样比较好

dyrnq commented 6 days ago

https://rocketmq.io/course/deploy/rocketmq_learning-gvr7dx_awbbpb_ogr2blaw8vy3tv14/?spm=0.29160081.0.0.630d5342Dzuczv#33-proxy-%E6%9C%AC%E5%9C%B0%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F

根据以下图片,即使是Local也像是路由了

这是图片

dyrnq commented 6 days ago

Caused by: java.lang.IllegalArgumentException: Message type is not specified also see https://github.com/apache/rocketmq/issues/8546

dyrnq commented 5 days ago

对比以上代码,发现LocalMetadataService确实没有通过Namesrv请求路由信息,你是从哪里看到过Local模式有能获取路由信息的表述吗? @VictoryAnn

VictoryAnn commented 5 days ago

对比以上代码,发现LocalMetadataService确实没有通过Namesrv请求路由信息,你是从哪里看到过Local模式有能获取路由信息的表述吗? @VictoryAnn 是获取topic路由的接口。getTopicRouteForProxy

dyrnq commented 5 days ago

嗯,对比了下这俩类的getTopicRouteForProxy方法 唯一的区别就是grpcPort和requestHostAndPortList

return new ProxyTopicRouteData(topicRouteData, grpcPort); // grpcPort是不带IP的啊,他过不去另外的机器啊
return new ProxyTopicRouteData(topicRouteData, requestHostAndPortList);
VictoryAnn commented 5 days ago

我看是从这里cache获取的,cache是从nameserver获取的,proxy只是替换了端口(这里也存疑,cluster部署可能端口都是一致的,不会有问题。如果像local部署,不同的代理端口不同是不是也有问题?),不需要去访问其他机器。 image

dyrnq commented 5 days ago

grpcPort等同于仅仅包含了一个元素的List<Address>,所以相当于又过滤了?

dyrnq commented 5 days ago

还是把proxy从 broker拆分部署吧,这个是没有问题的。入口不从namesrv,元信息就获取不到,local模式怪怪的。

VictoryAnn commented 5 days ago

还是把proxy从 broker拆分部署吧,这个是没有问题的。入口不从namesrv,元信息就获取不到,local模式怪怪的。

local这块是感觉怪怪的,还有一个疑问点,local部署下,如果client不去获取topicRoute,直接sendmessage proxy是不是会自己转到其他的proxy,那这样client似乎没必要获取topicRoute?尽管是cluster,客户端连代理的话,有必要获取topicRoute吗?这是为了兼容nameserver的访问方式吗,还是有其他考量?

dyrnq commented 5 days ago

第一个回答不了(非官方人员:( ) 第二个(作为用户)感觉有必要,毕竟proxy和namesrv类似的入口能力,像你这样划分topic的话,确实proxy需要知道topic具体落地到那个broker上,有点类似nginx的动态配置,比如/hello --->upstream 到后端,那么后端必须得能承接 /hello的访问,所以不管是namesrv或者proxy 都得做到这个匹配能力,不然用户得自己配置(提供配置入口,感觉也没必要)?

VictoryAnn commented 5 days ago

个人感觉,topic路由相关的应该在proxy内部做掉,proxy的角色也是对外屏蔽掉broker和nameserver,proxy外层加负载均衡即可。

dyrnq commented 5 days ago

嗯,唯一的区分就是local Proxy怎么定义了,按道理这里的local proxy的这个叫法有点让人误解,如果要是叫 broker 提供grpc协议入口会更合适。

即这个broker提供grpc协议又提供remoting协议。

这个和grpc的这个提供能力的叫法有关系,分离部署就叫proxy,合并启动就叫只负责自个的grpc。

dyrnq commented 5 days ago

所以我怀疑local proxy 是用 grpc over remoting 替代了一个假设的存在(即原生的grpc能力)

VictoryAnn commented 5 days ago

嗯,唯一的区分就是local Proxy怎么定义了,按道理这里的local proxy的这个叫法有点让人误解,如果要是叫 broker 提供grpc协议入口会更合适。

即这个broker提供grpc协议又提供remoting协议。

这个和grpc的这个提供能力的叫法有关系,分离部署就叫proxy,合并启动就叫只负责自个的grpc。

赞同,所以提供local这种部署模式 目的有点模糊,官方的资料给的都是跟cluster部署没什么区别,主要可以降低延迟,但实际分析下来,又给人感觉local仅仅是broker的替身。

dyrnq commented 5 days ago

嗯,唯一的区分就是local Proxy怎么定义了,按道理这里的local proxy的这个叫法有点让人误解,如果要是叫 broker 提供grpc协议入口会更合适。 即这个broker提供grpc协议又提供remoting协议。 这个和grpc的这个提供能力的叫法有关系,分离部署就叫proxy,合并启动就叫只负责自个的grpc。

赞同,所以提供local这种部署模式 目的有点模糊,官方的资料给的都是跟cluster部署没什么区别,主要可以降低延迟,但实际分析下来,又给人感觉local仅仅是broker的替身。

如果local proxy 等同于只给broker提供grpc的能力,那么入口就还得是namesrv,以效仿于remoting的形式获取topic和grpc broker的关联路由关系。

不过好像rocketmq-v5的客户端还不支持endpoints写namesrv

ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
            .setEndpoints(endpoints)