Top Banner
Using Armeria to write your RPC koji lin
41

Using armeria to write your RPC

Jan 09, 2017

Download

Technology

Koji Lin
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Using armeria to write your RPC

Using Armeria to write your RPC

koji lin

Page 2: Using armeria to write your RPC

Armeria

● 非同步 RPC library

● LINE 的開放原始碼專案

○ Trustin Lee

● Java 8 

● HTTP/1・2 

● Thrift/gRPC 

● 尤其適合在 Microservices 架構

Page 3: Using armeria to write your RPC

Synchronous? Asynchrnous?

● 在同步下,如果一個處理需要等待,thread 必須等

待完成才能繼續執行

● 同步處理在大量存取下不易 scale up

○ Concurrent requests 受限於 max threads 

○ CPU 花費成本在 contention & context switch 

○ 較快或優先程度較高的存取會被較慢的存取拖累

Page 4: Using armeria to write your RPC

Armeria is Asynchronous

● 建立於 Netty 之上

● Max concurrent requests >>> max threads

● 較慢的存取不會阻礙到其他存取

● 程式庫內部也非同步化

○ DNS 查詢

○ Connection pool

● 0.20.x reactive stream 化

Page 5: Using armeria to write your RPC

Why HTTP/2 ?

● 一個連線上可以同時來往多個 request / response

● 不需要一個存取就建一個連線

from https://www.nginx.com/blog/7-tips-for-faster-http2-performance/

Page 6: Using armeria to write your RPC

Why HTTP/2 ? (cont'd)

● 解決了 HTTP/1 的許多問題

○ Binary header compression

○ 更少的連線

● 比較容易從 HTTP/1 轉換

● 可以利用各種現存的工具

○ cURL,瀏覽器,Wireshark

Page 7: Using armeria to write your RPC

Netty 夠穩定嗎?

● HTTP/1

○ Twitter

○ Apple

● HTTP/2

○ gRPC

○ LINE internal use

Page 8: Using armeria to write your RPC

Thrift● 跨平台跟語言的服務開發框架

○ 透過 compiler 自動生成程式,支援 C++, Java,

Python, Ruby, Perl, C#, Go, Javascript ...等等

○ 支援各種傳輸格式/協定

● 原本是 Facebook 開發,現為 Apache Thrift 開源

● 定義好 service method 就可以快速開發 RPC

client 和 server

○ .thrift 本身就是良好的文件

● 比 text-based 格式更有效率

Page 9: Using armeria to write your RPC

Thrift hello world on Armeria

● 撰寫 .thrift 定義 service method1. namespace java idv.koji.example.service2. service HelloService {3. string hello(1:string name)4. }

Page 10: Using armeria to write your RPC

Thrift hello world on Armeria (cont’d)

● 使用 thrift compiler 產生好 client/server 溝通部分

● 實作邏輯

1. public class Foo implements HelloService.AsyncIface {

2. public void hello(String name, AsyncMethodCallback cb) {

3. cb.onComplete(name + ", hello world!");4. }5. }

Page 11: Using armeria to write your RPC

● 利用 Armeria 建立 Server1. ServerBuilder sb = new ServerBuilder();2. sb.port(8080, SessionProtocol.HTTP);3. sb.serviceAt(4. "/hello",5. ThriftService.of(fooHandler,6. SerializationFormat.THRIFT_BINARY)7. .decorate(LoggingService::new));8. sb.build().start();

Thrift hello world on Armeria (cont’d)

Page 12: Using armeria to write your RPC

● 利用 Armeria 建立 Client1. HelloService.Iface helloService = 2. Clients.newClient(3. "tbinary+http://127.0.0.1:8080/hello",4. HelloService.AsyncIface.class);5.6. helloService.hello("Armeria", 7. new AsyncMethodCallback<String>() {8. ...9. });

Thrift hello world on Armeria (cont’d)

Page 13: Using armeria to write your RPC

● 跟 Swagger 類似

1. ServerBuilder sb = new ServerBuilder();2. sb.serviceAt("/foo/", THttpService.of(...))3. .serviceAt("/bar/", THttpService.of(...))4. .serviceUnder("/docs/", new 5. DocService());

文件產生器

Page 14: Using armeria to write your RPC

和 legacy webapp 共存

● 將 legacy 的程式透過 Tomcat Servlet Engine 執行

● Tomcat 不需綁定 port,還可以透過 armeria 得到

HTTP/2 的好處

1. ServerBuilder sb = new ServerBuilder(); 2. sb.serviceUnder("/legacy/", 3. TomcatService.forFileSystem(4. "/var/example.war"));

Page 15: Using armeria to write your RPC

靜態頁面

1. ServerBuilder sb = new ServerBuilder(); 2. sb.serviceUnder("/images/", 3. HttpFileService.forFileSystem(4. "/var/lib/www/images"));

Page 16: Using armeria to write your RPC

HTTP Server

1. ServerBuilder sb = new ServerBuilder();2. sb.port(8080, SessionProtocol.HTTP);3. builder.serviceAt("/http", 4. new AbstractHttpService() {5. @Override protected void 6. doPost(ServiceRequestContext ctx,7. HttpRequest req,8. HttpResponseWriter res)... {9. res.respond(HttpStatus.OK, 10. MediaType.PLAIN_TEXT_UTF_8, 11. "test");12. }13. }).build().start();

Page 17: Using armeria to write your RPC

HTTP Client

1. HttpClient httpClient = Clients.newClient(2. "none+http://example.com/", 3. HttpClient.class);4. AggregatedHttpMessage textResponse = 5. httpClient6. .get("/foo/bar.txt") // Publisher7. .aggregate() // CompletableFuture8. .join();

Page 18: Using armeria to write your RPC

Client side load balancing

● Armeria 使用單一 HTTP/2 連線,所以在某些狀況

如 L4 下,需要自己的 LB 機制

1. EndpointGroupRegistry.register(2. "myGroup", 3. new StaticEndpointGroup( 4. Endpoint.of("1.2.3.4", 8080), ...),5. EndpointSelectionStrategy.6. WEIGHTED_ROUND_ROBIN); 7. Clients.newClient(8. "none+http://group:myGroup/foo/bar", 9. SimpleHttpClient.class);

Page 19: Using armeria to write your RPC

Metrics

● Dropwizard Metrics

● 使用 DropwizardMetricCollectingService decorate1. builder.serviceAt(2. "/hello", 3. THttpService.of(new HelloHandler())4. .decorate( 5. DropwizardMetricCollectingService 6. .newDecorator(metricRegistry, 7. "hello-service")));

Page 20: Using armeria to write your RPC

Zipkin 整合

● Twitter 的開放源碼專案

● 分散式服務追蹤系統,追蹤跨網路存取的一連串

API 呼叫過程

● 在存取產生時放入一些資訊在 request 中,送到後

台可視化

Page 21: Using armeria to write your RPC

Zipkin 整合 (cont’d)

1. Brave brave = new2. Brave.Builder("HelloService") 3. .spanCollector(4. new ScribeSpanCollector("127.0.0.1", 5. 9410)) 6. .traceSampler(Sampler.create(1f)) 7. .build();8. server.serviceAt("/hello",9. ThriftService.of(new HelloService())

10. .decorate(HttpTracingService11. .decorator(brave));

Page 22: Using armeria to write your RPC

Circuit Breaker

● 有多個遠端呼叫的系統最怕超時的服務所造成的連

鎖反應

● http://martinfowler.com/bliki/CircuitBreaker.html

http://developers.linecorp.com/blog/ja/?p=3684

Page 23: Using armeria to write your RPC

Circuit Breaker (cont’d)

1. decorator = 2. CircuitBreakerClient.newDecorator(3. new CircuitBreakerBuilder("hello")4. .failureRateThreshold(0.1).build());5.6. new ClientBuilder("tbinary+http://...")7. .decorator(ThriftCall.class, 8. ThriftReply.class, 9. decorator)

10. .build(HelloService.Iface.class);

Page 24: Using armeria to write your RPC

Circuit Breaker (cont’d)

● Circuit Breaker 開啟時會丟出 FailFastException

● 可以針對 host, method 等級去做設定

○ newPerMethodDecorator

○ newPerHostDecorator

○ newPerHostAndMethodDecorator

Page 25: Using armeria to write your RPC

gRPC support

● https://github.com/line/armeria/pull/2471. ServerBuilder sb = new ServerBuilder(); 2. sb.port(8080, SessionProtocol.HTTP); 3. GrpcService grpcService = new 4. GrpcServiceBuilder()5. .addService(new HiService())6. .build();7. sb.serviceUnder("/", grpcService); 8. sb.build().start();

Page 26: Using armeria to write your RPC

● 理應可以支援 HTTP/1,但現在沒有 HTTP/1 client

● 尚未支援文件產生器 DocService

● 尚未支援 json 格式

○ 類似 gRPC gateway

gRPC support (cont’d)

Page 27: Using armeria to write your RPC

Retrofit with armeria client

● https://github.com/line/armeria/pull/2971. HttpClient httpClient = 2. Clients.newClient(ClientFactory.DEFAULT,3. "none+http://localhost:8080",4. HttpClient.class);5. Retrofit retrofit = 6. ArmeriaRetrofit.builder(httpClient)7. .addConverterFactory(...)8. .build();9. MyApi api = retrofit.create(MyApi.class);

Page 28: Using armeria to write your RPC

Armeria 之於應用程式開發者

● 良好的抽象設計

○ 一樣的方式模式建立 http/thrift client 和 server

● 方便的 decorator 模式

○ 預設已提供 logging, metrics, tracing, circuit

breaker…

○ 依需求可以用同模式實作各種功能 例如: ACL,

rate-limiting...等等

Page 29: Using armeria to write your RPC

Is Armeria production ready?

Page 30: Using armeria to write your RPC
Page 31: Using armeria to write your RPC

Shop architecture using armeria

Page 32: Using armeria to write your RPC

● 內部與外部都從 thrift socket client/server 實作切

換到 armeria

○ 內部都是 HTTP/2

○ 外部則 HTTP/2 & HTTP/1 都有

● 與 Spring MVC 共存

● Circuit breaker

● Metrics + Zipkin tracing

Page 33: Using armeria to write your RPC

# of backend requests

Page 34: Using armeria to write your RPC
Page 35: Using armeria to write your RPC
Page 36: Using armeria to write your RPC
Page 37: Using armeria to write your RPC
Page 38: Using armeria to write your RPC

但是...

● 非同步化不只是更換框架/程式庫就完成

○ 非同步化的程式不易撰寫跟維護

○ 我們使用 Dagger Producers 去實作非同步的相依

流程

● server/client 都使用 armeria,記得不要使用 client

的 future#get 之類的阻塞方法

○ event loop 下造成同 thread 等待跑在同個 thread

下的 task, 造成永遠阻塞

Page 39: Using armeria to write your RPC

但是... (cont’d)

● 非同步出錯時,exception 的 stack trace 資訊不足

Page 40: Using armeria to write your RPC

更多資訊

● http://line.github.io/armeria/

● https://github.com/line/armeria

● 歡迎直接到 issue 提出建議跟需求

Page 41: Using armeria to write your RPC

Q&A