微服務框架Finagle介紹 Part3: 在Finagle中開發基於Thrift協議的應用

原文地址:http://skaka.me/blog/2016/05/02/finagle3/

在上篇文章中我們開發了一個基於Http協議的echo服務端和客戶端. 這篇文章我們將開發一個基於Thrift協議的客戶端和服務端. 這兩篇文章對應的源代碼地址在Github. 代碼中有Java和Scala版本兩套版本的實現, 但是這裏我只會介紹Java版本.

Thrift最早由Facebook開源, 後被Apache收錄成爲頂級項目. Thrift嚴格來說不只是一種協議, 而是一個RPC框架. 使用Thrift, 我們只需要定義好使用的類型和接口聲明, Thrift的代碼生成工具能夠自動爲我們生成客戶端和服務端代碼. 我們現在來看如何在Finagle中使用Thrift.

首先定義一個Thrift的IDL文件, 文件位置在java-finagle-example/src/main/thrift/DemoService.thrift:

1
2
3
4
5
6
7
8
9
10
namespace java com.akkafun.service.thrift

service DemoService {
  string method1();

  i32 method2(1: i32 a, 2: i32 b);

  void method3();

}

定義了一個DemoService服務, 這個服務有三個示例方法. namespace的語法是爲接口定義一個命名空間(對應Java裏的包). method1沒有參數, 方法的返回值類型是字符串. method2有兩個參數, a和b, 參數和返回值類型都是int32類型. method3無參數, 無返回值.

現在我們來生成代碼. Twitter提供了一個開源的工具Scrooge用來生成Finagle + Thrift的代碼. 我們使用Scrooge提供的maven插件用來生成代碼. 這個插件的配置可以查看pom.xml, 這裏不做介紹. 運行maven命令: mvn clean compile, 生成的代碼在java-finagle-example/target/classes/thrift目錄下. 這裏我們生成的是Scala代碼. 雖然Scrooge提供Java代碼的生成, 但是實際使用存在bug. 我們需要將這些代碼手動拷貝到源代碼目錄下. 將這些代碼拷貝到java-finagle-example/src/main/scala/thrift目錄下.

現在我們來實現Thrift服務端代碼. 打開java-finagle-example/src/main/java/com/akkafun/finagle/thrift/ThriftServer.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ThriftServer implements DemoService<Future> {

    public static void main(String[] args) throws Exception {
        ListeningServer server = Thrift.serveIface("127.0.0.1:8081", new ThriftServer());

        Await.result(server);
    }

    @Override
    public Future<String> method1() {
        System.out.println("implement method1");
        return Future.value("abc");
    }

    @Override
    public Future<Integer> method2(int a, int b) {
        System.out.println("implement method2");
        return Future.value(a + b);
    }

    @Override
    public Future<BoxedUnit> method3() {
        System.out.println("implement method3");
        return Future.value(BoxedUnit.UNIT);
    }
}

我們使用maven命令生成的Scala代碼, 裏面有一個DemoService接口. 我們現在要做的事情就是實現這個接口. 我們需要實現DemoService接口聲明的三個方法. 上面的實現都只是打印內容和返回簡單的值. 實現了這個接口, 接下來我們就可以寫啓動服務的代碼了. 上篇文章中我們啓動Http服務器的時候使用的是Http.server相關的方法. 現在啓動Thrift服務端可以使用Thrift.serveIface方法. 第一個參數傳入監聽的ip和端口, 第二個參數傳入接口的實現類. 這樣服務端的代碼就完成了.

Thrift的客戶端代碼也相當簡單. 打開java-finagle-example/src/main/java/com/akkafun/finagle/thrift/ThriftClient.java:

1
2
3
4
5
6
7
8
9
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
@SuppressWarnings("unchecked")
public class ThriftClient {

    static Function1<Throwable, BoxedUnit> errorFunc = func(e -> {
        System.out.println("error: " + e.toString());
        return BoxedUnit.UNIT;
    });


    public static void main(String[] args) throws Exception {
        DemoService<Future> demoService = Thrift.newIface("127.0.0.1:8081", DemoService.class);

        Future<String> future1 = demoService.method1();
        Future<Integer> future2 = demoService.method2(1, 2);
        Future<BoxedUnit> future3 = demoService.method3();

        future1.onSuccess(func(r -> {
            System.out.println(r);
            return BoxedUnit.UNIT;
        }));
        future1.onFailure(errorFunc);

        future2.onSuccess(func(r -> {
            System.out.println(r);
            return BoxedUnit.UNIT;
        }));
        future2.onFailure(errorFunc);

        future3.onSuccess(func(r -> {
            System.out.println(r);
            return BoxedUnit.UNIT;
        }));
        future3.onFailure(errorFunc);

        Await.ready(future1);
        Await.ready(future2);
        Await.ready(future3);

    }
}

客戶端代碼中, 通過調用Thrift.newIface我們構造了一個DemoService的stub. 之後即可對DemoService的方法進行調用. 雖然調用方式看起來很像是本地調用, 實際上還是RPC. DemoService的服務端實現只是很簡單的返回了幾個值, 客戶端實現只是把返回值打印了出來.現在我們來運行看看. 首先啓動ThriftServer類, 然後啓動ThriftClient. ThriftClient運行完畢自動結束, 你應該能在ThriftClient的控制檯看到如下輸出:

1
2
3
implement method2
implement method3
implement method1

ThriftServer控制檯的輸出:

1
2
3
()
3
abc

無論是客戶端還是服務端, 方法被調用的順序都是不固定的. 因爲客戶端的RPC調用是異步執行.

Finagle的開發實戰就暫時介紹到這裏. 通過前面的介紹你應該能瞭解到, 使用Finagle開發一個服務是非常的簡單. 但是實際的多服務項目中, 幾乎不會直接通過ip和端口來訪問服務, 而是使用zookeeperetcd這種註冊中心來完成. 下篇文章我會介紹如何將Finagle服務註冊到zookeeper中以及如何使用zipkin來監控Finagle服務.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章