Open9
いつか「実践 Erlang/OTP 時雨堂編」を書くためのメモ
これは「プログラミングErlang」と「すごいErlangゆかいに学ぼう!」を読み終わった人が商用ミドルウェアを Erlang/OTP で書きたいって思ったときに手に取れる 「実践 Erlang/OTP 時雨堂編」という無料のオンライン書籍をいつか書くための雑多なメモ。
著者
- 時雨堂の中の人
- Erlang/OTP は R11 から
- Erlang/OTP を利用した商用パッケージ製品の開発者
これから Erlang/OTP を学ぼうと思う人へ
まずこの2冊を購入してしっかり読み込んでほしい。自分もプログラミング Erlang をひたすら読み込んだ。
また、この 2 冊以外は日本語の書籍は読む必要はない。これに書いていない事は Erlang のドキュメントやソースコードを読む。資料では、この 2 冊に足りていない部分を書いていく。
ドキュメント
-
https://www.erlang.org/doc/
- とにかく公式を読む
海外書籍
-
Property-Based Testing with PropEr, Erlang, and Elixir: Find Bugs Before Your Users Do by Fred Hebert
- 実践プロパティベーステスト ― PropErとErlang/Elixirではじめよう
- PBT に興味があるなら読んだ方がいい
-
Programming Erlang (2nd edition) by Joe Armstrong
- 英語がしんどくないなら読んだ方がいい
-
Erlang Programming [Book]
- 特に読まなくても困らない
-
Erlang and OTP in Action
- 特に読まなくても困らない
-
Designing for Scalability with Erlang/OTP [Book]
- 特に読まなくても困らない
-
Introducing Erlang [Book]
- 特に読まなくても困らない
資料
rebar3
ビルドツール。公式で配布してる。
Erlang の文法を覚える前に、rebar3 を覚えた方が良いくらい大事。
rebar3 プラグイン
-
erlef/rebar3_hex: Rebar3 Hex library
- Hex をプライベートで利用する場合は必須
- project-fifo/rebar3_lint: Erlang linter - rebar3 plugin
- rebar3_efmt | Hex
-
erlware/relx: Sane, simple release creation for Erlang
- rebar3 に組み込まれているので単独で使う事は無い
翻訳書籍には載っていない機能や標準ライブラリや文法
- BeamAsm, the Erlang JIT
- rand
- gen_statem
- counters
- persistent_term
- logger
- Maybe
- Bit String Comprehensions
counters と persitent_term と logger は erlang vm にとってブレイクスルーなので、必ず覚えるべき。
HTTP 系ライブラリ
-
sile/jsone: Erlang JSON library
- OTP 27.0 で標準で json ライブラリが用意されたのでそちらを検討しても良い
-
ninenines/cowboy: Small, fast, modern HTTP server for Erlang/OTP.
ninenines/gun: HTTP/1.1, HTTP/2, Websocket client (and more) for Erlang/OTP.
デバッグ系ライブラリ
- ferd/recon: Collection of functions and scripts to debug Erlang in production.
- massemanet/redbug: erlang tracing debugger
フォーマッターのライブラリ
-
sile/efmt: Erlang code formatter
- Rust で書かれた Erlang/OTP フォーマッター
- 早いのは正義
- フォーマット前とフォーマット後の動作が同じ事を保証してくれるので安心して使える
UUIDv4 が使いたい
crypto:strong_rand_bytes/1 を使って簡単に自作できる。
%% https://www.rfc-editor.org/rfc/rfc4122.html
uuidv4() ->
%% https://www.rfc-editor.org/rfc/rfc4122.html#section-4.1.2
<<Rand1:48, _:4, Rand2:12, _:2, Rand3:62>> = crypto:strong_rand_bytes(16),
<<Rand1:48,
%% https://www.rfc-editor.org/rfc/rfc4122.html#section-4.1.3
%% Msb0 Msb1 Msb2 Msb3 Version Description
%% 0 1 0 0 4 The randomly or pseudo-
%% randomly generated version
%% specified in this document.
2#0100:4,
Rand2:12,
%% https://www.rfc-editor.org/rfc/rfc4122.html#section-4.1.1
%% Msb0 Msb1 Msb2 Description
%% 1 0 x The variant specified in this document.
2#10:2,
Rand3:62>>.
ライブラリ FAQ
- Language Server は?
-
sile/erlls: Erlang language server
- 時雨堂は erlls を採用
-
WhatsApp/erlang-language-platform: Erlang Language Platform. LSP server and CLI.
- 積極的に開発されている
- 多機能
-
erlang-ls/erlang_ls: The Erlang Language Server
- 開発が停滞しておりお勧めしない
-
sile/erlls: Erlang language server
- 暗号ライブラリは?
- OpenSSL 3.0 系を利用する crypto が OTP に内蔵されてる
- Erlang -- crypto
- X509 関連ライブラリは?
- OpenSSL 3.0 系を一部利用する public_key が OTP に内蔵されている
- Erlang -- public_key
- LDAP ライブラリは?
- eldap というライブラリが OTP に内蔵されている
- Erlang -- eldap
- HTTP/2 ライブラリは?
- サーバーであれば Cowboy
- クライアントであれば Gun
- HTTP/3 ライブラリは?
- サーバーであれば Cowboy が対応中
- クライアントライブラリであれば Gun が対応中
- WebSocket ライブラリは?
- サーバーであれば Cowboy
- クライアントライブラリであれば Gun
- QUIC ライブラリは?
- msquic のラッパーが公開されている
-
emqx/quic: QUIC protocol for Erlang & Elixir
- 時雨堂は自前
- Raft ライブラリは?
- RabbitMQ と WhatsApp が実際に利用しているのを公開している
-
rabbitmq/ra: A Raft implementation for Erlang and Elixir that strives to be efficient and make it easier to use multiple Raft clusters in a single system.
- 時雨堂では RabbitMQ の Ra を採用
- WhatsApp/waraft: An Erlang implementation of RAFT from WhatsApp
-
sile/jsone: Erlang JSON library
- 時雨堂では jsone を採用
- json ベースで jsone インターフェースを実現していく予定
- 標準ライブラリの json で十分であればそちらがお勧め
- 時雨堂では jsone を採用
書き方 FAQ
- 何かあったらクラッシュさせていいの?
- ダメ、把握できる範囲は ok/error で対応する
OTP 26
https://www.erlang.org/news/160 の翻訳。
Erlang シェル
- 変数、レコード名、レコードフィールド名、マップキー、関数パラメータタイプ、ファイル名のオートコンプリート
- シェルで外部エディタを開き、現在の式を編集します
- シェルでレコード(型あり)、関数、スペック、型を定義
JIT
- base64モジュールの性能は大幅に改善されました
- JITを使ったx86_64システム上では、エンコードとデコードの両方がErlang/OTP 25のときよりも3倍近く速くなった
- 固定サイズのセグメントを持つバイナリの作成とマッチングが最適化されました
- UTF-8 セグメントの作成とマッチングが最適化されました
- バイナリへのアペンドが最適化されました
- コンパイラとJITは、すべてのキーがコンパイル時に分かっているリテラルである小さなマップを作成するためのより良いコードを生成するようになりました
Dialyzer
- Dialyzerには新しいインクリメンタルモードがあり、Dialyzerの実行時に--incrementalオプションを与えることで起動します。 この新しいインクリメンタルモードは将来のリリースでデフォルトとなる可能性があります
Maps
- マップ内包が実装されました
- アトムキーの内部ソート順を変更することにより、いくつかのマップ操作が最適化されました。これは小さなマップのアトムキーがどのように表示され、maps:to_list/1とmaps:next/1 によって返されるかという(文書化されていない)順番を変更します。 新しい順番は予測不可能で、Erlang VMの異なる起動の間で変わるかもしれません
- マップの要素を決定論的な順序で返すインターレーターを作成するための新しい関数maps:iterator/2が導入されました。 また、マップの要素を順序どおりに印刷するための新しい修飾子kとKが io:format() のフォーマット文字列として導入されました
ssl
- erl_dist の ssl が ktls に対応
その他
- BIFのmin/2、max/2がガードやマッチの仕様で使用できるようになりました
- 選択的受信の最適化が改善され、他の関数から返された参照に対して有効化できるようになりました。これにより、gen_server:send_request/3 やgen_server:wait_response/2 といった関数の性能が大幅に改善されます
- inet:setopts/2に3つの新しいオプションが追加されました:reuseport,reuseport_lb,exclusiveaddruse
- application:get_supervisor/1を導入
基本戦略
- 依存ライブラリをとにかく減らす
- 可能なかぎりライブラリは自作する
- 汎用ライブラリは既存のものを利用する
- 可能なかぎり標準ライブラリを利用する
- OSS ライブラリを利用する時はフォークする覚悟で利用する
-
https://github.com/shiguredo/ra
- 積極的な改善をするためフォークした
-
https://github.com/shiguredo/jesse
- JSON Schema ライブラリがメンテされなくなったのでフォークした
-
https://github.com/shiguredo/ra
- 標準ライブラリでも利用しないのはパッケージに含めない
- Erlang/OTP ソースコードインストールのススメ
- とにかく利用しないライブラリを削っている
- ログは JSON Lines
- 標準ライブラリの logger を利用して実現してる
- ログローテーションはしない
- 将来的にログローテーションや圧縮の仕組みを作り込みたい
OTP 27.0
https://www.erlang.org/blog/highlights-otp-27/ の雑な翻訳
- ドキュメントが XML から Markdown へ
-
-doc
を利用してドキュメントが書けるようになった -
<<"しぐれどう"/utf-8>> が
~"しぐれどう" と書けるようになった-
~b"しぐれどう"
でもよい
-
-
maybe
が設定なしで利用できるようになった -
json
モジュールが入った - デバッグ向けにプロセスにラベルが付けられるようになった
proc_lib:set_label/1
proc_lib:get_label/1
- tprof という新しいプロファイラーが入った
トリプルクオート
こんな感じでかけるようになった。
S = """
あいうえお
かきくけこ
"""
Erlang/OTP の向いている分野
- ミドルウェア
- 分散ミドルウェアも頑張れる
- データベース系は向いていない
- 特にディスク書き込みで性能は出ない
- データベース作るなら Rust や C++ が良いと思う
- メッセージングや音声
- WhatsApp / Discord / ejabbered
- WhatsApp は 20 億ユーザー以上が利用してる
- 9 億ユーザーの時点でエンジニア 50 名
- WhatsApp は 20 億ユーザー以上が利用してる
- WhatsApp / Discord / ejabbered
- RabbitMQ / emqx
- MQ
- RabbitMQ は AWS がマネージドするくらいメジャー
- リアルタイムなメッセージングやら MQ に強い
もし採用する場合
- プロトコルは自前で実装する
- 依存ライブラリはできるだけ減らす
- Raft ライブラリは自作しない
- WhatsApp と RabbitMQ が公開している
- https://github.com/rabbitmq/ra
-
https://github.com/WhatsApp/waraft
WARaft は、5 つ以上のデータ センターにわたる大規模で強力な一貫性のあるストレージ システムである WhatsApp メッセージストレージの合意プロバイダーとして使用されています
- ボトルネックは暗号処理とパケット書き込み
- 暗号処理は OpenSSL を利用するが早くはない
- Rust と比較したところ Rust の方が 2 倍速かった
時雨堂では
- WebRTC SFU の実装に利用している
- プロトコルスタックは全て自前
- Raft ライブラリは RabbitMQ の Ra を採用
- できるだけ標準ライブラリを利用