Kubernetes と CSI(Container Storage Interface) について
この記事は Kubernetes2 Advent Calendar 4 日目の記事です。
本記事は CSI(Container Storage Interface) と Kubernetes での CSI のサポートについて触れます。 執筆に時間があまり割けなかった為、後でもう少し加筆する、あるいは別途続きの記事を書くかもしれません。
CSI(Container Storage Interface) とは
CSI(Container Storage Interface, 以下 CSI) は Kubernetes など複数の Container Orchestration (CO) から共通のプラグインを使って SP (Storage Provider) とやり取りするためのインタフェース仕様です。 より具体的には、 CO からストレージを抽象化した Volume をアタッチ・デタッチしたりスナップショットを取ったりする機能のためのインタフェースを提供します。 CSI は Kubernetes とは独立したプロジェクトで進行しております。
また Kubernetes のプロジェクト以下で、 Kubernetes から SP が提供する CSI プラグインへ通信するための CSIDriver と関連実装を以下プロジェクトで進行しています。
Kubertenes としては CSI は 1.9 で Alpha 、 1.10 で Beta サポート対象になっています また Kubernetes での CSI 利用については他に既に試されている方もいるようです。 こちらの記事は詳細に踏み込んだ構成説明などもされており、オススメできる内容になっています。
CSI の仕様
CSI のインタフェース仕様は Protocol Buffer で定義されており、以下リポジトリで管理されています。
またこのリポジトリ内の lib/go/
ディレクトリには .proto ファイルの定義に従ったライブラリの Go 実装が配置されています。
CSI のプラグインは Controller plugin, Node plugin の二種類が想定されております。 また CO とこれら CSI プラグイン間は gRPC で通信することが想定されています。
CSI のサービス
CSI のサービスとして以下三種類が想定されています。
構成によっては実装しなくても良いサービスやメソッドがありますが、少なくとも Node Service の NodePublishVolume
, NodeUnpublishVolume
は実装する必要があります。
(でないと Node から Volume を参照できないはず)
- Identity Service
- CO から Plugin のケーパビリティ (後述) やヘルスチェック、メタデータ参照を可能にするサービス
- Controller Service
- Node をまたいで Volume の構成を管理するためのサービス
- Volume のスナップショット操作もサポートする
- Node Service
- 各 Node から Volume の操作を可能にするためのサービス
CSI における Volume の状態遷移
CSI で Node から Volume を利用されるまでに、 Volume は基本的に以下のような状態遷移をしていきます。 幾つかの状態は、プラグインが示す後述の CSI ケーパビリティによって存在しなかったりします。
CreateVolume +------------+ DeleteVolume +------------->| CREATED +--------------+ | +---+----+---+ | | Controller | | Controller v +++ Publish | | Unpublish +++ |X| Volume | | Volume | | +-+ +---v----+---+ +-+ | NODE_READY | +---+----^---+ Node | | Node Stage | | Unstage Volume | | Volume +---v----+---+ | VOL_READY | +------------+ Node | | Node Publish | | Unpublish Volume | | Volume +---v----+---+ | PUBLISHED | +------------+
ref. https://github.com/container-storage-interface/spec/blob/master/spec.md#volume-lifecycle
CSI のケーパビリティ
CSI プラグインでどのような操作をサポートするかの情報です。 CSI の仕様としては以下 4 種類のケーパビリティをサポートします。
- PluginCapability
- VolumeCapability
- Volume のファイルシステムのタイプやアクセス制御(リードオンリーなのかなど)、容量などの情報を含む
- CO は
CreateVolume
,ControllerPublishVolume
などのメソッドで指定や値の検証が可能
- ControllerServiceCapability
- Create/Delete , Publish/Unpublish などの操作をサポートするかの情報を含む
- CO は
ControllerGetCapabilities
メソッドで取得可能
- NodeServiceCapability
- Stage/Unstage などの操作をサポートするかの情報を含む
- CO は
NodeGetCapabilities
メソッドで取得可能
CSI の利用用途
CSI プラグインとしてはすでに、 NFS や iSCSI などの公式のサンプルプラグインを含め、 AWS や GCP のストレージサービスの利用を可能とするプラグインが存在します。 以下の公式ドキュメントに既に存在する CSI プラグインに関する記述があります。
簡単な CSI Plugin の実装を追ってみる
以上だけだと CSI プラグインの動作が把握し難いので、 kubernetes-csi の drivers リポジトリにある HostPath plugin の動作を追ってみます。 このプラグインはリポジトリに kubernetes への deploy 用 yaml ファイルも同梱されており動作を追うのに便利です。
HostPath plugin では CSI の Identity, Controller, Node 三種類の gRPC サービスを提供します。
その実装は github.com/kubernetes-csi/drivers/tree/master/pkg/hostpath
に存在します。
Identity Server は特に特殊な実装をしていません。
github.com/kubernetes-csi/drivers/blob/master/pkg/csi-common
に存在する、他の Driver と共通のデフォルトメソッド実装をそのまま使用しています。
Controller Server では CreateVolume
, DeleteVolume
, CreateSnapshot
, DeleteSnapshot
, ListSnapshots
を実装します。
CreateVolume
, DeleteVolume
では複雑なことをしておらず、 UUID 付きの名前のディレクトリを掘って Volume に見立て、 map で Volume の管理を行います。
CreateSnapshot
, DeleteSnapshot
はそれに似て、 Volume のディレクトリを tar czf
で固めて同じく UUID 付きのファイルに保存・管理します。
Node Server では NodePublishVolume
, NodeUnpublishVolume
, NodeStageVolume
, NodeUnstageVolume
を実装します。
NodePublishVolume
, NodeUnpublishVolume
は作成された Volume のディレクトリを k8s.io/kubernetes/pkg/util/mount
パッケージを介して mount/unmount します。
NodeStageVolume
, NodeUnstageVolume
は単にリクエストパラメータ中の Volume や ターゲットパスが空でないことをチェックしているだけになります。
HostPath プラグインでは他に複雑なチェックをする必要が無いためこうなっているのではと思われます。
kubernetes 上で想定される構成は以下の通りになっているようです。
- Controller Server のメソッドの参照
CreateVolume
など Volume の作成・削除は https://github.com/kubernetes-csi/external-provisioner コンテナを利用ControllerPublishVolume
など Volume の Publish 操作は https://github.com/kubernetes-csi/external-attacher を利用CreateSnapshot
などスナップショットの操作は https://github.com/kubernetes-csi/external-snapshotter を利用
- Node Server のメソッド参照
- https://github.com/kubernetes-csi/driver-registrar を使って CSIDriver を kubelet から参照可能にする
- kubelet から CSIDriver をプラグインにという格好で読み出し参照するロジックは Kubernetes 本体リポジトリの kubelet と関連パッケージに存在
- https://github.com/kubernetes-csi/driver-registrar を使って CSIDriver を kubelet から参照可能にする
おわりに
以上、 CSI とその Kubernetes へのインテグレーションに関する記事でした。 CSI は可搬性を担保しつつ Kubernetes での利用を重要視されて作られているようですが、 CSI の仕様含めエコシステムもまだ枯れているとは言えず、機能も多くはありません。 Kubernetes 用の単なるサンプルとはいえ HostPath プラグインで tar コマンドを実行してスナップショットを作成したりなど、もう少し抽象化されてほしい箇所もまだ存在します。
しかしながら個人的には Kubernetes での柔軟なストレージ利用には、以前の記事で挙げた通りまだまだ課題があると思っており、今後の発展を期待したいと考えています。
Kubernetes 上で動作するコンテナから安全に FUSE を利用したかった
本題の通りの気持ちがあったのですが、結論としては手軽にできる良い方法は無いようでした。 備忘録的に挑戦した事を記録しておきます。
背景: FUSE 利用のモチベーション
言うまでもなくファイル I/O はシステム開発においてよく使われる機構であり、多くのプログラミング言語において標準ライブラリまたはそれに類するライブラリでファイル I/O をサポートしていると思われます。
さて Kubernetes 上でマイクロサービスを実装していく事が多々あるこのご時世、各マイクロサービスで実装言語非依存で使えるデータの読み書きのロジックがあると、例えば何らかの設定ファイルの動的受け渡しやロギングにおいて便利な可能性があります。 これに似た課題を抱えて解決に向かったプロダクトとして Envoy Proxy があるかと思われます。 これは元々ネットワーキングやトレーシングの課題などを各言語ごとのライブラリで対応していたもののつらくなり、 HTTP や gRPC を解釈するプロキシを導入することで緩和に成功しています。
前述の通りファイル I/O は HTTP や gRPC をしゃべるより更にリーズナブルな共通プロトコルであると考えられもしそうです。 さらに FUSE を使えばファイルシステムとしてインタフェースを提供して、かつ裏側で複雑なロジックを動かすこともできるように考えられます。 そんなわけで、 Kubernetes 上で動作するコンテナからいい感じに FUSE で実装したファイルシステムをマウントして利用できると良いかもと着想した次第です。
FUSE 利用の限界
同じような思考をしたり、あるいは既存 FUSE 資産を利用したい人たちが多々居たようで、 Kubernetes 公式リポジトリの Issue でも議論がされていたりします。
残念ながらこの 2015 年に open した issue は 2018 年も終わりを迎える今日においても close されていません。 どういう点がネックになるかというと
/dev/fuse
を open するのに特権が必要- mount, umount するのに SYS_ADMIN ケーパビリティが必要
が挙げられ、一応利用できなくは無いものの利用条件を満たすため現状は privileged mode でコンテナを動かす羽目になり、やや安全面でリスクがあるように思えます。
FUSE 利用パターンいくつか
前述の Issue の中で幾つかのアイデアも提示されています。少しこれらを実際に試してみることにしました。 多少このリスクを緩和するため、大きく分けて以下の方針がありそうです。
- コンテナ外でなんとかするパターン
- 特権を持つコンテナをアプリケーションを動作させるコンテナと分離するパターン
前者は場合によっては可搬性を損なうか導入が非常に困難になる恐れがあり、また後者であればコンテナ内の世界で完結させることができそうです。 従ってまずは後者のアイデアを試してみます。
以下に検証用に用意した Dockerfile や設定ファイルを配置しました。
FUSE でマウントするのは libfuse に含まれる、ファイルを read すると "Hello, World!" を返す hello.c
を利用しておきます。
こちらのリポジトリでは initContainers
で mount するのと、 postStart
, preStop
でサイドカーコンテナで mount/umount する案を試してみました。
が、結局マウント先を参照するアプリケーションコンテナからはマウントした先は参照できなくなります。
結局この例だと特権を渡さざるを得ませんでした。
次の一手のアイデア
今回特権を要求されたのが、コンテナ内から /dev/fuse
が open できない点なので、この点を何とかできれば 多少課題は緩和されるかもです。
Kubernetes は Device Plugin という機構を最近サポートしているようで、これで何とかできる可能性があるような全く無いような気がしています。
また Kubernetes v1.10 からベータになったというストレージ接続インタフェース CSI は将来も見据えてこの問題に取り組むのに、もしかしたら良い機構かもしれません。
いずれにせよ Kubernetes 自体の調査をほとんどやっていないので次の一手はこれら周辺技術の調査からかと考えております。
ISUCON8 に参加して最終成績が本戦3位だった
タイトルのとおりです。何やかんやあり ISUCON8 の予選を無事突破した後に 10/20(土) LINE さんのオフィスにて本戦に参加して、最終成績 3 位に収まりました。 3 位だと特に表彰されるわけでもなく気持ちのみなのですが。
チーム構成と役割分担について
職場のよしみで cubicdaiya さん、 catatsuy さんと何らか SRE チームらしき雰囲気を醸し出しながら参戦しました。 大枠としては以下の役割分担を組んでいました。
- インフラ担当
- cubicdaiya
- アプリ担当
- catatsuy
- syucream
全体チーム構成やツール・環境構築お膳立ては catatsuy さんがいい感じにやってくれていました。
予選について
本記事執筆にあたり予選実施日と期間が空いて、ほぼすべての記憶を損失しました。 様子はたぶん catatsuy さんの以下記事にある気がします。
本戦について
だいたい出題された課題の要点は以下記事で説明されています。
3 位に入賞できた決めては突出したコレという点は無く、チームでそれぞれ貢献できた、バランス的には良い塩梅なのではと感じました。 具体的なタイムラインとしては覚えている限り以下のとおりです。
前半: 好調な滑り出し
とりあえず各々初期準備をする
- 自分はここでは DB スキーマを取り出して共有したり WebUI 調べたり
catatsuy さんが早期にログ分析APIの叩き方問題に気づく
- 着想としてはrate limitとかより重要なパスでI/Oしていそうなことがやばそう
- 11 時台に議論して、ハマりそうだから手を打とうと結論づけて catatsuy さんが着手しだす
syucream が LIMIT 1 問題に気づく
- 最初はサブクエリ書く感じで改善したが LIMIT 1 するのと課題的に差分がそれほどなかった
- ここで一時的に 5000 点ほどスコアを叩き出しトップに躍り出る
- 時間軸が入れ替わるが、この改善の実施直前に cubicdaiya さんが slow query を出してくれていてプロファイルの裏付けもした上で実施した
cubicdaiya さんがインフラ周り、特に nginx 周辺のチューニングを徐々にする
- 冗長そうなコンテナ化をやめる
- 静的ファイルを nginx で配信
中盤: 次ステップへの到達との葛藤
会場提供でランチとして弁当が出る
- AbemaTV のニュースで鯖の漁獲量が減って値段が若干上がった話を思い出し、僕は思わず鯖味噌煮弁当を確保
catatsuy さんのログの集約送信が動き出す
send_bulk
API の利用がうまくいかず、時間ももったいないのでバッファリングして send するだけにとどめたり- この瞬間はスコアに響かなかったが、後々ボディブローのように効いてきた感じがある
syucream が地味に無駄そうな user table のレコードロックを外す
- slow query ではあったが、全くスコアに響かなかった
cubicdaiya さんがそろそろいいでしょと良い SNS share 機能を有効化する
syucream が雑にロウソク足チャートのオンメモリキャッシュを入れる
- マージした後に、一度キャッシュをすると別タイミングに対してのクエリにもキャッシュヒットしてしまうバグに気づく
- が、ベンチマーカが文句を言わなかった!
- 一瞬チームで相談して、問題が出てないなら後で考えようと結論づける
cubicdaiya さんが複数台構成を考え始める
- 特に異論無く、 1: DB, 2: App, 1: nginx という意思決定が即なされる
後半: 着眼点は悪くなかったがもう一歩だったか
catatsuy & syucream で orders & trade の課題について考え出す
その裏で cubicdaiya さんが App サーバを 2 台構成にしていた
- このあたり?でスコアが 10000 近くに到達
catatsuy さんがミクロな最適化したり、 syucream が銀行 API アクセスを並列化したり N+1 を無くそうとして爆死したり
その裏で cubicdaiya さんが 4 台フルに使い切る構成への移行を追えてチューニングに入ったり
DB の負荷をさげたくて ORDER BY を使うクエリを Go のアプリレベルに移植して時間がたりなかったり
一部さばけない負荷に対して cubicdaiya さんが async sleep 入れたり
- syucream はこれが大きな差別化ポイントだった気がしている
そうこうしている間に 17:50 頃になって収束させて終了
'もう一歩' に対する所感
- 着眼点は非常に良くて、 PARTITION に対する疑惑や
POST /orders
、RunTrade()
最適化は課題に感じていて一部取り組んでいました - あらかじめ配布された spec を読み込んだり、外部 API に対して向ける疑惑がもっとあっても良かったかも
結論: ISUCON はいいぞ
今回の出題の外部 API が絡む話は個人的によく練られていて、個人的に非常に好ましい話でした。なぜならこういう外部APIとその挙動の差異は現実問題に起こりうりそうな話だからです。 そういう観点から言うと、学生チームが優勝したという展開はとても興味深いようにも思えます。 個人的課題として、自分が当日見ていた箇所で見どころは誤っていないけど一歩足りなかったことが挙げられ、狂おしいほど悔しいです。
もし次回参加して同じメンバーでチームを組むのなら、 catatsuy さんが優勝するのに並々ならぬ熱意を抱いているのでたぶん僕らが優勝するでしょう。
POSIX message queue を Go のコードから利用するためのライブラリ posix_mq を作った
表題の通りです。
cgo を使って POSIX message queue の基本的な操作、 open/close と send/receive とその他細々とした機能を実装しています。 とは言っても、それほど複雑なことはしておらず、 POSIX の関数呼び出しを愚直に Go の func にラップしているだけなのですけどね。
なぜやったのか
入門 Kubernetes などを読むと、 Pod 内のコンテナ同士では SysV / POSIX の IPC namespace を共有している記述があります。
Pod 内の別コンテナへの通信となると、 sidecar パターンで Envoy を動かすようなネットワーキング用プロキシを介するのに利用したり fluentd などのロギングエージェントにログを送ったり、お決まりのパターンがあると思います。 そういった際に低コストで非言語依存なプロトコルが欲しくなることが多々あるように考えられます。
POSIX message queue は POSIX としての仕様も存在し、低コストな IPC 手段のひとつです。 これを選択肢のひとつとして用意しておくことは発生する課題に柔軟に対応するのに重要であると考えます。 手段は他にもあるし、同様の機能であれば SySV message queue やいっそ AMQP などをしゃべっても良い気もするのですが、手段を増やす意味でも今回のライブラリを開発してみた次第です。
動作例
sender / receiver の通信例
シンプルなsender と receiver であれば以下のコードで実装してやり取りできます。
- sender.go
package main import ( "fmt" "log" "time" "github.com/syucream/posix_mq/src/posix_mq" ) const maxTickNum = 10 func main() { oflag := posix_mq.O_WRONLY | posix_mq.O_CREAT mq, err := posix_mq.NewMessageQueue("/posix_mq_example", oflag, 0666, nil) if err != nil { log.Fatal(err) } defer mq.Close() count := 0 for { count++ mq.Send([]byte(fmt.Sprintf("Hello, World : %d\n", count)), 0) fmt.Println("Sent a new message") if count >= maxTickNum { break } time.Sleep(1 * time.Second) } }
- receiver.go
package main import ( "fmt" "log" "github.com/syucream/posix_mq/src/posix_mq" ) const maxTickNum = 10 func main() { oflag := posix_mq.O_RDONLY mq, err := posix_mq.NewMessageQueue("/posix_mq_example", oflag, 0666, nil) if err != nil { log.Fatal(err) } defer mq.Close() fmt.Println("Start receiving messages") count := 0 for { count++ msg, _, err := mq.Receive() if err != nil { log.Fatal(err) } fmt.Printf(string(msg)) if count >= maxTickNum { break } } }
Kubernetes の同一 Pod 上 container 通信例
折角なので上記の sender / receiver を Kubernetes の Pod に押し込んで通信させてみます。 あらかじめてきとうに sender / receiver 用の Docker イメージを作っておいてください。
Pod の定義なのですが、愚直に container の設定を羅列していくだけです。 IPC namespace は勝手に共有されるのでそれに関する設定や準備は必要ありません。
apiVersion: v1 kind: Pod metadata: name: posixmq-pod spec: containers: - name: posixmq-sender image: "posix_mq_sender" imagePullPolicy: IfNotPresent - name: posixmq-receiver image: "posix_mq_receiver" imagePullPolicy: IfNotPresent restartPolicy: Never
Pod の動作確認をさくっとしてみましょう。
$ kubectl apply -f example/kubernetes/pod-posixmq.yaml pod "posixmq-pod" created ... $ kubectl logs posixmq-pod -c posixmq-sender go run example/exec/sender.go Sent a new message Sent a new message Sent a new message Sent a new message Sent a new message Sent a new message Sent a new message Sent a new message Sent a new message Sent a new message $ kubectl logs posixmq-pod -c posixmq-receiver go run example/exec/receiver.go Start receiving messages Hello, World : 1 Hello, World : 2 Hello, World : 3 Hello, World : 4 Hello, World : 5 Hello, World : 6 Hello, World : 7 Hello, World : 8 Hello, World : 9 Hello, World : 10
この出力結果を見るに、 sender の送ったメッセージがちゃんと receiver に届いていそうです!
余談
POSIX の機能となると可搬性を期待してしまいますが、 POSIX message queue は darwin や windows では実装されていなかったりと意外に可搬性に欠けます。 対して SysV の message queue はこれに比べて可搬性が高く、より多くの環境でサポートされています。 (このあたりは Linuxプログラミングインタフェース にも記述されていますね!)
とは言っても本記事で書くようにあらかじめ環境が定められている Kubernetes クラスタ上で動かす場合は、それほど気にすることでも無いのかもしれません。 また、 SysV message queue の Go ラッパーライブラリは Shopify により実装されているのでこれを試すのもアリかもです。
ちなみに少し前のベンチマーク内容ですが、 POSIX message queue は IPC の手段として結構高パフォーマンスであるような調査結果もあります。
技術書典5にてマイクロサービスとEnvoy、暗号通貨についての薄い本を配布します
明日 10/08 (月) は技術書典5 の日ですね!
当サークル「まいにちがきんようび。」もサークル参加して、新刊を配布する予定です!(既刊の配布予定はありません)
内容としては、マイクロサービスと Envoy Proxy を試してみた結果からの紹介記事をメインに、前回記事執筆者による bitcoin の仕様の闇の記事を付録に添えたものになります。
具体的には以下のような内容になります(目次から抜粋)
第1章 Envoy Proxy 入門 1.1 はじめに 1.2 マイクロサービスアーキテクチャ概要 1.2.1 モノリシックアーキテクチャ 1.2.2 マイクロサービスアーキテクチャ 1.3 マイクロサービス、そして Envoy と Istio 1.3.1 Envoy とは 1.3.2 Istio とは 1.4 Envoy 詳解 1.4.1 Envoy アーキテクチャ概要 1.4.2 Envoy のリソース抽象化 1.4.3 Envoy の特徴的な機能説明 1.4.4 nginx など従来のプロキシと何が違うのかについて 1.5 Envoy の試し方 1.5.1 Docker image をとりあえず動かす 1.5.2 複雑な構成を試してみる 1.6 おまけ 1.6.1 Istio における Envoy の組み込まれ方 1.6.2 Envoy ソースコードリーティング 1.7 まとめ 付録A 私が暗号通貨を嫌いになったわけ A.1 はじめに A.2 前提知識 A.2.1 トランザクションの構造と所有権の移転履歴 A.2.2 TXID とトランザクションデータ A.2.3 コインベーストランザクションとマイニング報酬 A.2.4 マークルツリーとマークルルート A.2.5 マイニングと Nonce A.2.6 コインベーストランザクションとエクストラ Nonce A.2.7 TXID の衝突確率と鳩ノ巣原理とバースデイパラドックス A.3 TXID の衝突事例と BIP-30 A.4 BIP-30 から BIP-34 へ A.5 BIP-34 以前のトランザクションとの衝突問題 A.6 BIP-30,34 と各種アルトコイン A.7 実際の衝突発生確率 A.8 おわりに あとがき
ぜひ会場でお目に止まるようであれば、手にとってみていただけると幸いです!
また当日会場に来ない、来れない、あるいは僕にとっては運良く完売してしまって購入できなくなったという時のために kindle 版も用意しております。 こちらも合わせてご検討いただければ幸いです。
Netflix のデータパイプラインを読み解きたい
Netflix はマイクロサービスアーキテクチャ界においてプロダクションで成功例を積んでいる、いわば大先輩だと思われます。 彼らは数多くのイベント登壇や techblog の記事、 GitHub 上による OSS の公開を行っており、それらからアーキテクチャやその変遷を垣間見ることができると考えています。
本記事では筆者が最近悩んでいる、マイクロサービス前提の世界でのログ収集基盤において、 Netflix の様々な事例を調べた結果をつらつら書いていこうと思います。 あらかじめ本記事は正確性を担保しておらず、あくまで筆者個人が調べることができた範囲での記述に留まることをお断りさせていただきます。
Suro: 分散データパイプライン
2015 年くらいにメンテが止まってしまったのですが、分散データパイプラインをうたう Suro というソフトウェアが存在しました。
Suro に関しては解説記事も書かれていて、イベントログを集約し後続の S3 、 Kafka 、その他イベント処理システムに転送する役割を担っていたようです。 またバッチとリアルタイム、両方の性質を持つデータを受け付けていたようです。
Suro がメンテされなくなった経緯は筆者もよく分かっていませんが、後続のデータパイプラインの仕組みを見るにバッチとリアルタイムの両方の要望に答えるのが辛かったのか、あるいはデータの分析基盤の変更に合わせて作り直す決定をしたものかと推測しています。
Cassandra のデータ転送のバッチレイヤーと Ursula によるスピードレイヤー
Suro と入れ替える形かどうそうでないかは定かで無いですが、以下の資料によると Lambda Architecture に似たバッチレイヤーとスピードレイヤーの分離を行っているのが見て取れます。
https://qconsf.com/sf2016/system/files/presentation-slides/netflix-cloud_analytics.pdf
バッチレイヤーでは、 Netflix で広く使われている Cassandra をベースに SSTable をダンプして、それを aegisthus という Cassandra 向けバルクデータパイプラインソフトウェアを使って、 Netflix がデータウェアハウスに使っている S3 に転送していたようです。 また SSTable のダンプは上記資料では明示されていないのですが、 Priam というツールが公開されておりこれを使っているのではないかと推測しています。
ちなみにこの aegisthus も、 2017 年にメンテナンスモードに移行し今ではコミットされていないようです。 最後のコミットに対してされたコメント を見るに、 Cassandra のデータのデータウェアハウスへの転送は今後 Spark のジョブに移行することを検討しており、 2018 年 8 月時点ではまだ移行途中?でかつ新しいツールは OSS にはなっていないようです。
スピードレイヤーを支える Ursula というソフトウェアの存在も上記スライドでは触れられていますが、こちらは OSS になっている気配はありませんでした。
データパイプライン周辺技術
パイプライン以外にも、 Netflix はビッグデータ処理ジョブのオーケストレーションツールである genie や、 メタデータ管理ソフトウェアである metacat など多くの小道具を揃えているようです。
余談
上記のうち Suro や aegisthus については、 "マイクロサービスアーキテクチャ" にも記述があり参考になる部分があるかも知れません。
ここで挙げたツールは Netflix が Cassandra を広く採用していることや、大規模なデータを持つがゆえの様々な課題、背景などもあって作ったのだと考えられます。 これらがそのままマッチして利用できる企業は多いわけではないと思われますが、これらの変遷や構成などが読み解けるものがあるのかも、などと思いました(小並感)
追記
今は Kafka を結構活用しているのかも。
ちょっと前の記事だけど、調べ損ねてた netflix のデータパイプライン、投入部分は Java library (+ Non-java app 向けの proxy) でやってるのかなー? https://t.co/eCKkKf58KT
— しゅー くりーむ (@syu_cream) 2018年8月22日
2017 年の資料にも sharing jar の話出てくるし投入部分は今もあまり変わってないのかしら https://t.co/oTIeDhLJY2
— しゅー くりーむ (@syu_cream) 2018年8月22日
株式会社メルカリに入社して1年が経過した
ちょうど一年前の 2017年8月16日に株式会社メルカリに入社しました。キリがいいこともあり、ここらで個人的な振り返りをつらつら書いてみます。あらかじめ、はっきりいって個人の日記レベルの内容であることをお断りさせていただきます。
転職の経緯から入社まで
2017 年 1 月頃から転職を考え初めていました。元の所属も Web サービスをなりわいとしており、それなりの愛着もあり良い経験をさせて頂いてはいたのですが、自分の能力向上を目指しつつより早いペースでプロダクトを提供していく体験を積みたく粛々と準備をしていました。 そんな中メルカリは、急成長しているサービスを提供しており外部への発信も多く、また所属エンジニアも強力な方々が多く自分にとっても良い経験になると踏んだため応募した次第でした。
応募に際して僕の場合は特に知り合いのツテやエージェントを通さずに、採用ページの募集フォームにダイレクトアタックを仕掛けて選考に進みました。敢えて反省点をひねり出すならば、何とか所属するエンジニアにアプローチを仕掛けて雰囲気などを確かめるとより良かった気はします。採用ページや各種アウトプットからは見えない現場での葛藤やそこに根ざす文化を確認するのは、重要なことでしょうし。
入社後から今まで
2017 年内はメルカリ SRE チームに所属して、ミドルウェア開発マンとして主にデータ収集基盤とその他細々としたコンポーネントの開発に携わっていました。 その後は 2018 年 2 月頃?(うろ覚え)に子会社メルペイに籍を移し、一部マイクロサービスの開発や、メルペイのためのデータ収集基盤を、マイクロサービスアーキテクチャに従った世界でのプロダクトでの課題も吸収しつつ考えるという仕事に従事し始めました。
この間に起こった大きな変化として、個人的には前職が基本オンプレ前提のインフラ構成であったところからクラウドのリソースを多用する環境になったことと、会社的にはマイクロサービス化へ舵を切ったことです。 特に後者は今でも悩ましい事がいくつもあり、刺激の多い日々を過ごせているように感じています。
反省点と今後の目標
ここ一年多くの刺激を受けつつ過ごせましたが、まだまだ自分が納得できるほど大きな成功に到達していないとも思えます。 元々、不確定な世界の中こつこつと少しずつ成果を積み上げ模索するのが好きであり得意であると考えているのですが、そのスタイルでは到達しにくい領域についても考えるべきかもという危機感も持ってきています。 そういった現状の自身の不足しているスキルやできる領域、やれる領域を明確にしていくのが今後の課題なのかなぁ、などと考えています。
おまけ: 仕事以外のここ一年の活動
ngx_mruby のノンブロッキング sleep
メルカリ SRE チームに所属した際、そういえばちゃんと nginx を理解していないなと危機感を覚えつつ、勉強も兼ねて mruby スクリプトを動かすためのモジュール ngx_mruby にノンブロッキング sleep する仕組みを追加するパッチを書いてみていました。 このパッチは結局幾つかの問題にハマり、自分だけでは解決できず半ば放置していたのですが、 matsumotory さんはじめ GMO ペパボさんの方々に拾っていただき、 RubyKaigi 2018 で紹介されるまでに至りました。 ・・・諦めて単純に放置するでなく、もう少し能動的に相談しに行ったりとかすべきだったかも、など様々な反省があります。
Go でいくつかツールを書いた
すでに記事と化したものもあるのですが、 Go でいくつかツールを書きました。
自分の業務に直結するスキルが得られる以外にも、やっぱ何も考えなくてもシングルバイナリで使えるとツールとしては便利だと考えたため、ひたすら Go で書いてます。
で、
誰?