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/helloThriftServiceRegistrationBeansetPathで設定した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を使ったトレーシング機能あたりを調べて書こうと思っています。