2018/12/07

ReFe + ref.vim で Neovim から Ruby の document を読む

この記事は Okinawa.rb Advent Calendar 2018 の 7 日目の記事です。
昨日の記事は @hanachin_ さんの 『refineをしてるモジュール取り出せるrefinements_robbery gem』 でした。


なにができるの

カーソルが指している(クラス|メソッド)名のドキュメントが一発で引けます。
これが
こうじゃ

的な感じ。


環境

OS: macOS Sierra 10.12.6
Neovim: 0.3.1
ReFe: 2
Ruby: 2.5.3p105 (2018-10-18 revision 65156)
vim-ref: b45d10f6d0c82e3afd17774626e952fde03274a1



NeoVim + vim-ref

私の環境では NeoVim を使っていますが、Vim でもおそらく動くはずです。
vim-ref というリファレンスを読むのに便利なツールがあり、2014年あたりから私は活用させてもらっています。


ReFe 2

クラス名かメソッド名を指定すると該当するドキュメントを表示してくれるツールです。


ReFe + vim-ref

さて。この二つを組み合せていきます。

  • $ bitclust setup
で refe を使えるようにします。
この時点で
  • $ refe Integer
とするだけで

のように表示できます。便利。

ちなみに vim-ref は plugin を入れると refe に関しては設定無しでも動きます。
normal mode で K を押すだけ。便利便利。


まとめ

ということで vim-ref を使って ReFe 2 を引くお話でした。
ちなみに vim-ref で開いた buffer 内のワードでも refe を引けるので、色々と探検できたりします。
後、地味な利点としてオフラインでもドキュメントが見られる点があります。
快適な Ruby ライフをー

2018/10/31

tmux 2.8 を全角記号対応させる

ということで恒例の分割線を EastAsianAmbiguous から ascii の線に変更するバージョンを作成。
2.7 の時とか 2.6 の時とかの作業履歴とかもまとめてあります。
そもそもどういう問題なのかはこの記事で。


環境

  • macOS Sierra 10.12.6
  • tmux: 2.8-border-ascii (4283f6b6e3f3c46b8665ce398a164063a7ef0aab)
  • utf8proc: 2.1(562edab805b82d66622914d06a5da3f53cd54a17)
  • Homebrew: 1.8.0-76-gcbb2e1b
  • Homebrew/homebrew-core: (git revision 95614; last commit 2018-10-30)
  • Ricty: 3.2.2(no option)


作業

今回は割とあっさりできました。cherry-pick して tag 更新して終わり。
  • $ git pull upstream
  • $ git checkout 2.8
  • $ git cherry-pick border-ascii
  • $ git checkout -b 2.8-border-ascii
くらい。

make できるかの確認は
  • $ sh autogen.sh
  • $ ./configure --enable-utf8proc
  • $ make
くらいで。

current directory に tmux command ができるので、動作確認とかもできます。
  • $ ./tmux -V
    • tmux 2.8
  • $ ./tmux
    • border-ascii 版の tmux が起動します。
あとは自分用の tap に反映しておしまい。


インストール方法

1からインストールする場合のコマンドは
  • $ brew tap atton/customs
  • $ brew install atton/customs/utf8proc
  • $ brew install --HEAD atton/customs/tmux
でいけます。


ぼやき

これで分割時の線が ascii になりました。良し良し。

自分用にメンテし続けてるけれど、tui を使う時とかはどうしても崩れてしまう。
特定の文字を表示する時かけられる hook があれば、置換表を config に書くと tui も問題無く表示できるとは思うのだけれど、そんなの無いかなー。

2018/09/13

ISUCON7の予選問題を解いて、スコアを27万点まで上げた

こんにちは。フリーランスのエンジニアのあっとんです。
仕事が一段落したのもあってプチ夏休みという名の仕事が無い期間、ISUCON7 の予選問題をやったりしました。
それを改めてログにまとめる次第です。

結論から言えば、予選突破のボーダーの21万点を越えられました。
ちなみに累計作業時間は58時間くらいで、最終スコアは 270957 でした。
あとリモートワークのお仕事を募集中(2018/09/13現在)です。


どうして ISUCON の問題を触ってみようと思ったのか

  • Twitter でたまに見た単語で気になっていたので
  • ミドルウェアをインストールする事はあってもガリガリにチューニングする経験が無かったので
  • とりあえず数字で善し悪しが分かるので


自分レギュレーションと目標とか

  • スコア的な目標は予選突破ボーダー(21万点くらい)
  • とりあえず最初(ISUCON7予選)はブログとか見て良いのでノウハウを積む
  • ノウハウを積んだ上で本戦問題を時間制限+解説見ずに解く


環境構築とベンチマーカを動かす

まずは環境構築から。
とりあえず GCP の上に 4core 8GB の instance を上げる。
ISUCON7 の予選問題の README.md に従って環境構築。
初期スコアは5000点くらいだったと思います。
ベンチマークをかける側も 4core 8GB で環境構築。


なんとなくの知識で高速化をする

とりあえず知ってる範囲で適当に進めていく。
  • nginx の proxy を経由せずに直接 puma で 80番を bind するように
    • スコアが 3000 くらいになる。 却下。
  • rackup する時に environment を production にする
  • logger を無しにして log を disk に書かないようにする
    • 一応スコアが 5980 くらいにはなる
  • css と js を minify する
    • yui-compressor なるものを使う
    • $ yui-compressor main.css -o minimain.css # とか
    • Validation に失敗するのでこの手は使えない
  • gzip で圧縮してみる
    • .gz を置いて配る
    • そんなにスコアが変わんなかった
  • N+1 を解決したいが SET IN ... に書き換えるのが面倒
    • 普段 ActiveRecord を使っていたので includes で解決して欲しい……
    • (後から結局 sinatra-activerecord を入れることになる)
  • SELECT * の結果に対して first していた部分に LIMIT 1 を付ける
    • 1万点くらいになる
  • メモリの上に DB の全データを載せる
    • tmpfs + rsync で載せてしまう
    • 19340 点になる。倍。
  • mysql の log の WARN を取り除く
    • 22511 点になる。10%増し。


予測するな計測せよ

結局何が一番のネックなのかが分からないとどうしようもない。
ということで計測していく。
profiling には rack-mini-profiler を使ってみた。
さてこれでどこがネックなのか探るか、と思ったら作成されたファイルが読めない。
結論から言えばファイルに書く前に Marshal.dump されているせいで Marshal.load しないと読めなかった。
Marshal.dump を JSON.dump に monkey patch して無理に plain text にして jq で読む。
しかしファイルが多すぎて(200個とか)まともに読めない。
profiler を使うのは諦めて top だけで行くというゴリ押しをする。
(rack-mini-profiler を rack application で動かす、というのも記事にできそうなので後から書くかもしれない)
なお、初期の段階でベンチマークをかけると CPU を mysql が 55% 、puma が 35% くらい食っていて DB ネックだった。


参考文献を参照開始


1Core 1GB にスペックダウン



11万あたりの伸び悩み

その後もチマチマと変更を加えるものの、12万点の壁は越えられず。
CPU使用率も合計100%にならなくなった。
気付くのに結構かかってしまったけれど、オチとしてはメモリ不足。
具体的には残り10k とかになっていた。
というわけでここからは複数台構成にする。


複数台構成



lsyncd を使って画像の同期

解決すべき問題は icons を3台の間でどう整合性を取って返すか。
業務だったら S3 に置くなり CDN を使うのが良さそう。
しかし ISUCON なので、手元にあるサーバでどうにかする必要がある。
画像ファイル自体は1MB以下なのが保証されている。
なので書き込み時に memcached じゃなくて全サーバに書き込むことに。
そうすれば /icons を nginx が Cache-Control 付きで返してくれて良さそう。
(nfs で mount しても良かったのですが、結局 network access が発生するので早くならなそうだったので断念。)
(nfs の cache の config でどうにかなった可能性もゼロではないが……)
最初は inotify + rsync でゴリ押ししようと思ったのですが、 lsyncd なるものを発見。
(rdiff-backup とか osync とか csync2 とか unison とか mirror とかあるがどれも古い)
サーバA は更新があったらサーバB に rsync。 B は C へ。 C は A へ。という形に。
これでファイルが upload されたら全サーバが共通のファイルを返せる。
結果、1台だけの時にスコアが 69770 に。3倍にできれば目標達成かな。


最終的な構成

3台 nginx にするより、2台 nginx + DB のがスコアが高かった。
あと mysqltuner というスクリプトを見つけて、それで値を調整。
最終的には score 270957 を達成したので脳内予選突破。



まとめ

  • ISUCON7 の予選問題のスコアを 27 万点くらいまで上げました。
  • 作業ノートによると58時間くらいかかっているらしい。
  • これで夏休みの自由研究2018としましょうか。



参考

2018/07/22

Docker Registry の backup と restore

前回は Image の Backup/Restore について書きました。
これで Image を指定してバックアップ可能になったのですが、Registry に登録される Image が1つとは限らない。
ということで Docker Registry ごと全イメージをバックアップしてみる。


環境

  • OS: CentOS Linux release 7.4.1708 (Core)
  • Docker: version 1.13.1, build 774336d/1.13.1
  • Kernel: 3.10.0-693.5.2.el7.x86_64


Docker Registry を tar にする

さて、Registry はコンテナ内部に登録イメージのファイルを持ってます。
ファイルごとバックアップを取りたいので、戦略としてはコンテナのバックアップを取る。
今度使うのは docker export コマンド。

  • $ docker run -d -p 5000:5000 --name registry registry:latest
  • $ docker push hogehoge
  • $ docker export registry > registry-backup.tar
これで Registry のコンテナが tar ファイルになります。


Docker Registry を復元する

さて、 tar ファイルから復元したいと思います。
  • $ docker import - registry:latest < registry-backup.tar
今回はタグの情報とかは無いので自分で指定する。
というかコンテナからイメージを作るので実質 docker commit みたいなものか。

tar から作られた registry:latest を実行します。
  • $ docker run -d -p 5000:5000 --name registry registry:latest
お? 動かない。 
/usr/bin/docker-current: Error response from daemon: No command specified.
と言ってくる。CMD の情報が吹っ飛んでるのか。
Github にある Registry の Dockerfile を見ると、'docker-registry' とすれば良いかな。
  • $ docker run -d -p 5000:5000 --name registry registry:latest docker-registry
動かない。今度は
/usr/bin/docker-current: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "exec: \"docker-registry\": executable file not found in $PATH
か。そんなコマンドは無いらしい。 
もうコンテナ内に入ってしまうかな。export 前の registry に対して
  • $ docker exec -it registry bash
すると
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:247: starting container process caused "exec: \"bash\": executable file not found in $PATH"
おお、bash すら無いのか。sh も無ければ最早 user interactive に何もできないコンテナだ。

  • $ docker exec -it registry sh
流石に sh はありました。find もある。
find で docker-registry を探しても無い。
他に探索していると registry というのが /bin/registry にあった。
実行すると serve か garbage-collect と help がサブコマンドにある。serve してみます。
  • $ registry serve
文句言ってきました。具体的には
configuration error: configuration path unspecified
と。 docker-registry の configuration path って何だろう。
どこかに mount してたらそれを参照してくれるから設定変更可能、とかそういう意図なんだろうか。

とかとか、いろいろ試した結果、ps で path が分かりました。
Process ID 1 のやつが
registry serve /etc/docker/registry/config.yml
で動いていました。
と、いうことで、実行するコマンドは
$ docker run -d -p 5000:5000 --name registry registry:latest registry serve /etc/docker/registry/config.yml
で Import した Registry を復元できました。やったね。


おまけ

/etc/docker/registry/config.yml を読むと storage.filesystem.rootdirectory が /var/lib/registry
だったので、run する時に -v で /var/lib/registry に Host の Directory を mount しておけば Image の保存が楽だった説が。

それと、Docker EE だと、 DTR (Docekr Trusted Registry) の backup/restore 手順が提供されています。
きちんとサポートを受けたい場合は Docker EE を使うのもアリかも。


参考

2018/07/15

Docker Image の backup と restore

さて、Docker Registry を立てたは良いものの、マシンが壊れたりすると悲しい事態になります。
Build 元と Registry で二重になってはいるのですが、両方が同じマシンだと悲しい事態が発生する可能性がありますね。
と、いうことで Build した Docker の Image をファイルに書き出したり、そのファイルからイメージを復元します。


環境

  • OS: CentOS Linux release 7.4.1708 (Core)
  • Docker: version 1.13.1, build 774336d/1.13.1
  • Kernel: 3.10.0-693.5.2.el7.x86_64


Docker Image をファイルへバックアップする

Docker そのものはファイル群を /var/lib/docker の下に持ってます。
Image は default だと overlay2 で作成されます。
overlay2 は差分でファイルを管理するファイルシステムなので、そういったメタ情報もバックアップしないといけない。
つまりは cp とか rsync だと事故る可能性があります。

さて、何を使うのが正しいかと言えば公式です。具体的には docker save コマンド。
Image を構成する全レイヤをきちんと tar に書き出してくれます。
実行例として、hogehoge Image をバックアップするのはこんな感じ。
  • $ docker image save hogehoge > backup.tar
この tar をバックアップ先 HDD 等に持っていけば良い。


Docker Image をファイルから復元する

バックアップする方法は分かりました。
次はバックアップからの復元。
docker load コマンドを使います。具体的には
  • $ docker image load < backup.tar
で終わり。
Image の repository name や tag も tar に入っているので、それらの情報も全部復元されます。楽。


参考