読書メモ: 入門 eBPF

www.oreilly.co.jp

1章 eBPF とは何か?なぜ重要なのか?

eBPF の歴史

  • [1993年] 「BSD Packet Filter(BPF)」が論文に登場
    • eBPF のルーツは「BSD Packet Filter(BPF)」で、ローレンス・バークレー国立研究所の Steven McCanne と Van Jacobson により書かれた論文で初めて登場した。BPF は、プログラマが自分で書いたフィルタプログラムをカーネルの中で実行できるようにする機能で、プログラムは汎用的な BPF 命令セットを使って書くことができた。
  • [1997年] Linuxカーネルバージョン2.1.75 で初めて導入
    • tcpdump の中でトレースされるべきパケットをキャプチャするためのより効率的な方法として使われはじめた。
  • [2012年] seccomp-bpf がカーネル v3.5 で導入
    • この機能を使うと、ユーザー空間のアプリケーションがシステムコールを呼び出すことについて、BPF プログラムを使って許可するか禁止するかを決定できる。この機能はパケットフィルタの範囲を超えていて、この辺りから「packet filter」という名前はあまり意味を持たなくなった。
  • [2014年] 拡張された(extended)BPF(eBPF) がカーネルバージョン 3.18 でリリース
    • eBPF の基盤部分が追加され、この後の大きな進化につながる。
  • [2015年] eBPF プログラムを kprobe にアタッチする機能が追加
    • kprobe(kernel probe)はカーネル内のほとんどの命令に対してフックを入れて、追加の命令を実行できる。開発者は kprobe に関数をアタッチしたカーネルモジュールを書いて、デバッグや性能評価の目的に利用できる。
    • 同時期に、カーネルのネットワークスタック内部にフックが追加され、eBPF プログラムはより多くのネットワーク機能に対して利用できるようになった
  • [2020年] LSM(Linux Security Module)BPF が登場
    • これは eBPF プログラムに LSM カーネルインターフェースへのアタッチを可能にするもので、これによって eBPF はネットワークと可観測性に加えて、セキュリティツールとしての用途が可能になった。

なぜ eBPF?

eBPF によって、開発者はカーネルの振る舞いを変更できるカスタムコードを、カーネルの内部にロードし、実行することができるようになった。

今までこれを行うには、カーネルに新機能を追加するか、カーネルモジュールを書く必要があった。問題は前者はリリースまでに時間がかかるし、またどちらもカーネルプログラミングの技術が必要になる。また、安全に実行できるカーネルのコードを書くのが難しい問題もある。

その点、eBPF プログラムは動的ロードをサポートしているので、カーネルのアップグレードもマシンの再起動も必要ない利点がある。また、eBPF 検証器が eBPF プログラムが安全に実行できると判定されたときのみロードされることを保証する仕組みになっている。

2章 eBPF の 「Hello World

BCCHello World

MacOS を使っている場合は https://github.com/lizrice/learning-ebpf の手順に沿って、VM 上で実行環境を用意するといい。

# クローン
$ git clone --recurse-submodules https://github.com/lizrice/learning-ebpf
$ cd learning-ebpf

# lima のインストール
$ brew install lima 

# VM 起動
limactl start learning-ebpf.yaml

# VM ログイン
limactl shell learning-ebpf

VM ログイン後、次のように hello.py を実行すると、使用中のマシンで execve() システムコールが呼び出されるたびに "Hello World" の文字列を含むトレースが出力される。execve() システムコールは、新しいプログラムを実行しようとするたびに呼び出される。

yoheimuta@lima-learning-ebpf:/Users/yoheimuta/lizrice/learning-ebpf$ sudo -s

root@lima-learning-ebpf:/Users/yoheimuta/lizrice/learning-ebpf# cd chapter2/
root@lima-learning-ebpf:/Users/yoheimuta/lizrice/learning-ebpf/chapter2# python3 hello.py
b'           <...>-5873    [003] d...1   787.501458: bpf_trace_printk: Hello World!'
b'            bash-5873    [003] d...1   787.507280: bpf_trace_printk: Hello World!'
b'           <...>-5874    [001] d...1   787.509545: bpf_trace_printk: Hello World!'
b'           <...>-5875    [002] d...1   787.511014: bpf_trace_printk: Hello World!'
b'           <...>-5876    [000] d...1   787.512891: bpf_trace_printk: Hello World!'
b'           <...>-5879    [001] d...1   787.524347: bpf_trace_printk: Hello World!'
b'           <...>-5880    [000] d...1   787.525203: bpf_trace_printk: Hello World!'
b'           <...>-5882    [001] d...1   787.526269: bpf_trace_printk: Hello World!'
b'           <...>-5883    [000] d...1   787.527529: bpf_trace_printk: Hello World!'
b'           <...>-5885    [001] d...1   908.367247: bpf_trace_printk: Hello World!'

hello.py は次のようなコードで、BCC Python フレームワークを使って記述されている。このコードは二つの部分から構成されていて、最初の program 変数に C 言語で書かれた eBPF プログラムが定義されている。後半は、その eBPF プログラムをカーネルにロード、イベントにアタッチ、トレース結果を読み出すためのユーザー空間のコードになる。

#!/usr/bin/python3  
from bcc import BPF

program = r"""
int hello(void *ctx) {
    bpf_trace_printk("Hello World!");
    return 0;
}
"""

b = BPF(text=program)
syscall = b.get_syscall_fnname("execve")
b.attach_kprobe(event=syscall, fn_name="hello")

b.trace_print()

BPF Map

BPF Map は eBPF プログラムとユーザー空間の両方からアクセスできるデータ構造で、典型的なユースケースは次の通り:

  • ユーザー空間で設定情報を書き込み、eBPF プログラムからその情報を取得する
  • eBPF プログラム間で状態を共有する
  • eBPF プログラムから実行結果やメトリクスを書き込み、ユーザー空間のアプリケーションから取得して結果を表示する

様々な種類の Map が定義されており、例えばハッシュテーブル、Perf リングバッファ、配列として利用できる。

次のサンプルはハッシュテーブル Map を作成し、その Key に Linux のユーザーID、Value にそのユーザーが動かすプロセスが execve() を呼び出した回数のカウンタを記録する。 別ターミナルを立ち上げてみることで、このプログラムが execve() を記録できていることが確認できる。

# ターミナル1
# python3 hello-map.py

ID 501: 1
ID 501: 2
ID 501: 2
ID 501: 2
ID 501: 11
ID 501: 11
# ターミナル2
12:40:09 ~/lizrice/learning-ebpf $ limactl shell learning-ebpf

$ ls
LICENSE  README.md  chapter10  chapter2  chapter3  chapter4  chapter5  chapter6  chapter7  chapter8  learning-ebpf-cover.png  learning-ebpf.yaml  libbpf

$ echo $UID
501

前半が C 言語風で書かれた eBPF プログラムで、counter_table ハッシュテーブルにカウンタを書き込んでいる。 後半が python で書かれたユーザー空間のアプリケーションで、b["counter_table"] ハッシュテーブルからカウンタを呼び出している。

#!/usr/bin/python3  
from bcc import BPF
from time import sleep

program = r"""
BPF_HASH(counter_table);

int hello(void *ctx) {
   u64 uid;
   u64 counter = 0;
   u64 *p;

   uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
   p = counter_table.lookup(&uid);
   if (p != 0) {
      counter = *p;
   }
   counter++;
   counter_table.update(&uid, &counter);
   return 0;
}
"""

b = BPF(text=program)
syscall = b.get_syscall_fnname("execve")
b.attach_kprobe(event=syscall, fn_name="hello")

while True:
    sleep(2)
    s = ""
    for k,v in b["counter_table"].items():
        s += f"ID {k.value}: {v.value}\t"
    print(s)

3章 eBPF プログラムの仕組み

この章からしばらく内部構造の説明が続く。eBPF の利用者に詳細の把握は必要ないが、これ以降の章を理解するための最低限は整理しておく。

eBPF 仮想マシン

eBPF プログラムのソースコードが実行されるまでには次の変換を辿る:

  1. eBPF コードを開発者が C または Rust 言語で書く
  2. Clang コンパイラなどで eBPF バイトコードコンパイルする
  3. カーネル内にある eBPF 仮想マシンが eBPF バイトコードを動かす
  4. 実行時にバイトコードJIT コンパイルされて機械語命令(ネイティブマシン命令)に逐次翻訳される

カーネルへの eBPF プログラムの操作

ここでは bpftool というコマンドを使って、プログラムのロード・情報の確認・イベントへのアタッチなどを行う。 bpftool を使うと、BCC で記述して実行していた操作を、コマンドライン経由で行える。

man でも説明されている通り、ここでもデバッグ用途で使っていく。

BPFTOOL - tool for inspection and simple manipulation of eBPF programs and maps https://man.archlinux.org/man/bpftool.8.en

# ロード
$ bpftool prog load hello.bpf.o /sys/fs/bpf/hello

# イベントにアタッチ
$ bpftool net attach xdp id 540 dev eth0

4章 bpf() システムコール

ユーザー空間のアプリケーションがカーネルに eBPF プログラムをロードするには、bpf() システムコールを呼ぶ必要がある。

eBPF プログラムを作るときには、eBPF を高レベルで抽象化したライブラリを使うことが多いので、bpf() システムコールを直接呼ぶことはない。 ただ、ライブラリ関数は bpf() システムコールから呼び出す様々なコマンドとおおよそ 1対1 で対応しているので、bpf() システムコールの概要を知っておくのは必要である。

bpf() のシグネチャは次の通り:

int bpf(int cmd, union bpf_attr *attr, unsigned int size);
  • cmd はどのコマンドを実行するかを指定する。eBPF プログラムのロード、Map の作成、プログラムのイベントへのアタッチ、Map の Key-Value ペアへのアクセスと更新などに対応するコマンドがある
  • attr はコマンドのパラメーターを指定する。

以降は BCC プログラムを strace して、出力された bpf() のコマンドを詳説している。何か作るときにまた読むと良さそう。

5章 CO-RE、BTF、libbpf

多くの eBPF プログラムはカーネルのデータ構造にアクセスするため、あるマシンでコンパイルされた eBPF プログラムが別の Linux カーネルのバージョンで動く保証はない。 このカーネル間の移植性の問題には二つのアプローチが存在する:

BCC のアプローチ

BCC はマシン上で実際に実行するときに eBPF コードをコンパイルすることで移植性の問題を解決している。 ただし、このアプローチには次のような問題がある:

  • プログラムを実行したいすべてのマシンにコンパイルチェーンとカーネルのヘッダファイルをインストールしておく必要がある
  • プログラムを実行するたびにコンパイル処理が走るため、実行開始までに時間がかかる

このような問題があるため、BCC は実運用で使う eBPF プログラムの開発には向いていない。 一方で、Python のユーザー空間コードはコンパクトで読みやすいので、凝ったことをせずに即座に動かしたい場合は、BCC は第一候補になる。

CO-RE のアプローチ

CO-RE は compile once, run everywhere の略で、BCC よりもはるかに上手にカーネル間移植性に対処しているため、実運用ではこちらを検討することになる。

このアプローチでは、まずコンパイルされたデータ構造のレイアウト情報を eBPF プログラムに含める必要がある。この情報は BTF(BPF Type Format)と呼ばれる。Linux カーネルv5.4以降サポートされている。 そして、そのレイアウトが実行しようとしているマシンとで異なる場合に、フィールドのアクセス方法を調整することで移植が可能になる。

ライブラリによって、この調整を行う。この調整が可能なライブラリはいくつか存在する:

  • libbpf(Cライブラリ)。bpftool の裏側は libbpf
  • Cilium eBPF(Goライブラリ)
  • Aya(Rustライブラリ)

以降は libbpf を使用したコードを書く方法を紹介している。何か作るときにまた読むと良さそう。

6章 eBPF 検証器

eBPF プログラムをカーネルにロードするときは、検証プロセスによってプログラムが安全であることを保証している。 「検証(verification)」とは、プログラムを通して考えうるすべての実行経路をチェックし、どの命令も安全であると保証することを指す。

この章では検証器がどのようなことをしているかについて解説する。eBPF コードを書くときに発生する検証器のエラーを理解したくなったら、また読むと良さそう。

7章 eBPF のプログラムとアタッチメント

eBPF プログラムを書くときにはプログラムタイプを指定する必要がある。これによってそのプログラムがどのイベントにアタッチできるかを決定する。 プログラムタイプは大きく二つのカテゴリに分類される。トレーシングとネットワーク関連である。

トレーシング

Perf 関連のプログラムとも呼ばれる。このカテゴリに分類されるプログラムタイプには次のようなものがある:

  • kprobe: カーネル関数の入り口へのアタッチに使う。関数の引数にアクセスできる。
  • kretprobe: カーネル関数の終了時へのアタッチに使う。関数の戻り値にアクセスできる。
  • fentry: kprobe のより新しく効率的な代替。
  • fexit: kretprobe のより新しく効率的な代替。さらに戻り値だけでなく引数にもアクセスできる。
  • Tracepoint: カーネルコード内でマークされた場所。5.15 のカーネルでは 1400 以上の Tracepoint が定義されている。以前から SystemTap のようなツールでトレース出力に使われてきた。

ユーザー空間へのアタッチもできる。例えば、OpenSSL の SSL_write 関数の開始地点にアタッチできる。

  • uprobe/uretprobe: ユーザー空間の関数の開始と終了の地点へのアタッチに使う。
  • USDT(User Statically Defined Tracepoint): ユーザー空間のコードの特定の Tracepoint にアタッチできる。

ネットワーク

ネットワーク関連のプログラムタイプでは、トレーシング関連のプログラムタイプと違って、ネットワークの振る舞いをカスタマイズするために使われる。 例えば、ネットワークパケットをドロップしたりリダイレクトしたり、ソケットの設定パラメーターの変更を行う。

  • ソケット操作: TCP 接続に割り込んだり、TCP タイムアウトを設定したりできる
  • トラフィックコントール: 帯域制限の設定を変更したりできる
  • XDP: XDP プログラムは eth0 インターフェースなどにアタッチして、ネットワークデバイス上でパケットを処理できる。Linux のネットワークスタックに通る前に処理するので高速に動く
  • cgroup: 特定の cgroup において、ソケットの操作やデータ転送の実行を禁止できる

8章 ネットワーク用 eBPF

eBPF をベースにしたネットワークツールは広く使われている:

  • CNCF の Cilium プロジェクトによる Kubernetes ネットワークのカスタマイズ
  • Meta の Load Balancer
  • Cloudflare の DDos 防衛機能

これらはパケットのドロップや転送を XDP プログラムで実現することで、既存のものに比べて高いパフォーマンスを発揮している。 一部のネットワークカードは XDP オフローディング機能をサポートしている。これを使えば、全ての処理はネットワークカード上で完結するため、ホストマシンの CPU サイクルは 1 クロックも使わなくていい。

eBPF と Kubernetes ネットワーク

Kubernetes は CNI (Container Network Interface) を通して、どのネットワーク実装を利用するかをユーザーが選べる。 多くの CNI プルグインは Kubenetes における L3/L4 のネットワークポリシーを実装するために iptables を利用している。

Kubernetes では Pod とその IP アドレスが動的に更新されるため、iptables の更新に数時間かかる場合がある。 また、iptables のルール検索はルールの数に比例して時間がかかる問題もある。

Cillium は eBPF ハッシュテーブルで kube-proxy の iptables を置き換えることで、高いスケーラビリティを実現している。 Cillium は AWS, GCP, Azure で使える。

9章 セキュリティ用 eBPF

eBPF は不正な活動を検出・禁止するセキュリティツールを作成するためにも使われている。

Linux において、セキュリティイベントを検知するために使われるイベントは次の二つ:

  • システムコール
    • Docker や Kubernetes では BPF を使ってシステムコールを制限する seccomp という機能が使える
    • システムコールの追跡をベースにしたセキュリティツールで有名なものは、CNCF プロジェクトの Falco がある。Falco はセキュリティアラート機能を提供している。
  • LSM インターフェース
    • システムコールのフックは厳密なセキュリティツールの実装には不十分という問題を解決するために、LSM(Linux Security Module) API に eBPF プログラムをアタッチする新しい機能、 BPF LSM がある。
    • セキュリティの観点で好ましくないことが起こりうるシステムコールには、それに対応する LSM のフックが存在するので、eBPF プログラムをシステムコールの入り口の代わりにそちらにアタッチさせればいい。

10章 プログラミング eBPF

eBPF プログラムを書くときの最もシンプルな方法は bpftrace を使うこと。bpftrace を使えば、カーネル空間とユーザー空間の分離を意識せずにコードを書ける。 https://github.com/bpftrace/bpftrace/tree/master?tab=readme-ov-file#one-liners には便利なワンライナーのサンプルがたくさん載っている。

例えば、2章で BCC を使って書いた execve システムコールが呼ばれた回数を uid 別に集計するコードは bpftrace だと次のように書ける。

# 動作中のマシン上で利用できる kprobe の一覧を表示
$ sudo bpftrace -l "*execve*"
...
kprobe:__arm64_compat_sys_execve
kprobe:__arm64_compat_sys_execveat
kprobe:__arm64_sys_execve
kprobe:__arm64_sys_execveat
...

$ sudo bpftrace -e 'kprobe:__arm64_sys_execve { @[uid] = count(); }'
Attaching 1 probe...
^C

@[501]: 2
@[0]: 2

📝 https://github.com/bpftrace/bpftrace/blob/master/docs/tutorial_one_liners.md にあるチュートリアルはわかりやすい。

Vitess: Introduction, New Features and the Vinted User Story

www.youtube.com

関心のあるところだけ抜粋。

Introduction

  • 4 つのキーワード:
    • Keyspace は MySQL のデータベースに相当する。論理的なデータベースを表すので、実際は複数に horizontal sharding された物理データベースで構成される。
    • Shard は Keyspace の subset。Keyspace は複数の Shard で構成できる。1 Shard は 1 primary と 0 ~ n の replica で構成される。
    • VSchema は特定のテーブルをどう horizontal sharding するかを定義する。
    • VIndex は VSchema 内で利用されるもので、MySQL のインデックスに相当する。

Vinted User Story

  • Vinted は 8000 万ユーザーいる中古ファッションマーケット
  • Vitess を導入している。トラフィックは 2.2 Million QPS、38 TB data、5K VStreams
  • Why Vitess?
    • いくつかあるが、Throttling API はその一つ。バッチで db に負荷のかかる処理をするときに、負荷が上がりすぎたら処理を止めるようなコードが書ける。
    • もともとは application 側でシャーディングしていた
    • latency overhead は 2ms くらいで優秀という評価

New Features (v18, v19)

  • Query Serving
    • Basic CTE support for SELECTs
    • MySQL syntax extension: VEXPLAIN
    • DELETES with JOIN
  • Performance and Reliability
    • Connection pooling がより効率的になった。以前はまず pool が full になるまで新規接続を確立していたが、新規接続はコストがかかるのでなるべく行わない挙動に変わった。

Upcoming (v20+)

  • More CTE support

読書メモ: Prometheus実践ガイド: クラウドネイティブな監視システムの構築

どんな本?

Prometheus の概要から実践的な運用ノウハウまでまとまっていて、それを日本語で読めるのがポイント。 また、雑多になるのでここにはメモしてないが PromQL の解説も詳しいので、クエリの書き方に迷ったときの辞書としても便利そう。

Prometheus のアーキテクチャ

Prometheus のシステムを構成するコンポーネントは主に次の四つ:

  • Prometheus Server: Prometheus 本体。Exporter から受け取ったメトリクスを保存してクエリの実行を担う。
  • Exporter: メトリクスの収集。監視したい対象に合わせて必要なものを導入する。種類は非常に多く、200 以上存在する。
  • AlertManager: アラートの発報
  • Grafana: 収集したメトリクスの可視化

これらのコンポーネントは Go 言語で実装されており、シンプルなバイナリで提供されている。

Why Prometheus?

一つ目の理由は、他の監視システムに比べて構成がシンプルであること。 Web サーバーやデータベースといったミドルウェアが必要ないので、どんな環境でも導入が容易になってる。

二つ目の理由は、クラウドネイティブな監視が可能であること。 ここでいうクラウドネイティブな監視とは、監視対象となるシステムが頻繁に変化しても適切に追従でき、システム全体の正常性が常に把握できること を意味してる。 そのために Prometheus は、監視サーバーがクライアントに対してメトリクスを収集しに行く、 Pull 型のメトリクス収集の仕組みを採用している。 同時に、クラウドシステムではサーバーの IP アドレスもクライアントの数も固定されていないので、Prometheus はサービスディスカバリの仕組みも備えている。 サービスディスカバリは、クラウドサービスの API などを利用して対象の情報を能動的に取得・更新して、構成の変化に動的に追従して監視を継続できるようにする仕組みのこと。

三つ目の理由は、Kubernetes 上での監視のデファクトスタンダードになっているため、エコシステムが充実していること。 結果、エクスポーターが豊富に提供されている。サーバーのメトリクス監視には Node exporter、nginx の監視には nginx-prometheus-exporter、MySQL の監視には mysqld_exporter などが利用できる。 また、Kubernetes とともに CNCF にホスティングされている。Kubernetes 上で Prometheus を構築するための Prometheus Operator というプロジェクトもある。

データ構造とクエリ

Prometheus では、すべてのデータがメトリクスとして表現される。メトリクスは Key-Value 構造になっている。 たとえば、localhost:9090 マシンの CPU 使用率が 50% というメトリクスは、cpu_usage{instance="localhost:9090"} が Key で、50 が Value になるデータで表せる。 このとき、cpu_usage は メトリクス名、instance="localhost:9090" はラベルと呼ばれる。

メトリクスを取得するには、PromQL を使ってクエリを実行する。http_requests_total{instance="prometheus"} というクエリを実行すると、http_requests_total というメトリクスのうち、サーバー名に "prometheus" という文字列が含まれる情報を取得できる。

k8s 上のセットアップ

Prometheus の管理の効率化と自動化が可能になる、Prometheus Operator を使うのが良い。 カスタムリソースによって監視ターゲット設定を簡単に定義できる。

監視ターゲットを追加するには ServiceMonitor や PodMonitor を、ルールを追加するには PrometheusRule といった対応する CRD を定義する。

冗長構成

Prometheus の可用性を高めるためには、Prometheus 本体の冗長化と、AlertManager の冗長化をそれぞれ行う必要がある。

Prometheus 本体には冗長化の仕組みは備わっていないので、実現するには同一の設定を持つ Prometheus を二つ構築する方法が取られる。 こうすることで Prometheus はそれぞれ独立してメトリクスを収集する。

AlertManager では単純に複数起動するとそれぞれの AlertManager からアラートが発報されてしまうので、クラスタリングの仕組みが用意されている。 AlertManager を起動する際に別の AlertManager のアドレスをフラグで渡すことで、クラスターが構成される。 Prometheus からはクラスタ化された二つの AlertManager の両方にアラートを通知すればよく、あとは重複排除されて一つだけアラートが発報されるようになる。

ストレージ

Prometheus が利用するストレージには、ローカルストレージリモートストレージの二種類がある。

  • ローカルストレージは、Prometheus を起動しているサーバー上に作成されるストレージである。デフォルトでは、Prometheus のバイナリと同じディレクトリに data ディレクトリを作成し、そこに TSDB(Time Series Database)を構築する。
  • リモートストレージは、外部のストレージソフトウェアへメトリクスを転送する機能のことを指す。リモートストレージを利用するには、Prometheus のリモートストレージ機能に対応したソフトウェアを用意する必要がある。たとえば InfluxDB は標準機能として Prometheus のリモートストレージ API をサポートしており、比較的安定している OSS の時系列データベースである。

短期間かつ小規模であればローカルストレージでも十分実用に耐える。逆に、長期間データを運用する場合、PromQL のパフォーマンス低下などが問題になるのでそのような現象に陥った場合はリモートストレージの利用を検討すべき。

読書メモ: 大規模言語モデル入門

どんな本?

大規模言語モデルの理論と実践についての入門書。 英語だと、大規模言語モデルは Large Language Mode / LLM になる。

前半は大規模言語モデルの理論的な解説。 後半は Hugging Face が開発する Python ライブラリの transformers などを使って、実用的に使える日本語自然言語処理のモデルを作成する。

大規模言語モデルって何?何が新しいの?

大規模言語モデルは要するにニューラルネットワークのこと。 大規模なテキストデータを使って訓練された大規模なパラメーターで構成されたことで、飛躍的に性能が向上した点が新しい。

これを使うと自然言語処理(Natural Language Processing)のさまざまなタスクを解くことができる。 例えば、

  • 文書分類(document classification): ニュース記事などをジャンルに分類する
  • 自然言語推論(natural language inference; NLI): 二つのテキストの論理関係(矛盾してるとか)を予測する
  • 意味的類似度計算(semantic textural similarity; STS): 二つのテキストの意味が似ているかを予測する
  • 固有表現認識(named entity recognition; NER): テキストに含まれる固有表現を抽出する
  • 要約(summarization generation): 比較的長い文章から短い要約を生成する
  • 質問応答(question answering): 質問にコンピューターが回答する
  • 機械翻訳(machine translation)
  • 対話システム(dialogue system)

Transformer とは

Transformer を理解しないとこの本の前半を読むのが厳しかったので、まずはそこだけ他の資料も見つつまとめておく。

Transformer とは 2017 年に Google が提案したニューラルネットワーク。GPT などの今世の中で使われているモデルはこれをベースにしてるので大事。

GPT (Generative Pre-trained Transformer) は Transformer を採用した最初の大規模言語モデルで、2018 年に OpenAI が提案した。Transformer が設計で、GPT がその実装という関係。BERT とか T5 も実装。

ニューラルネットワークを歴史的にみると、Convolutional Neural Network (CNN) は画像などを扱う Vision タスクを解くには優秀で、2012 年以降写真の中の物を特定するとかは進展していた。一方で、言語の解析は遅れていて Recurrent Neural Network (RNN) が使われていた。RNN の問題は、長いテキストを扱えないこと、トレーニングを十分に並列して行えないので遅く結果として大量のデータを扱えないことの二つがあった。Transformer は両方の問題を解消したことで、GPU を同時に動かして、例えば GPT-3 なら45TBのトレーニングデータを使った大規模言語モデルを実現している。

www.youtube.com

どうやって大規模言語モデルを使うの?

本書の後半ではいくつかの自然言語処理を解くために、公開されているモデルとデータセットを transformers から利用する方法が紹介されている。 基本的には、大規模言語モデルがすでにあって、そこにファインチューニングを施して個別タスクに適応させて解く。

transformers を使えばかなりシンプルだが、それでも評価・エラー分析は地道に作業が必要。

本書の最後には ChatGPT API を使った検索システムの実装例も載っている。外部の情報を検索させるために、プロンプトにクエリの関連情報を載せる手法が紹介されている。

2023 年振り返り

あけましておめでとうございます。2023年もお世話になりました。

2024 年もよろしくお願いします。

私生活

  • 体調管理
    • 健康です。熱が突然出るとかはあった気がしつつ、仕事を休むほどにはならなかったです
    • 家族の体調に左右されてリモートワークを選択することが何度かありました。アフターコロナ時代で気を遣った面もあります
  • 旅行
    • 5月に軽井沢に二泊三日しました。東京からのアクセスは抜群で、北陸新幹線なら70分です。ゴールデンウィークの翌週に行ったので混雑なく過ごせました。山を散策したり、いちご狩りしたり、自然を満喫できました。
    • お気に入りの白馬キャンプは、当日に子どもが高熱でキャンセルしました 😿

野鳥の森でバードウォッチング

  • 子育て
    • 四歳になって色々できるようになってきたので、サッカー教室に入れました。気に入ったようで、公園遊びのレパートリーに「サッカーボールで遊ぶ」が増えました
    • 本がそんなに好きそうでなかったので、毎日朝晩絵本の読み聞かせ + 隔週で図書館通いを一年間徹底したら、本好きになりました。表紙が飾れるラックに借りてきた絵本を並べておくと興味が向きやすくなるのでオススメです。
  • 読書
    • 英語の勉強も兼ねて、2023年は小説を多めに読みました。「Secret Garden」「Matilda」「To Kill a Mockingbird」など。
    • 中でも 「Anne of Green Gables(赤毛のアン)」は実は続編があって、シリーズ2と3まで読むほどには面白かったです。シリーズ3「Anne of the Island」はアンの大学時代(18~22)の話です。1915年出版にも関わらず、大学生活は今とそんなに変わらないのが読んでいて新鮮な驚きでした。
  • 雑感
    • 夏の間、貸菜園でトマト・きゅうり・なす・ピーマンなどの夏野菜を育てました。1~2週間ごとに通うのは大変でしたが、収穫は週末の楽しみになってました。10月になると寒いので一夏でやめましたが、また機会があればやりたいです。
    • インフレと円安もあって、2023年はお金のことを考える機会が多かったです。

炎天下の中、野菜のお世話

仕事

  • 入社から三年半経ちました
  • 開発チーム全体を振り返ると、施策の開発スピードは相変わらず早く、一方で安定性と開発生産性をバランス良く維持できたと思います 👍
  • 個人的に大きな issue として、前半に Vitess の本番導入が、後半に Flink のステージング導入ができました。Vitess は当初から期待していた MySQL 接続集約による接続上限の回避に加えて、Thread_running が下がったことで slow query を大きく減らす効果もありました。一方で、proxy の割にリソース消費量が大きいのは意外でした。Flink は今後のシャーディングを見据えて、複雑な JOIN クエリのマテリアライズテーブルをリアルタイムに作成するために使う予定です。
  • 2024 年のあけおめピークは無事障害もなく乗り越えることができて感無量です 😂
  • 2023/12/21 4:00 に障害がありました。GKE クラスタの Pod が問題なく起動するにも関わらず LB(NEG)に入るタイミングで Error syncing to GCP: error running backend syncing routine: googleapi: Error 400: Invalid value for field 'zone': ''. Must be a match of regex '(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)', invalidという身に覚えのないエラーが発生しはじめて、リクエストが全く届かなくなりました。結局、その場で GKE クラスタをコピーして Ingress 含めた主要リソースを全部移行するという大工事で乗り切りました。GCP サポートとともに原因特定に取り組んでますが、GKE 自体に根本原因がある可能性も残ってます。

ソフトウェアエンジニアリング

  • 2023 年も Vitess に bug fix や feature request の PR を送り続けました。中でもパラレルのユースケースで特に対応が必要だった issue は次の三つです。
    • github.com
      • v15, v16 には、MySQL サーバーが高負荷で一時的に応答不能になるとその前段にある vttablet component の再起動が走るバグがありました。v17 では修正されてます。
    • github.com
      • v15, v16 には、vttablet の rolling update 時に最大1分間リクエストが MySQL まで届かなくなるバグがありました。こちらも v17 で修正されてます。
    • github.com
      • vitess-operator で unmanaged MySQL 構成を実現する場合、MySQL Replica ごとに vtgate/vttablet のセットが必要です。次にリリース予定の v2.12 ではこの冗長な設定は不要になります。
  • 自分のプロジェクトだと protolint 関連のメンテナンスが中心でした。
    • protolint のインストール方法がさらに増えました。Maven Central 経由npm パッケージ経由 でも利用できるようになりました。
    • もともと実装されていた、キャメルケースをスネークケースに変換する処理(例: accountStatus -> account_Status)でエッジケースの要望対応に少し苦労しました。小文字と大文字の間に _ を入れるというシンプルな実装になっていたので、ITDepartmentRegion は ITD_epartment_Region に変換されてました。それを IT_Department_Region に変換したいという話です。最初、大文字二つと小文字があったら大文字間に _ を入れるルールを追加したら、この例は解決しました。一方、今度は ListAccountOAuthsEnabledFilter が List_Account_O_Auths_Enabled_Filter になるデグレが報告されました。結局、大文字が三つ以上並んで最後が小文字のときに限定して、末尾の大文字二つの間に _ を入れるとちょうど良くまとまりました。こういう地味な作業は ChatGPT ならすぐに書いてくれると思ってましたが、全く要件を満たしていないコードを生成し続けるので、愚直にやりました。

2022 年振り返り

あけましておめでとうございます。

2022 年は、生活全般と専門的なソフトウェアエンジニアリングを分けて、振り返りをまとめました。 この記事は生活全般についてです。

私生活

  • 体調管理
    • 風邪症状は何度かありましたが、仕事に支障が出るほどではありませんでした。
    • どちらかというと、予防接種や自宅待機、保育園休園によってリズムが崩れることが多い一年でしたね。
    • 子どもの予防接種全三回が 2023 年の 4 月までに終わるので、それで多少は落ち着いてくれるのを祈る日々です。
  • コミケ
    • 2022 年は夏コミ(C100, 8/14)と冬コミ(C101, 12/31)の二回手伝いに行きました。人も徐々に戻ってきているような気がして、C99 ほど寂しい感じではなかったです。
    • 冬コミは二スペだったのでスペースが広く使えて、いつもより余裕を持って望めました。毎回こうだと長時間緊張を強いられなくて済みます。
      設営をはじめて少し経った 7:27 AM の東ホール
  • キャンプ
    • 白馬駅から歩いて 10 分ほどのところにある、「スノーピークランドステーション白馬」でキャンプしました。最高だったので、2023 年も行きます。緑溢れる自然の中にスタバがあって便利なので、小さいお子さんがいる家族でのキャンプデビューにぴったりですよ。
    • 行きは新宿駅から白馬駅まで「特急あずさ」、帰りは長野駅から東京駅まで「新幹線かがやき」に乗ったので、鉄ちゃんの息子も 😁
      キャンプ場の区画。真ん中のテントを建ててから BBQ して寝袋に入ります
      その裏側にある、スタバやトイレを含む現代的な建物
  • 子育て
    • 三歳になると、言語能力がメキメキ上がってきます。一年前は聞いて理解はできていそうだけど〜、というくらいでしたが、今やしっかり自分の考えを伝えられるし、理解できなければ質問してきます。それに伴いある程度落ち着けるようにもなったので、一安心です。
    • ピアノ教室はリトミッククラスから鍵盤クラスに上がりました。毎日、練習してます。白馬に行ったときもおもちゃのピアノを持っていき、保育園を休んだ日もピアノだけは休まずやっている気がします。自分も一緒にピアノを最初から練習できて楽しいですね。小学生に上がるくらいまでは自分の方が常に先を行けるだろうと思ってましたが、暗譜能力・絶対音感・小指と薬指の稼働は早々に抜かされてしまいました。特にピアノの音当てゲームを一緒にやったときは全くわからないので、ふざけてると思われてしまい、終始怒られました。
    • 足が早いです。外に行ったときの彼の第一声はいつも「よし、走ろう!」です。長所を伸ばしてあげるために、最近は週末遠くの公園や庭まで足を運んで、自然の荒れた地面で走り込みさせてます。「教育の森公園」にある「占春園」という庭園がお気に入りです。
      これは文京区にある「関口台公園」です。死んで浮き上がった魚を枝でつついているところ

ベスト of 2022

  • 買ったもの:
    ホワイトボード
    • ピアノ練習の、「長期課題」とそこからブレークダウンした「やること」が多すぎる上に更新も早くて漏れやすいので、導入しました。
    • 両面があって大きいホワイトボードを選びました。一面は親が使う用で、もう一面は子どもが自由に書く用です。両面必要かとか大きい必要があるか迷いましたが、子どもからひらがなや数字を聞かれたときにすぐに書いてみせることができるし、大きい字で書いてあげられるのでこれで正解でした。
  • ブック(フィクション)
    • www.goodreads.com
    • 19 世紀のイギリス(主にロンドン・オックスフォード)と中国(広東)が舞台。アヘン戦争がはじまるまでの歴史を忠実になぞるように物語が進むので一見フィクションではないようですが、描かれる世界には一つだけフィクションが入ってます。この一つのフィクションを背景に、幼少期を中国で過ごした少年がイギリスに単身連れて行かれて青春期を過ごすという話です。アヘン戦争を前にして、どちらの母国のために戦うのかというのが一つの盛り上がりです。「現実に一つだけ映像映えするフィクションがある」、「アウトサイダーがインサイダーになろうと葛藤する」、「主人公が特別なスキルを持っている」、という特長に興味がそそられるようであればオススメの一冊です。
  • ブック(専門書)
    • www.goodreads.com
    • books.rakuten.co.jp
    • パラレルで業務委託を長く続けてくださってる、インフラスペシャリストの大山さんに二〜三年前におすすめされた本。こちらは和訳もありますが、原著でも平易な英語で書かれていて読みやすかったです。
    • 3 年前からベビーシッターさんをお願いするときには、英語の勉強も兼ねて日本人ではない人にもお願いしてます。2022 年だけでも、フィリピン人・インド人・中国人・アメリカ人・イギリス人・カナダ人・フランス人・ロシア人・スペイン人が家に来ました。Agency を挟まないで直接やり取りすることが多いので、しっかりコミュニケーションを取らないといけません。ただ、中々思い通りに動いてもらえないことも多く、何かしらコミュニケーションのヒントを得るために手に取りました。
    • 本を読むだけで解決とはいかないですが、「国(異文化)による常識には大きく違いがあること」、「そういう常識が大きく違う人同士でのコミュニケーションに最適化されたプロトコルがあること」、を豊富な具体例で説得力を持って知れたのは良かったです。異文化チームを率いるときのプロトコルは例えば、リーダーが自分の常識を事前にチームに伝えておくことでチーム共通のルール・基準を最初に設けること、などがありました。常識の違いについては、日本人が相当変わっているというのに気付かざるを得ないので読んでいてクスっとできます。下のマッピングは同じ著者の別記事からの引用ですが、リーダーシップと意思決定に関わる日本人の特徴が際立ってます。日本は Hierarchical x Consensual の象限の端で孤立してますよね。ボスの指示を待って部下は意見は控えることが社会的に期待される一方、いざやるとなったら部下全員の合意を得ないと反発が起きるという意味です。その象徴が稟議(Ringi)です。真反対に位置する Egalitarian x Top-down のアメリカは、コミュニケーションは対等にやるのが好まれる一方で、決めるのはボス一人に一任されているので部下の合意は必要ないという常識です。そういう視点でアメリカのドラマを見ると確かにと思うことがありますよ。また、日本のような文化でアイデアを出してもらうなら、あえて上司抜きでミーティングする機会を作るのが有効と書いてありました。

リーダーシップ文化のマッピング

仕事

  • 会社
    • 入社から二年半経ちました。
    • Tech Group のオーナーを担当してました。この Group の中に、Native Unit / Unity Unit / Infra Unit があって、全エンジニア職がどこかに所属してます。Infra Unit のオーナーも兼務していて、この中にさらに Database Team / Android Infra Team / Voice Chat Team がありました。
    • Database Team は MySQL の負荷対策を中心に行っていて、スケールアウトを見据えた Vitess 導入はここで行ってます。Vitess はシャーディング用途だけが注目されますが、シャーディング前であっても ProxySQL のように間に挟めばコネクション集約によるパフォーマンスメリットが期待できます。これを Unsharded Vitess と呼びます。MySQL スケールアウトのソリューションは色々ありますが、アプリケーションコードの変更が最小限であること、段階的に導入できること、費用が抑えられること、InnoDB の過去の知見が活かせること、類似ユースケースにおける導入実績、を踏まえて Vitess 採用を決めました。
    • Android Infra Team は Android アプリのパフォーマンスと開発生産性を改善するために立ち上げました。前者は例えば起動時間(Cold Start)が 50 % 削減できましたね 🎉 後者は開発生産性がどういう開発のときに落ちるのかを整理した上で人のアサインや体制変更で手当したのが即効性があって有効だったと思います。道半ばではありますが、たくさんのアイデア出しと分析・検証作業を通して、どれくらい理想と今が乖離していて、そのために何をどれくらいのリソースでやる必要があるのか、即答できるくらいに自分たちのシステム理解が深まったのも一つの成果だと思います。
    • Voice Chat Team は通話品質を安定的に提供するための改善や不具合修正を行いました。このチームが立ち上がった一年半前は社内外から通話トラブルの報告を常に受けていた状況でしたが、2022 年後半にもなるとすっかり落ち着きました。通話はネットワーク回線、デバイス、周辺機器(イヤホン・マイク)からも影響を受けるので完全に問い合わせがなくなるということはないですが、そこから共通する要素をまとめて issue 化する段階になると数はぐっと少なくなりました。また、ノイズキャンセル機能の導入(Android)・安定化(iOS)もできましたね。
  • 実装
    • Amazon Prime 同時視聴機能の POC を iOSAndroid で作って、これは最終的にパラレルに組み込まれました。デジタルコンテンツの著作権を管理するための技術である DRM(FairPlay/Widevine)にはだいぶ詳しくなりましたよ 😎
    • MySQL のシャーディングソリューションとして Vitess の導入作業中です。まだシャーディングはしないので、Proxy として間に挟むだけです。
  • 障害
    • 2022 年は障害の規模も小さく、頻度も少なかったです。障害の都度、再発防止策を入れてもらったおかげでどんどん安定化してきたと思います。
    • と思っていたら年明け早々の 2023/1/1 0 時にサービスダウンしました。その間終始パソコンの前に張り付いて対応しました。あけおめ時のスパイクがすごかったですが、もっと精進が必要だと思った 2023 年幕開けでした。Twitter のトレンドに「パラレル」が載っていたようで規模感を知る貴重な機会にはなりましたね。
  • 第一回 Tech Group 忘年ホームパーティ
    • 同僚のお家でお昼から忘年会させてもらいました 🏠 素敵な新居でクリスマスツリーをバックに記念写真まで撮ってしまいました。幹事をしてくれた別の同僚含め、ありがとうございました。
    • 東京近辺も広いので、こういう機会を利用して馴染みのない土地に足を運べるのはそれだけで学びがあります。
    • 生産性の秘訣を探るためにリモートワーク環境を拝見させてもらうという裏目的をすっかり忘れていたので、次回はそこの見学ツアーも打診しなくては(その前にまずは自分が招待する側にいってからだろうというツッコミも)。

2022 年振り返り(ソフトウェアエンジニアリング)

あけましておめでとうございます。

オープンソース活動は変わらず元気に続けてます。 子育ての中で時間を見つけるのは大変なので、子どもが生まれた直後からベビーシッターを積極的に利用してます。

2022 年は、専門的なソフトウェアエンジニアリングと生活全般を分けて、振り返りをまとめました。 この記事はソフトウェアエンジニアリングについてです。

登壇

4/23(土)に開催された Go Conference 2022 Spring に登壇しました。

Protocol Buffer 言語をパースする go-protoparser と Protocol Buffer スキーマファイルをチェックする protolint を自作したときの経験はどこかで整理しておきたいと思っていたので良い機会になりました。

Go Conference 2022 Spring で採択されたプロポーザル(CfP) - yoheimuta’s blog にそのときの Cfp(プロポーザル)を公開しているので、発表背景など詳しくはそちらを参照してください。

発表後、下のように書いてくれた方(自分のすぐ後のセッションで GC について発表されていた)がいました。 レキサーとパーサーを分けて実装するという一番伝えたかったポイントに言及されていて良かったです。 自分にとっては当たり前になってましたが、実際に書くときにはその発想にならなかったり、どう書くかわからないものだと思います。

他人がオーナーのプロジェクトへの参加

所属企業で MySQL のシャーディングソリューションに Vitess を採用することにしたので、今年の後半は合間の業務時間も使って Vitess にいくつかコミットしました。 Vitess の CDC キャプチャには Debezium を使うのが一般的なので、そちらにもコミットしました。

debezium/debezium-connector-vitess

Debezium は変更データキャプチャ (Change Data Capture; CDC) のための低遅延データストリーミングプラットフォームを提供するオープンソースプロジェクトです。Debezium は MySQL のシャーディング用プロキシである Vitess にも対応していて、debezium-connector-vitess がその実装にあたります。

github.com

  • debezium-connector-vitess には他のすべての connector(例えば debezium-connector-mysql)でサポートされている、起動時のスナップショット取得機能がサポートされていませんでした。Vitess のバックエンドである MySQL のバイナリログは通常一定期間で削除されるので、バイナリログのストリーミングだけだと完全なデータを再現することができません。例えば、シャーディング後の MySQL クラスタで以前のような複雑な JOIN クエリをサポートするために、Flink などでリアルタイムに Materialized テーブルを作ろうと思ったとき、これだと困ります。
  • この PR がマージされた v2.1 からは、Debezium を起動するとまず MySQL クラスタ(Vitess)の現在のスナップショットを一貫性を保ったまま取得して、それが完了してから更新履歴のストリーミングがはじまるようになります。
  • Slack/Salesforce 社もこの機能を要望していて、設計やレビューを手伝ってくれました。最初に大規模に使いそうなので、問題なく動いて欲しいです 🙏
  • v2.1 は 2022.12.22 にリリースされてました

vitessio/vitess

Vitess は MySQL の水平スケーリングを行うためのデータベースクラスタリングを提供するミドルウェアです。 YouTube が開発して後に OSS 化されました。データベース分野で初の CNCF の Graduated project です。

Slack, Square, GitHub, Shopify, HEY (DHH の) など導入事例は豊富で、これらの会社が積極的にコントリビュートしてます。

github.com

  • Vitess は多くのコンポーネントが協調動作して動くので、開発環境を作ったりそれぞれの挙動を理解するのが最初の関門です。幸い examples ディレクトリがあるので、そこで docker-compose up -d したらまさかの失敗、というわけで修正しました。レビューの過程で開発者から細かいところを指摘してもらえたので、システム理解を深める良い機会になりました。Vitess v15 リリースのコントリビューターにちゃっかり入ってたのは 🉐。

github.com github.com

  • 前述の debezium-connector-vitess にスナップショット機能を追加する上で見つけた課題に対応した PR たちです。ほかにも一つがレビュー中、もう一つが実装待ち(自分の)です。Vitess v15 以下には connector のスナップショット機能を fault tolerant するために必要な機能が欠けてます。fault tolerant とは例えば、失敗したらリトライするなどです。Vitess 公式 slack のスレッドで相談しつつ、issue 化しては PR を投げてます。これ専用のスレッドは、2022.08.22 からはじまり、こんなに長いスレッドはお目にかかれないというほど長大になってます。振り返ると、メンテナーに意図が伝わらなかったり、レスポンスが長い時間返ってこなかったときには焦った記憶があります。
  • Vitess v16 に入る予定なので、そちらがリリースされたら debezium-connector-vitess にリトライ機能を入れたいです。

自分がオーナーのプロジェクトへの参加

細かいのを挙げるときりがないので、印象深いリリースや出来事を五つ挙げます。

yoheimuta/protolint

protolint は Protocol Buffer のスキーマファイルが、Google公式スタイルガイドに関するルールや独自ルールに違反していないかチェックする linter/fixer です。 plugin も書けるので社内独自ルールの違反も見つけることができます。

今年は、長年の悲願だった「必須ルールすべてに fixer を実装する」がようやくできました。 fixer が揃ってからスター数の増加傾向も少し高くなっている気がします。353 ⭐

github.com

  • linter で見つかったルール違反を自動で直してくれます。自分の中では fixer と formatter は別物という認識で、formatter はあるスタイルに沿って全部書き換える一方、fixer は一つ一つの細かいルールごとに修正してくれるものです。その意味で、protobuf の fixer でこれくらい細かいルールに対応しているソフトウェアは OSS にはないと思います。
  • 需要があるのはわかりつつ、linter の中で lexer を再度動かすという設計(これが一番書く量が少なく実装できる)に二の足を踏んでいたのですが、下のようなツイートを燃料に書き上げました。おっしゃるとおり。今はそんなことないので、使ってみてください 🤝

github.com

  • fixer の拡充が終わって数カ月後に受け取った機能リクエスト。fixer で直されると後方互換性が壊れるから、違反した行だけ 「rule 適用を無効にするコメントを挿入する」オプションを用意して欲しいという内容。
  • これは感銘を受けたリクエストで、API 用途で利用されるスキーマファイルの linter/fixer ならではの要望です。ソースコードの変数名のケースを直して互換性が壊れることはあまりないので、普通の fixer はそこまで考慮を求められないと思います。この人たち(当時は Secureworks という会社のアカウントっぽかった)のように多くのリポジトリを抱えているところには大事そうなので対応しました。
  • この対応で、protolint -fix -auto_disable=next . で互換性を保ったままスタイル違反を修正できるようになりました。すでにコメントを使って rule 適用を無効にする機能はあったので、この PR ではそのコメントをルール違反があった行の直前に挿入するだけで楽勝だと思っていたら全然そんなことはなくて、だいぶうんうん唸りながら書くことになりました。まず、すべてのルール修正が後方互換性を壊すわけではなくて、例えば import 文のソートは API 処理時には関係ないのでこれをどう扱うかを決める必要があります。後方互換性を壊すルールだけコメントを挿入してそれ以外は今まで通り直してしまうことにしました。次に、コメントをどこに挿入するかで、シンプルなのは違反がある行の上になるのですが、リクエストをくれた人は inline コメントがお望みでした。inline だとすでにコメントが書いてあったときどうするのかとか、1 行 80 文字を超えたときに別の lint エラーが発生するのをどうするか、複数の rule 違反が同じ行で重なったときにはどうするかなど色々なケースを考える必要が出てきます。あまりオプションを増やしたくもないので、良いバランスを探るのとそれを実装するのが大変でした。

blog.cybozu.io

  • cybozu.com のバックエンドでスキーマファーストな開発手法を導入するにあたって、社内独自ルールを強制するために protolint の plugin 機構を活用している、というアドベントカレンダー記事です。
  • 記事中、感謝されたり褒められていて読んでて気持ちよかったです(耳が痛いところは素通りしているとも言えるかも)。plugin の作り方がすごい丁寧に書いてあるしサンプルリポジトリもあるので、README からリンクを貼らせてもらったほうがいいかも。
  • plugin 機構はどれくらい使われているかわからなかったので、あまり目が行き届いていないかもしれません。ビルトインのルールと同じことができないとかあったら feature request か PR ください 😸

github.com

  • 自分が知らないところで、Homebrew 本体に protolint が年末組み込まれていました。5,463 個(現時点での homebrew-core にある Formula 数)あるソフトウェアの仲間入りです。これで brew install protolint だけでダウンロードできるようになりました 🎉

yoheimuta/action-protolint

reviewdog で protolint を動かす GitHub Action を公開しました。

github.com

reviewdog を使ってみたい、GitHub Action を公開してみたい、というだけをモチベーションに着手しました。 reviewdog は PR review 時に見やすくて便利、GitHub Action は Dockerfile と action.yaml の二つを用意すれば簡単に作れる、という触れ込み通りだけど、その実感を得られたのが学びですね。

投稿した記事

itnext.io

  • MySQL をシャーディングしたときに isolation level がどう変わるのか整理した記事を書きました。MySQL のデフォルトの isolation level は REPETABLE READ ですが、一般にシャーディングするとより isolation が緩い READ COMMITTED になると言われてます。そのような挙動の変化がどうして発生するのか、また具体的なアプリケーションでそれぞれがどう動くのか、自分が Vitess 導入過程で気になった疑問に答えました。整理しながら、分散 MySQL で REPETABLE READ を実現している TiDB はすごいと思う一方、それがすべてのユースケースで求められる要件でもないと再確認できました。

読んで良かった本

www.oreilly.com

  • Apache Flink 入門書です。少し情報は古いですが、公式ドキュメントよりも体系的にまとまっているので、まず全体像を掴むのにとても役に立ちました。子どもとコロナ隔離中に読んでいたので、子どもには「今からリスの図鑑読むね」と言い聞かせてました。
  • この本を読みながら、Flink SQLflink-cdc-connectors を使った MySQL の Materialized Table リアルタイム作成の POC を作りました。Flink SQL は強力で、いつも通りの JOIN 文を書くだけで、裏側で負荷を考慮したストリーミング JOIN を行う JobGraph (Dataflow) が出来てしまいます。flink-cdc-connectors は Debezium を内包しているので、インフラ構築は Flink 導入だけで済みます。処理を再開するときには、MySQL のバイナリログを途中から読むか、スナップショットを取って最初から読み込めばいいので、わざわざ Kafka を立てる必要もありません。