iJIAJIA opened a new issue, #13401:
URL: https://github.com/apache/dubbo/issues/13401

   <!-- If you need to report a security issue please visit 
https://github.com/apache/dubbo/security/policy -->
   
   - [x] I have searched the [issues](https://github.com/apache/dubbo/issues) 
of this repository and believe that this is not a duplicate.
   
   ### Environment
   
   * Dubbo version: 3.2.3
   * Operating System version: win10
   * Java version: jdk 8
   
   ### Steps to reproduce this issue
   
   1. provider 使用端口融合
   ```
   dubbo:
     protocol:
       name: tri
       ext-protocol: dubbo
   ```
   ### Expected Behavior
   
org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory#toInvokers 
返回 TripleInvoker和DubboInvoker.
   
![image](https://github.com/apache/dubbo/assets/10057108/27b33def-1fa1-4389-af27-757603d7537b)
   
   ### Actual Behavior
   
   
org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory#toInvokers 
两个协议,返回了两个DubboInovker或者TripleInvoker.
   
![image](https://github.com/apache/dubbo/assets/10057108/1fc71198-54e7-4e26-926e-7284f820e0c8)
   
   
   <!-- What actually happens? -->
   **原因**
   ```
   private Map<ProtocolServiceKeyWithAddress, Invoker<T>> 
toInvokers(Map<ProtocolServiceKeyWithAddress, Invoker<T>> oldUrlInvokerMap, 
List<URL> urls) {
           
           for (URL url : urls) {
               // 由于provider启用了端口复用, tri和dubbo两个实例端口相同
               InstanceAddressURL instanceAddressURL = (InstanceAddressURL) url;
               
               // filter all the service available (version wildcard, group 
wildcard, protocol wildcard)
               int port = instanceAddressURL.getPort();
               List<ProtocolServiceKey> matchedProtocolServiceKeys = 
instanceAddressURL.getMetadataInfo()
                   .getMatchedServiceInfos(consumerProtocolServiceKey)
                   .stream()
                   // 这里进行实例元数据匹配时, 会匹配tri和dubbo两个实例, 仅靠端口做进一步过滤时, 
没能过滤掉不匹配的protocol协议.
                   .filter(serviceInfo -> serviceInfo.getPort() <= 0 || 
serviceInfo.getPort() == port)
                   .map(MetadataInfo.ServiceInfo::getProtocolServiceKey)
                   .collect(Collectors.toList());
   
               // 一个protocol匹配了两个ProtocolServiceKey, 在下一个instanceAddressUrl循环时, 
会覆盖前一次创建的Invoker.
               for (ProtocolServiceKey matchedProtocolServiceKey : 
matchedProtocolServiceKeys) {
                   
                   ProtocolServiceKeyWithAddress protocolServiceKeyWithAddress 
= new ProtocolServiceKeyWithAddress(matchedProtocolServiceKey, 
instanceAddressURL.getAddress());
                   Invoker<T> invoker = oldUrlInvokerMap == null ? null : 
oldUrlInvokerMap.get(protocolServiceKeyWithAddress);
                   if (invoker == null || urlChanged(invoker, 
instanceAddressURL, matchedProtocolServiceKey)) { // Not in the cache, refer 
again
                       try {
                           iboolean enabled;
                           if (instanceAddressURL.hasParameter(DISABLED_KEY)) {
                               enabled = 
!instanceAddressURL.getParameter(DISABLED_KEY, false);
                           } else {
                               enabled = 
instanceAddressURL.getParameter(ENABLED_KEY, true);
                           }
                           if (enabled) {
                               if (shouldWrap) {
                                   ....
                                   //  这里遍历List<ProtocolServiceKey>  
instanceAddressURL进行protocol创建, 
                                   invoker = new 
InstanceWrappedInvoker<>(protocol.refer(serviceType, instanceAddressURL), 
newConsumerUrl, matchedProtocolServiceKey);
                               } else {
                                   invoker = protocol.refer(serviceType, 
instanceAddressURL);
                               }
                       if (invoker != null) { // Put new invoker in cache
                           newUrlInvokerMap.put(protocolServiceKeyWithAddress, 
invoker);
                       }
                   } else {
                       newUrlInvokerMap.put(protocolServiceKeyWithAddress, 
invoker);
                       oldUrlInvokerMap.remove(protocolServiceKeyWithAddress, 
invoker);
                   }
               }
           }
           return newUrlInvokerMap;
       }
   ```
   
![image](https://github.com/apache/dubbo/assets/10057108/6cdee271-5273-44cb-b2c1-3241728831ae)
   
   
   **解决建议**
   ```
   int port = instanceAddressURL.getPort();
               String instanceProtocol = instanceAddressURL.getProtocol();
               List<ProtocolServiceKey> matchedProtocolServiceKeys = 
instanceAddressURL.getMetadataInfo()
                   .getMatchedServiceInfos(consumerProtocolServiceKey)
                   .stream()
                   .filter(serviceInfo -> serviceInfo.getPort() <= 0 || 
serviceInfo.getPort() == port)
                   // 额外添加基于instanceAddressUrl的protocol过滤条件, 
修复端口复用场景下匹配不同协议的ProtocolServiceKey问题
                   .filter(serviceInfo -> 
Objects.equals(serviceInfo.getProtocol(), instanceProtocol))
                   .map(MetadataInfo.ServiceInfo::getProtocolServiceKey)
                   .collect(Collectors.toList());
   ```
   
   


-- 
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: notifications-unsubscr...@dubbo.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org
For additional commands, e-mail: notifications-h...@dubbo.apache.org

Reply via email to