使用spring boot和thrift、zookeeper建立微服務


     Spring cloud適應於雲端服務,也適用於企業信息化SOA建設。spring boot也是restful微服務開發的利器。但對於內網服務,即服務與服務之間的調用,spring並沒有去刻意封裝,也許他們認為已經沒有必要了,因為已經有了thrift、ice等強大的框架。

    如果是用spring boot本身提供的restful服務作為服務與服務之間的調用,效率低很多,thrift的效率大概是restful的100-1000倍左右。本篇既是基於spring boot框架,結合thrift和zookeeper實現的一個簡單微服務框架,服務與服務之間使用thrift通信(thrift既是通信方式也是數據壓縮方式)。

    本demo一共包括三個工程:

    cloud-thrift-server:服務提供方

    cloud-thrift-interface:接口及傳輸對象定義

    cloud-thrift-client:服務調用方

    開源代碼地址:http://git.oschina.net/zhou666/spring-cloud-7simple

1)建立thrift接口定義文檔

    namespace java cloud.simple.service

    struct UserDto {

      1: i32 id

      2: string username

    }

     service UserService {

      UserDto getUser()

    }

    接口定義完后,使用thrift命令生成對應的java文件,主要生成兩個文件,分別是UserService.java和UserDto.java,把這兩個文件放入cloud-thrift-interface工程,因為客戶端也需要這個接口定義。

2)實現thrift服務注冊

    在服務的提供端需要實現接口,並且還要把實現類注冊到thrift服務器。

    UserService.Processor processor = new UserService.Processor(

                       new UserServiceImpl());

         TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(

                       tServerTransport()).processor(processor));

    UserServiceImpl就是接口實現類,將其注冊金Tserver。

    注冊完服務后,需要啟動Tserver,很顯然這個需要在線程里啟動。

    executor.execute(new Runnable() {

                @Override

                public void run() {

                       tServer().serve(); 

                }

    });

3) 使用zookeeper進行服務名稱注冊

    上面是注冊具體的服務執行類,這一步是將服務的實例注冊進zookeeper,這樣才能實現負載均衡。讓客戶端可以根據服務實例列表選擇服務來執行。當然這里只需要注冊服務所在服務器的IP即可,因為客戶端只要知道IP,也就知道訪問那個IP下的該服務。

    String servicePath = "/"+serviceName ;// 根節點路徑

       ZkClient zkClient = new ZkClient(serverList);

       boolean rootExists = zkClient.exists(servicePath);

       if (!rootExists) {

           zkClient.createPersistent(servicePath);

       }

       InetAddress addr = null;

       try {

           addr = InetAddress.getLocalHost();

       } catch (UnknownHostException e) {

           e.printStackTrace();

       }

       String ip = addr.getHostAddress().toString();

       String serviceInstance = System.nanoTime() +"-"+ ip;

       // 注冊當前服務

       zkClient.createEphemeral(servicePath + "/" + serviceInstance);

       System.out.println("提供的服務為:" + servicePath + "/" + serviceInstance);

    要注意這里使用zkClient.createEphemeral建立臨時節點,如果這台服務器宕機,這個臨時節點是會被清除的,這樣客戶端在訪問時就不會再選擇該服務器上的服務。

4) 客戶端更新服務列表

    客戶端需要能及時的監聽服務列表的變化並作出負載均衡,我們用如下方式監聽服務列表的變化:

    // 注冊事件監聽

         zkClient.subscribeChildChanges(servicePath, new IZkChildListener() {

                // @Override

                public void handleChildChange(String parentPath,

                              List<String> currentChilds) throws Exception {

                       // 實例(path)列表:當某個服務實例宕機,實例列表內會減去該實例

                       for (String instanceName : currentChilds) {

                              // 沒有該服務,建立該服務

                              if (!serviceMap.containsKey(instanceName)) {

                                     serviceMap.put(instanceName,createUserService(instanceName));

                              }

                       }

                       for (Map.Entry<String, UserService.Client> entry : serviceMap.entrySet()) {

                              // 該服務已被移除

                              if (!currentChilds.contains(entry.getKey())) {

                                     serviceMap.remove(entry.getKey());

                              }

                       }

                       System.out.println(parentPath + "事件觸發");

                }

    });

    有了服務列表,客戶端在調用服務的時候就可以采用負載均衡的方式了,在這里使用最簡單的隨機方式:

         public UserService.Client getBalanceUserService(){       

         Map<String, UserService.Client> serviceMap =ZooKeeperConfig.serviceMap;

         //以負載均衡的方式獲取服務實例           

         for (Map.Entry<String, UserService.Client> entry : serviceMap.entrySet()) {

                System.out.println("可供選擇服務:"+entry.getKey());

         }

         int rand=new Random().nextInt(serviceMap.size());           

         String[] mkeys = serviceMap.keySet().toArray(new String[serviceMap.size()]);

         return serviceMap.get(mkeys[rand]);

  }

本文結束,具體參見代碼,另外,之前還不了解thrift和zookeeper的朋友,不要被他們嚇到,其實他們是很輕量級的技術,很容易上手,這也許就是他們流行的原因。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM