DNSの送受信をtcpdumpで見る
apt update && apt install -y tcpdump dnsutils tcpdump -X -n -vv dst port 53 or src port 53 &
# dig すればなんか出るはず dig yahoo.co.jp
tcpdumpで真面目に見たのは初めてなので ↓を見ながら調べた。
- tcpdumpチートシート - Qoosky
- 28バイトはヘッダ
- https://tools.ietf.org/html/rfc2929
- この辺見ながらバイト列見ると良い
2019/07/26 KCL v2周りの話
KCLv2の話
- 移行はこの辺読んで。Kinesis Client Library 1.x から 2.x への移行 - Amazon Kinesis Data Streams
- localstackではKinesis Client Library v2はテスト出来ない
- 内部で使っているkinesaliteでは、新しいAPIがサポートされていない
- Kinesis Client Library v2 · Issue #75 · mhart/kinesalite · GitHub
- DynamoDBのbilling modeをpay per requestにする手段は現状ない。
- 以下のissueでは、TableCreatorCallbackが紹介されているが、DynamoDBのテーブルは作った後、すぐにはbillingModeを変えられない。
- Support for create table requests to allow for BillingMode to be PAY_PER_REQUEST · Issue #489 · awslabs/amazon-kinesis-client · GitHub
aws sdk for java v2の話
- 移行はこの辺読む。AWS SDK for Java 2.x 移行ガイドとは - AWS SDK for Java 移行ガイド
- デフォルトではHTTPクライアントとしてnettyを使う模様
- ServiceLoader経由で切り替えられるようになっている模様
- nettyのunstable APIに依存していて互換性エラーが出ることがある
- 現状メトリクス周りの実装は存在しない
- Netflixでは spectatorにinterceptorを用意しているっぽい?
- IPC integration for AWS SDK v2 by brharrington · Pull Request #689 · Netflix/spectator · GitHub
- aws sdk for java v2 は、ServiceLoader経由で interceptorを指定出来るっぽい。便利。
- HTTPクライアントで使われるスレッドプールは以下の感じになっていた sdk-core:2.5.10
スレッドプールがmax: 50
ThreadPoolExecutor executor = new ThreadPoolExecutor(50, 50, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10_000), new ThreadFactoryBuilder() .threadNamePrefix("sdk-async-response").build()); // Allow idle core threads to time out executor.allowCoreThreadTimeOut(true); return executor;
Armeriaで始めるDNSのSRV Recordを使った クライアントサイドロードバランシング
今回は、Armeriaを使って、DNSのSRV Recordを使ったクライアントサイドロードバランシングをやってみました。
クライアントサイドロードバランシングの必要性については以下の記事を読むと良いかもしれません。 いくつか現実とそぐわない点があるかもしれませんが。
- Microservices: Client Side Load Balancing
- 自分が和訳したもので恐縮ですが、リンクを貼っておきます。
今回動かす構成としては以下の通りです。
- server: Hello Worldを返すエンドポイントを持つHTTPサーバ
- client: Armeriaの機能を使って、クライアントサイドロードバランシングしながらserverに接続する
serverは、シンプルなもgolangで書かれたサーバです。 clientは、クライアントサイドロードバランシングしながらserverに接続します。 マイクロサービスの文脈で使おうと思っているので、今回はclientもHTTPサーバとして起動し、APIを持っています。
また、動作確認には、AWSのECSで、Fargateタイプでコンテナを起動しながら、動作確認をしました。 ECSではService Discoveryの機能を使ってDNSのSRVレコードを生成することが出来るので、便利です。 今回はECSコンテナインスタンスを立てるのが面倒なので、Fargateを使います。
Service Discoveryの設定等については以下のブログを参考にしました。 SRVレコードが登録されるように、設定してください。
server
golangで書きます。
package main import ( "log" "net/http" "time" ) func main() { m := http.NewServeMux() m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World!\n")) }) srv := &http.Server{ Addr: ":8080", ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, Handler: m, } log.Println("started 8080") log.Println(srv.ListenAndServe()) }
Hello Worldを返すエンドポイントが生えてるだけですね。 今回のメインはこちらではないので、さっくり流します。
client
このclientでは、ArmeriaのService Discovery機能を使って クライアントサイドロードバランシングをします。 ドキュメントを見ると他の例も書かれているので 詳しいことが知りたければそちらを見ると良さそうです。
APIとクライアントの利用例を先に下に示します。
@RestController public class RootController { private final ExternalService externalService; RootController(ExternalService externalService) { this.externalService = externalService; } @GetMapping("/") public CompletableFuture<String> index() { // serverに通信したレスポンスをそのまま返却する return externalService.get().thenApply(r -> r.content().toString(StandardCharsets.UTF_8)); } } /** * 色々例としてはよくないけど、通信するためのService。 */ @Service public class ExternalService { public CompletableFuture<AggregatedHttpResponse> get() { // 本当はフィールドに持っておいたほうが良さそう HttpClient httpClient = HttpClient.of("http://group:backend/"); // URLも外部化しておくべき。 return httpClient.get("/").aggregate(); } }
ControllerとServiceをざっと書きましたがすごくシンプルなものです。
見てほしいのは下の部分です。
HttpClient httpClient = HttpClient.of("http://group:backend/");
ここで、Armeriaに対して、backend
という、EndpointGroupを解決してリクエストを送ってほしい旨を表しています。
では、backendというEndpointGroupはどこで登録しているかというと下の部分です。
@Configuration public class ArmetriaConfig implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { // DNSのSRVレコードでService Discoveryするエンドポイントのグループ // backend.internal.localという名前でDNSに問い合わせる DnsServiceEndpointGroup group = new DnsServiceEndpointGroupBuilder("backend.internal.local") // Custom backoff strategy. .backoff(Backoff.exponential(1000, 16000).withJitter(0.3)) .build(); // Wait until the initial DNS queries are finished group.awaitInitialEndpoints(); // backendという名前で エンドポイントのグループを登録 EndpointGroupRegistry.register("backend", group, EndpointSelectionStrategy.WEIGHTED_ROUND_ROBIN); } }
ドキュメントからほぼコピペです。
これだけで動きます。
Fargateにデプロイするくだりは省略します。 Docker Imageをいい感じに作っていい感じにService Discoveryの機能を有効にして Fargateでデプロイしてください。
(Fargateにデプロイ後) すごい!簡単に動きました!便利! 本当に使いやすくて楽だった。
まとめ
Armeriaで、DNSのSRVレコードのサービスディスカバリを試しました。
spotify/dns-java
などを自前で使って実装する場合、ラウンドロビンの実装などが必要になってしまうため
もう少し簡単に利用できないものかな?と考えていました。
今回試した、Armeriaは、すごい簡単にService Discoveryを使ったクライアントサイドロードバランシングが可能で
本番に導入していきたいと思います。
今回はマイクロサービス間での利用を考えていますが、Androidでクライアントサイドロードバランシングしたい要求とかってあるのかな? あんまり聞いたことないんですが、Envoy Mobileみたいなのも出てきているので 需要はあるのかな?
今回の記事は、こんなところで。
Armeria、クライアントライブラリとして利用するだけでも非常に便利なので使っていきたい。 OAuth2周りの連携部分を組み込んで、本番導入を狙っていきたい。