Kris20030907 commented on issue #10529:
URL: https://github.com/apache/rocketmq/issues/10529#issuecomment-4739271588
I also checked the Java SDK side to see whether this is only a response
display issue.
The queue permission from `QueryRouteResponse` is not ignored by the Java
SDK. The route data is parsed and used to build local producer / consumer load
balancers.
Route fetch path in Java SDK:
- `ClientImpl#fetchTopicRoute0` sends `QueryRouteRequest`, reads
`response.getMessageQueuesList()`, and constructs `TopicRouteData`.
- `TopicRouteData` wraps every protobuf `MessageQueue` as `MessageQueueImpl`.
- `MessageQueueImpl` stores both `messageQueue.getId()` and
`Permission.fromProtobuf(messageQueue.getPermission())`.
Relevant code path:
- `client/src/main/java/org/apache/rocketmq/client/java/impl/ClientImpl.java`
- `fetchTopicRoute0`: `response.getMessageQueuesList()` -> `new
TopicRouteData(messageQueuesList)`
-
`client/src/main/java/org/apache/rocketmq/client/java/route/TopicRouteData.java`
- constructor wraps every protobuf `MessageQueue`
-
`client/src/main/java/org/apache/rocketmq/client/java/route/MessageQueueImpl.java`
- stores `queueId = messageQueue.getId()`
- stores `permission =
Permission.fromProtobuf(messageQueue.getPermission())`
The producer load balancer filters queues by this permission:
```java
topicRouteData.getMessageQueues().stream()
.filter(mq -> mq.getPermission().isWritable() &&
Utilities.MASTER_BROKER_ID == mq.getBroker().getId())
```
So if the server returns wrong per-queue permissions, the Java SDK producer
can build a wrong local writable queue set. For example, with:
- `readQueueNums = 8`
- `writeQueueNums = 4`
- `perm = PERM_READ | PERM_WRITE`
The real writable queues should be ids `0..3`, but the old server-side route
generation can mark ids `4..7` as `READ_WRITE`. The Java SDK would then treat
ids `4..7` as writable and exclude ids `0..3` from its local publishing load
balancer.
The consumer side has the same kind of dependency:
```java
topicRouteData.getMessageQueues().stream()
.filter(SubscriptionLoadBalancer::isReadableMasterQueue)
```
where `isReadableMasterQueue` checks:
```java
mq.getPermission().isReadable()
```
So with `readQueueNums = 4` and `writeQueueNums = 8`, the Java SDK consumer
can build a local readable queue set using ids `4..7`, while the actual
readable queues are ids `0..3`.
One nuance: in the current gRPC proxy implementation, the actual send /
receive path does another server-side queue selection before talking to the
broker.
For send:
- Java SDK chooses a local `MessageQueueImpl` from `PublishingLoadBalancer`.
- The selected queue id is written into message system properties.
- But `SendMessageActivity` creates a `SendMessageQueueSelector`, and
`ProducerProcessor` builds the final `SendMessageRequestHeader` using the
server-side selected `AddressableMessageQueue#getQueueId()`.
For receive:
- Java SDK chooses a local `MessageQueueImpl` from
`SubscriptionLoadBalancer`.
- It sends the selected `MessageQueue` in `ReceiveMessageRequest`.
- But `ReceiveMessageActivity` currently uses the broker name from the
request and then selects from the server-side read selector.
So in the current Java SDK + gRPC proxy flow, the wrong route response does
affect the SDK's local route view and load balancer candidates, but the
server-side proxy can mask part of the issue when executing send / receive
because it reselects queues internally.
Still, the route response itself is incorrect: `MessageQueue.id` and
`MessageQueue.permission` no longer describe the same physical queue. Any
client that relies on the per-queue permission directly, including Java SDK
route filtering logic, can observe a wrong route view.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]