Getting started Armeria w/ Spring Boot
LINE社がOSSとして公開しているArmeriaというフレームワークがあります。
https://line.github.io/armeria/
ArmeriaはSpring Bootとintegrationするための機能も提供しています。
この記事では、Spring Bootユーザ向けにSpring BootとArmeriaを組み合わせる方法を紹介します。
Armeriaの紹介
Armeriaは以下のような特徴があります
(公式サイトから一部を抜粋)
Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC.
Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol.
- RPC Server/Client
- Thrift
- gRPC
- REST Server/Client
- Async
- HTTP/2
- Micrometer + Prometheusによるメトリクス収集
- Zipkinによるトレーシング
- Circuit breaker
microservicesを実装・運用する時に必要になる機能を持っていますね。
詳しい說明は、公式サイトと以下のスライドをどうぞ。
一番最初のチュートリアルとしては、この記事がわかりやすいと思います。
また、ArmeriaはLINEのサービスで実際に使用されていて、関連する記事やスライドがいくつか公開されています。
Spring Bootと組み合わせるメリット
個人的に以下のような事が思い付きます。
- DI,AOP,RDBMSのトランザクション管理などのSpringの機能が便利
- 依存ライブラリのバージョン組み合わせを自分で管理したくないので、Spring Bootが管理しているバージョンを使いたい
とはいえ、ArmeriaだけでRPC server/REST serverを実装する事ももちろん可能なので、シンプルなserverであればSpring Bootと組み合わせなくても良いでしょう。
今回作成したサンプルアプリケーションのソースコード
https://github.com/matsumana/armeria-sandbox/tree/0.0.1
0.0.1というtagを付けておきました。
ビルドするにはthrift compilerが必要です。僕はhomebrewでインストールしました。
Macでしか動作確認してませんが、LinuxやWindowsでビルドする場合は、build.gradleをいい感じに修正する必要があります。
今回作成したサンプルアプリケーションの構成
REST API(Spring MVCで実装) と RPC API(Armeriaで実装)を持っている、Spring BootのWebアプリケーションサーバ(Embedded Tomcat)です。
ArmeriaにもAnnotated HTTP Service
というSpring MVCに似た機能がありますが、
僕は個人的にSpring MVCに慣れているしSpring MVCには便利な機能が多いので、今回はREST APIの部分はSpring MVCで実装しています。
今回使用したバージョン
- Java: Oracle JDK 10.0.2
- Armeria: 0.69.0
- com.linecorp.armeria:armeria
- com.linecorp.armeria:armeria-spring-boot-starter
- com.linecorp.armeria:armeria-tomcat
- com.linecorp.armeria:armeria-thrift
- Spring Boot: 2.0.4.RELEASE
- org.springframework.boot:spring-boot-starter-web (Spring MVC)
- Thrift: 0.11.0
- thrift compiler (brewでインストール)
- org.apache.thrift:libthrift
- thrift-gradle-plugin: 0.4.0
サンプルアプリケーションの說明
1. Armeriaに関する設定
以下の2つの設定をしています。
Armeria公式のサンプルアプリケーションであるarmeria-examplesから持ってきました。
1-1. application.yml
Spring MVCでは、TomcatがHTTPのポート(8080)をLISTENしますが、Armeriaも同様にHTTPのポート(8080)でLISTENします。
(ちなみに、ArmeriaのHTTPサーバはNettyです)
ポートが競合してアプリケーションが起動エラーになるので、TomcatがHTTPのポートをLISTENしないように設定します。
(LISTENしないだけで、Tomcat自体は起動した状態になります)
server:
port: -1
1-2. Java config
上記application.ymlの設定でTomcatがHTTPのポートをLISTENしないようになるのでリクエストはArmeriaのNettyが受ける事になりますが、
Spring MVCの処理はTomcatでやってもらわないといけないのでリクエストをTomcatに流す設定が必要です。
以下がその設定です。
@Configuration
public class ArmeriaConfig {
private static Connector getConnector(ServletWebServerApplicationContext applicationContext) {
final TomcatWebServer container = (TomcatWebServer) applicationContext.getWebServer();
container.start();
return container.getTomcat().getConnector();
}
@Bean
public HealthChecker tomcatConnectorHealthChecker(ServletWebServerApplicationContext applicationContext) {
final Connector connector = getConnector(applicationContext);
return () -> connector.getState().isAvailable();
}
@Bean
public TomcatService tomcatService(ServletWebServerApplicationContext applicationContext) {
return TomcatService.forConnector(getConnector(applicationContext));
}
@Bean
public ArmeriaServerConfigurator armeriaServiceInitializer(TomcatService tomcatService) {
return sb -> sb.service("prefix:/", tomcatService);
}
}
2. Thrift APIの実装方法
ThriftのIDLは src/main/thrift
に置きます。
2-1. IDLを書く
今回は単純にエコーするだけのAPIです
namespace java info.matsumana.armeria.thrift
service HelloService {
string hello(1:string name)
}
2-2. 生成されたインターフェースを実装するクラスを書く
build.gradleにthrift-gradle-pluginを設定しているので、ビルド時にJavaソースコードが生成されます。
HelloService.Iface
というインターフェースが生成されるので、それを実装するクラスを書きます。
Springのコンポーネントにするために、@Component
アノテーションを付けました。
Thriftでは非同期APIを実装する事も出来ますが、今回実装したのは同期APIです。
@Component
public class HelloServiceImpl implements HelloService.Iface {
@Override
public String hello(String name) throws TException {
return "Hello, " + name;
}
}
2-3. Thrift serviceをSpringのコンポーネントとして登録する
ThriftServiceRegistrationBean
というクラスが提供されているのでそれを使います。
ArmeriaにはDocService
というSwaggerみたいなWeb UIがありますが、ThriftServiceRegistrationBean
で登録したThrift serviceはDocService
でも確認できます。
https://line.github.io/armeria/server-docservice.html
setExampleRequests(ImmutableList.of(new HelloService.hello_args("foo")))
はDocService
向けの設定です。
@Configuration
public class ArmeriaConfig {
@Bean
public ThriftServiceRegistrationBean helloService(HelloService.Iface helloService) {
return new ThriftServiceRegistrationBean()
.setPath("/thrift/hello")
.setService(THttpService.of(helloService))
.setServiceName("HelloService")
.setExampleRequests(ImmutableList.of(new HelloService.hello_args("foo")));
}
}
3. DocServiceからThrift APIをCallしてみる
以下のURLをブラウザで開いてください。
http://localhost:8080/internal/docs/
こういう画面が見れると思います。
左のAPI一覧からAPIを選択すると、APIの情報が確認できます。
APIをCallする機能も付いています。
SUBMIT
ボタンを押すと、
Call出来ました。
4. ArmeriaのThrift ClientからThrift APIをCallしてみる
ArmeriaにはThrift Clientも同梱されています。
使い方は以下のような感じです。
/thrift/hello
はThriftServiceRegistrationBean
のsetPath
で設定したpathです。
@RestController
@RequestMapping("/")
public class HelloController {
@GetMapping("hello/{name}")
String hello(@PathVariable String name) throws TException {
final HelloService.Iface helloService = Clients.newClient(
"tbinary+http://localhost:8080/thrift/hello",
HelloService.Iface.class);
return helloService.hello(name);
}
}
ブラウザから見てみると、
Call出来ました。
まとめ
JavaでMicroservicesなサービスを実装する場合、Armeriaは良い選択肢の1つだと思います。
次はMicrometerとPrometheusを使ったメトリクス収集機能、Zipkinを使ったトレーシング機能あたりを調べて書こうと思っています。