YoWuwuuuw opened a new pull request, #7887:
URL: https://github.com/apache/incubator-seata/pull/7887
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Please make sure you have read and understood the contributing
guidelines -->
- [ ] I have read the
[CONTRIBUTING.md](https://github.com/apache/incubator-seata/blob/2.x/CONTRIBUTING.md)
guidelines.
- [ ] I have registered the PR
[changes](https://github.com/apache/incubator-seata/tree/2.x/changes).
### Ⅰ. Describe what this PR did
#### 1. Core Capabilities and New Configuration Items
##### 1.1. Server Side: Metadata Registration
+ Seata-Server can **carry custom metadata** when registering with the
registry center.
```properties
# server: application.yaml, common metadata is provided, custom
configuration items can be configured.
# Common metadata for routing, custom metadata key-value pairs can be
configured.
seata.registry.metadata.weight: 1
seata.registry.metadata.env:
seata.registry.metadata.region:
seata.registry.metadata.version:
```
##### 1.2. Client Side: Metadata-Driven Instance Selection
Client instance selection is broken down into **two stages**: **route
filtering and load balancing, the process is as follows**
```properties
All Instances
│
▼
Metadata Routing (0 ~ N routers)
│
▼
Filtered Instances
│
▼
LoadBalance Strategy (random / round-robin / Advanced Load Balancing Based
on Metadata
│
▼
Target Server Instance
```
Configuration items are as follows:
```properties
# Add load balancing strategy: Weighted Random
seata.client.load-balance.type=WeightedRandomLoadBalance
client.routing.enabled=false # Enable route filtering mode
client.routing.debug=false # Debug mode, displaying detailed logs of the
route filtering handler
client.routing.routers= # Declare routers to load router configuration
# 1. Single router: use metadata-router-1
client.routing.routers = metadata-router-1
client.routing.metadata-router-1.enabled = true
client.routing.metadata-router-1.expression = version >= 2.3 && env == prod
# 2. Multiple routers: use metadata-router-1, metadata-router-2, ...
client.routing.routers = metadata-router-1, metadata-router-2, spi-cunstom
client.routing.metadata-router-1.enabled = true
client.routing.metadata-router-1.expression = version >= 2.0 || env == dev
client.routing.metadata-router-2.enabled = true
client.routing.metadata-router-2.expression = weight >= 1
client.routing.spi-cunstom.enabled = true # Configurable SPI router, custom
configuration and filtering logic, name must start with 'spi-'
client.routing.spi-cunstom.xxx = ...
```
#### 2. Expression Syntax:
##### 2.1. Basic Format
`key operator value`, three parts separated by spaces: key name, operator,
value
##### 2.2. Supported Operators
| Operator | Description | Supported Types |
|-----------------|------------------|-----------------|
| == / = | Equal to | String, Number |
| != | Not equal to | String, Number |
| > / >= / < / <= | Comparison | Number only |
> <、>、>=、<= Only support numbers. If the instance metadata is not a number,
it will return false and filter the instance.
##### 2.3. Expression Examples
1. Single expression: `version >= 2.3`
2. OR expression: `(version >= 2.3) || (env == dev)`
3. AND expression: `(version >= 2.3) && (env == prod)`
##### 2.4. Expression Limitations
Limitation: A single expression does not support mixing && and ||
Solution: Use multiple || expressions in the router to implement complex
logic
```properties
# Implement the logic of (A || B) && (C || D)
client.routing.metadata-router-1.expression= A || B
client.routing.metadata-router-2.expression= C || D
```
> Or use the distributive law: `(A && B) || (C && D) = (A || C) && (A || D)
&& (B || C) && (B || D)`
>
#### 3. Metadata Enhancement for Each Registry
##### 3.1. Enhancement Methods
| Registry | Metadata Implementation
| Description |
|-----------------|-----------------------------------------------------------|-------------|
| **Consul** | Directly call the API's `setMeta()` / `getMeta()`
| Consul natively supports metadata fields, and the API handles them
automatically |
| **Nacos** | Directly call the API's `setMetadata()` /
`getMetadata()` | Nacos natively supports metadata fields, and the API handles
them automatically |
| **Eureka** | Through `instanceConfig.setMetadata()` /
`instance.getMetadata()` | Eureka natively supports metadata
fields;<br/>`getMetadataMap()` converts them to a `Map<String, String>` |
| **Namingserver**| Based on the original API, metadata is part of the
`Instance` object | The `Instance` object itself contains a `metadata`
field,<br/>passed via JSON serialization/deserialization, which the API handles
automatically |
| **Zookeeper** | Manually serialize metadata to string format
(`key=value\n`) | Stored in the `data` of the `ZNode`, requiring manual
serialization/deserialization |
| **Redis** | As shown below
| — |
##### 3.2. To be implemented
| Registry | Status |
|----------|--------|
| **Etcd** | The original logic is not working; the existing implementation
logic should be fixed first. |
| **Sofa** | Cannot be built; a separate pull request will be made to
enhance it in the future. |
##### 3.3. Redis Enhancement Description
Implementation method: Manually build a hash structure to store metadata.
Core design:
+ Maintain the original live keys. Unchanged:
`registry.redis.${cluster}_${serverAddr}` (used for service discovery and
heartbeat detection)
+ Added metadata key: `registry.redis.${cluster}.meta_${serverAddr}` (Hash
structure, storing metadata)
Backward compatibility:
+ When a new server registers, it creates both a liveness key and a metadata
key (if metadata exists).
+ Existing clients only scan the liveness key and can discover new servers
normally (ignoring the metadata key).
+ After scanning the liveness key, new clients attempt to retrieve the
metadata key; if it does not exist or is empty, a ServiceInstance without
metadata is created.
Technical details:
+ Metadata is stored in a separate hash structure, decoupled from liveness
detection.
+ The TTL of both keys is refreshed synchronously (5 seconds) to ensure data
consistency.
#### 4. Compatibility Notes
+ Enabling `routing` mode:
- seata-server without metadata configuration:
* When route filtering is enabled, instances without metadata will be
filtered.
* When using a weighted random load balancing strategy, a default weight
of `weight=1` will be assigned.
- seata-client does not enable `routing` mode: logical consistency
backwards.
### Ⅱ. Does this pull request fix one issue?
<!-- If that, add "fixes #xxx" below in the next line, for example, fixes
#97. -->
fixes #7886
### Ⅲ. Why don't you add test cases (unit test/integration test)?
### Ⅳ. Describe how to verify it
Refer to
[#7550]([https://github.com/apache/incubator-seata/pull/7550](https://github.com/apache/incubator-seata/pull/7550)),
use [demo](https://github.com/apache/incubator-seata/pull/7550), modify the
corresponding configurations for verification.
### Ⅴ. Special notes for reviews
--
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]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]