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

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

    若是是用spring boot自己提供的restful服務做爲服務與服務之間的調用,效率低不少,thrift的效率大概是restful的100-1000倍左右。本篇既是基於spring boot框架,結合thrift和zookeeper實現的一個簡單微服務框架,服務與服務之間使用thrift通訊(thrift既是通訊方式也是數據壓縮方式)。git

    本demo一共包括三個工程:spring

    cloud-thrift-server:服務提供方服務器

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

    cloud-thrift-client:服務調用方負載均衡

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

1)創建thrift接口定義文檔dom

    namespace java cloud.simple.serviceide

    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的朋友,不要被他們嚇到,其實他們是很輕量級的技術,很容易上手,這也許就是他們流行的緣由。

相關文章
相關標籤/搜索