动态获取Dubbo服务提供方地址列表

如何动态获取Dubbo服务提供方地址列表
一、前言
dubbo框架本身提供了丰富的负载均衡策略,比如轮询、随机、最少活跃调用数、一致性hash等,但是有时候我们需要自己根据业务指定某个ip来进行调用。要指定ip进行调用就需要先知道服务提供者的ip。本文我们先来探讨第一步,当服务注册中心使用zookeeper时候如何获取某一个服务的提供端的地址列表。

二、实现
我们知道当服务提供方启动时候,会注册服务到服务注册中心,本文我们通用zookeeper,比如服务com.books.dubbo.demo.api.GreetingService则注册到zk后,那么当消费端启动时候会去zookeeper上订阅path为/dubbo/com.books.dubbo.demo.api.GreetingService/providers下面的信息,也就是服务提供者列表信息,那么我们就可以基于这个原理来获取某一个服务提供者列表,然后对信息进行过滤加工,并且注册一个监听器,当服务提供者机器增减后,动态更新保存的地址列表。
基于上面原理实现代码如下:
 

[Java] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

public class ZookeeperIpList {

 

    private String dataId = "com.books.dubbo.demo.api.GreetingService/providers:1.0.0";

    private URL CONSUMER_URL;

    private static final Joiner j = Joiner.on("|").useForNull("nil");

 

    public final List getIpList() {

        return ipList;

    }

 

    private volatile List ipList = new ArrayList();

 

    //对获取的列表内容进行过滤

    private static List toUrlsWithoutEmpty(URL consumer, List providers) {

        List urls = new ArrayList();

        if (providers != null && providers.size() > 0) {

            urls = providers.stream().map(provider -> URL.decode(provider)).filter(provider -> provider.contains("://"))

                    .map(provider -> URL.valueOf(provider)).filter(url -> UrlUtils.isMatch(consumer, url))

                    .collect(Collectors.toList());

        }

         

        return urls;

    }

 

    // 解析服务提供者地址列表为ip:port格式

    private void parseIpList(List ipSet) {

 

        List urlList = toUrlsWithoutEmpty(CONSUMER_URL, ipSet);

        final List ipListTemp = urlList.stream().map(url -> url.getAddress()).collect(Collectors.toList());

        this.ipList = ipListTemp;

 

    }

 

    public void init(String zkServerAddr, String zkGroup, String dataId, String serviceGroup) {

        // 1.参数校验

        Assert.notNull(zkServerAddr, "zkServerAddr is null.");

        Assert.notNull(dataId, "dataId is null.");

        Assert.notNull(dataId, "zkGroup is null.");

        Assert.notNull(dataId, "serviceGroup is null.");

 

        // 2.拼接订阅的path

        String[] temp = dataId.split(":");

        if (temp.length != 2) {

            throw new RuntimeException("dataId is illegal");

        }

 

        this.dataId = "/" + zkGroup + "/" + temp[0] + "/providers";

        String consumeUrl = "consumer://127.0.0.1/?group=" + serviceGroup + "&interface=" + temp[0] + "&version="

                + temp[1];

        CONSUMER_URL = URL.valueOf(consumeUrl);

 

        // 3.开启zk,订阅path路径下服务提供者信息,并添加监听器

        System.out.println(j.join("init zk ", zkServerAddr, this.dataId, consumeUrl));

        ZkClient zkClient = new ZkClient(zkServerAddr);

        List list = zkClient.subscribeChildChanges(this.dataId, new IZkChildListener() {

 

            @Override

            public void handleChildChange(String parentPath, List currentChilds) throws Exception {

                // 3.1解析服务提供者地址列表

                parseIpList(currentChilds);

 

                try {

                    System.out.println((j.join("ipList changed:", JSON.json(ipList))));

                } catch (IOException e) {

                }

            }

        });

 

        //4. 解析服务提供者ip列表

        parseIpList(list);

 

    }

 

    public static void main(String[] a) throws InterruptedException {

        ZookeeperIpList zk = new ZookeeperIpList();

        zk.init("127.0.0.1:2181", "dubbo", "com.books.dubbo.demo.api.GreetingService:1.0.0", "dubbo");

 

        try {

            System.out.println((j.join("parseIpList", JSON.json(zk.getIpList()))));

        } catch (IOException e) {

        }

        Thread.currentThread().join();

 

    }

}


如上代码main函数创建了一个ZookeeperIpList对象,并且调用其init方法,参数分别为zk地址,zk分组,服务接口以及版本,服务分组。
init方法内首先拼接要订阅的zk的path,拼接完成后dataid为/dubbo/com.books.dubbo.demo.api.GreetingService/providers,然后创建zkclient订阅该dataid对应的path,并且注册监听器,当path下信息变化后会得到最新列表。
并且使用parseIpList方法解析获取的地址列表为ip:port个数,解析完毕后保存到ipList中。

三、总结
本节介绍了一个简单的基于zookeeper获取服务提供者地址列表的方法,后面我们看如何指定ip进行调用。

你可能感兴趣的:(Java)