Devlion Memo

どことなくそれっぽい新卒の日記

2019年最高のWSL環境を求めて

環境のスクショ

2016年、僕はWSLに出会い感動してからというもの、「最高のWSL環境を求めて」さまよい続けました。
来る日も来る日も「Windowsは最高・・・Windowsはクソ・・・Windowsは最高・・・」と呟きながら花びらを散らし、バグのあるWindowsアップデートにも負けず、急に唸りだすRuntimeBrokerたちにも負けず、費やした時間は数知れず。
時にはディストリビューション壊して再インストールして、時にはHyper-Vに浮気をしたり、時にはiMacを買ってそっちに逃げたりしながら・・・。
今回は2019年、僕が「最高」だと思うWSL環境をまとめたいと思います。

過去の記事
mjhd.hatenablog.com

Xサーバ

LinuxGUIアプリケーションを表示するために必要なXサーバ、以前はVcxsrvを使っていましたが、現在のおすすめはX410です。
シェアウェアだけあってとても安定しています。とりあえず入れとけば完璧に動く、という安心感は他にありません。
今なら4700円割引(ほんとか)らしいです。

www.microsoft.com

ターミナルエミュレータ

ターミナルエミュレータはwslttyを使ったりX11経由でgnome-terminal, tilixなどを使っていましたが、やはり機能面と安定感の両立がなかなかできませんでした。
wslttyは機能面・デザイン面で劣るし、gnome-terminal、tilixなどをX11越しで使うのはIMEの設定が必要であったりクリップボードが安定しなかったり起動がもたついたり、なかなか満足いく体験には至りませんでした。

現在はalacrittyを使っています。
alacrittyはGPUを使用した高速なレンダリングが特徴の端末で、マルチプラットフォームなので機能面での不足はあまりありません。Rustさまさまです。
描画がとにかく早いので、WSL上でzsh使ってももたつきがほとんどないです。マジで早い。

Windowsの場合、初回起動時に「ホームディレクトリ\AppData\Roaming」以下に「alacritty/alacritty.yml」ファイルができるので、いい感じに設定してあげてください。
「alacritty theme」で検索すれば有名な色設定をコピペできます。
ConPTYの設定項目をtrueにしておくと良いです。
Microsoftも頑張っています。

https://cloud.githubusercontent.com/assets/4285147/21585004/2ebd0288-d06c-11e6-95d3-4a2889dbbd6f.png

github.com

あと、Terminus、FluentTerminalという端末もモダンでWindows10らしさがあって良いです。が、まだ発展途上ということもあり、特にパフォーマンスの観点でオススメできません。今後を見守りたいです。

https://github.com/felixse/FluentTerminal/raw/master/Screenshots/terminal.jpg

https://github.com/Eugeny/terminus/raw/master/docs/readme.png

Terminus

GitHub - felixse/FluentTerminal: A Terminal Emulator based on UWP and web technologies.

今後の改善点

やはりWSL最大の不満点は、Windows側からWSLのFSをいじれないことでしょう。
しかし、ここもMicrosoftは頑張っていて、UNIXドメインソケットを実装したことによりWindowsとWSL間の高速で汎用的な通信が可能になり、これを通してファイルを共有するという機能が盛り込まれると発表しています
(このアップデートが入るまではsftpやftpで共有するぐらいしか手段がなかった。samba動かんし。Dokan使ってマウントしたり)

WindowsからWSL側のファイルシステムが気持ちよく触れるようになれば、例えばWindowsネイティブのIDEからWSL上のプロジェクトを開き、ビルドなどはWSL上で行う、といったシームレスな開発ができるようになる予感がしています。
まだまださまよい続ける必要がありそうです。
Microsoft頑張って。

サウナー用語

この頃サウナにはまっており、話題のサービス「サウナイキタイ」のサウナー達によるレビューを読み漁ってたらなんとなくサウナー用語(サウナスラング)がわかってきたのでまとめる。

サウニング

サウナに入ること。また、サウナ->水風呂->休憩のサイクルを繰り返すこと。

サ飯

サウナ施設や近所で食べられるご飯のこと。主にサウナ後の空腹状態で食べる。

サ室

サウナ室のこと。広さや設備、温度が語られることが多い。

アフターサウナ

サウニングが終わった後のこと。

ととのう

サウナによってある種のトランス状態に入ること。

ととのいポイント

サウナ外にあるデッキチェアなど、サウナ->水風呂の後に精神統一できるスペース。

北欧

「上野サウナ&カプセルホテル北欧」のこと。「北欧に行く」と行ったら旅行に出かけるわけではなく、「上野サウナ&カプセルホテル北欧」で外気浴を満喫することを指す。

聖地

静岡にある「サウナしきじ」のこと。全国からサとりを開くためにサウナーたちが集まる聖地。水風呂に浸かると「宇宙が降りてくる」らしい。

ストロング系

温度設定の強めなサウナ、水風呂のこと。

はごろも

水風呂に浸かってしばらくすると皮膚の周りに出来上がるぬるい水の膜。水流が当たるとはごろもが取れるため、冷たく感じる。

グルシン

水風呂の水温が一桁台(シングル)であること。

バイブラ

浴槽内に設置される泡を放出する機械。水風呂内に設置された場合、体感温度が下がる効果がある。

チラー

水風呂において、循環した水を冷やすための機械。これが効いてないと人が入るたびにぬるくなっていく。

ニルヴァーナ

悟りを開くこと

2018年買ってよかったもの

年の瀬なので2018年に購入したものの中で、買ってよかったものをまとめてみた。

1位. ミラーボール

友人との会話の中でふざけて購入したミラーボールが思いのほか生活に潤いを与えてくれている。
このミラーボールは音に反応して光る機能があり、通常は流れている音楽のテンポに合わせて光らせる用途に使うらしいのだが、この機能が思いのほか日常生活で役立つ。
使い方としては、部屋の天井に装着し、音楽に合わせて光るモードを常にONにしておく。
例えば、友人を部屋に招いておしゃべりをするとき、話が盛り上がり、笑い声が出る。すると笑い声に反応してミラーボールが回りだす。それを見て笑いが止まらなくなる。ミラーボールは回り続ける。死ぬほど笑える。
意外性も高いため、今年1位。

2位. Surface Pro 6

今まで使っていたXiaomi Notebook Air 13を友人に売り、Surface Pro 6を購入した。ラップトップとしても、タブレット端末としても使える2-in-1。これを購入して家での過ごし方が変わった。
今までは、机にラップトップを置いておき、プログラミングなどの作業をする場合は机に向かう、机に向かうのに飽きたらソファーに座りスマホを触る、という過ごし方をしていたのだが、これがすべてSurfaceに置き換わった。
SurfaceはTypeCoverを外せばタブレット端末として使えるため、机から離れるときはTypeCoverさえ外せば自由に持ち運ぶことができる。
例えば、プログラムを書いていてビルド待ちの間TypeCoverを外し、ソファーに寝転がってビルドの進捗を確認しながらYoutubeを眺める、などといったことができるようになった。
性能も、i7 8650U 1.9~2.11GHz、メモリ16GB、SSD 512GBと通常のラップトップPCとしても申し分ない。
また、スピーカーも疑似サラウンドに対応していたり、ディスプレイの発色が良かったり、マルチメディアを楽しむうえでも十分なスペックがあると思う。
Surface Pencilは要らない。自分のような字が下手で絵も描けない人はミミズの絵を量産して飽きる。

3位. Qi充電器

充電が遅そう、劣化しそうなどのイメージがあったため使ってこなかったQi充電器だが、試しに使ってみたところ完全にハマった。普段使ってるのはiPhoneとAppleWatchを同時に充電できるタイプの充電器。
現在はオフィスと家にひとつづつ置くことで、充電ケーブルを持ち歩かない生活を送っている。ケーブルがないだけでデスク上も持ち物もかなりすっきりした。

4位. Philips Wake-Up Light

光で目を覚ましてくれる目覚まし時計。物は試しと思って買ってみたが、iPhoneのアラームで起きる2倍は目覚めが良い。
この目覚ましは、設定時刻の30分ほど前からゆっくりと明るくなっていく。この光によって半分覚醒している状態で設定時刻を迎えることができる。
設定時刻になると、鳥のさえずりの音声が流れだし、徐々に音量が大きくなっていく。 とはいえかなり小さい音、初めはこの音量じゃ起きれないだろと思っていたが、半分覚醒している状態のためこの音量でも十分起きることができた。起きれなかったことは一度もない。(ただし起きれても遅刻はする)
iPhoneのアラーム、強引に覚醒させるため、実はかなり健康に良くないんじゃないかと思うようになった。

5位. NILS

Kickstarterのプロジェクトだが、腕に取り付けることのできる充電ケーブル。
Qiで充電ケーブルを持ち運ばない生活を手に入れることはできたが、終電逃してネカフェなど、いざというときにUSBポートはあるのに充電できないという事態がたまに起こる。
そういう場合の対応策として、普段はアクセサリとして腕に装着しておき、いざというときに充電ケーブルとして使用することができるNILSを購入した。

www.kickstarter.com

今年もお世話になりました。

Golangのメモリ周りのメモ

以前、このレポジトリがバズっていた。

GitHub - intel-go/bytebuf: Example of how CL133375 can be utilized to mitigate Go escape analysis limitations.

bytebufが小さなサイズのバッファ用にあらかじめ用意しているbootstrapというバイト列が、エスケープ解析の際に必ずヒープ上に確保されてしまうため、buffer構造体も本来はスタック上に確保できるはずであるが、ヒープ上にエスケープされてしまうという問題があった。
つまり、64byte以下の小さなバッファであっても必ずヒープ上にアロケーションが走ってしまい、パフォーマンスが落ちていた。

この件は既にパッチが当たっており、正しくエスケープがされるよう修正されているのだが、これをきっかけに「なんでヒープに確保することが重たいんだっけ」「どういうときにエスケープされるんだっけ」などのメモリ周りを調べたメモ。

なんでヒープ確保が重たいの

スタックの確保はとてもシンプルで、関数呼び出し時にスタックを伸ばし、関数を抜けた時点でスタックを縮める。
比較して、ヒープ上へ確保する場合は、確保先の探索、GCなど様々な処理が走り、この差がパフォーマンスに効いてくる。
他の関数で参照される、参照を取得する必要があるといった場合を除き、極力エスケープしないようなコードが高速に動作する。

エスケープされる条件

基本的には、

  • 関数内のみで参照される値は、スタック上に確保される
  • そうでないものは、ヒープ上へ確保される

のだが、コンパイラが途中で解析を止め、エスケープする条件が複数ある。

この条件は日々変更が入ったり、今回のような特定の条件下で異なる動作をする場合があるため、網羅することはできないが(本来プログラマが意識するべきではないが)、2015年の時点で以下のリンクなどにまとまっている。

Go Escape Analysis Flaws - Google ドキュメント

Goの公式ドキュメントを読んでも「すべての条件を説明するのは複雑すぎるので、コンパイルフラグで実際にエスケープされるか確認して」と書いてある。 以下のコマンドで確認することが出来る。

$ go build -gcflags '-m' ./main.go

CompilerOptimizations · golang/go Wiki · GitHub

関数のインライン化

直接関係はないが、エスケープ解析に効いてくる最適化の一つに、関数のインライン化の解析がある。

Goのコンパイラは、関数が以下の条件に当てはまるとき、関数を直接、呼び出し元に展開する最適化を行っている。(これも上のコマンドで解析結果を確認できる)

  • コードが80ノード以下(Go1.4以前は40ノード)
  • 関数呼び出し、ループ、ラベル、クロージャ、panic、recover、select、switchなどの複雑な構文を含まない

CompilerOptimizations · golang/go Wiki · GitHub

このインライン化がどうメモリ周りに効いてくるかというと、インライン化が無い場合、関数の引数に値を渡した時点でその値はヒープ上に確保されてしまう。 しかし、インライン化された関数であれば、関数内での値の使用となるため、スタック上の確保で済む。

別の記事で、この最適化を意識したコードの例を考えてみたいと思う。

参考

CompilerOptimizations · golang/go Wiki · GitHub

najeira: Go言語のスタックとヒープ

Escape-Analysis Flaws Go, (Golang) Programming - Blog - Ardan Labs

Allocation efficiency in high-performance Go services · Segment Blog

Prometheusの長期ストレージメモ

Prometheusを使うに当たって、長期ストレージについて調査をしたのでそのメモ。

Prometheus v2

Prometheus v2では、Remote Long-Term Storageのサポートがされている。以下のストレージを選択可能。

AppOptics: write
Chronix: write
Cortex: read and write
CrateDB: read and write
Elasticsearch: write
Gnocchi: write
Graphite: write
InfluxDB: read and write
IRONdb: read and write
M3DB: read and write
OpenTSDB: write
PostgreSQL/TimescaleDB: read and write
SignalFx: write

https://prometheus.io/docs/operating/integrations/

Thanos

Thanosは、Prometheusのサイドカーとして動作し、長期ストレージ、クエリの高可用性、ストレージの最適化などを行ってくれるミドルウェア

既存のPrometheusにサイドカーを付け足せば良いため、運用後導入することも可能。

Thanosは複数のコンポーネントから構成され、Sidecar、Store、Query、Rule、Compactorが存在する。

実際の収集はPrometheusが行い、それをSidecarを通してStoreコンポーネントが永続化を行う。

クエリ発行時はQueryコンポーネントがStoreコンポーネントに問い合わせる形でメトリクスを返す。

Compactorは永続化ストレージ上のデータのコンパクションを行う。

RuleはPrometheusのruleなどを分散管理するコンポーネントなのだが、仕組み上実験的なものとなっている。そのため、プロダクションで使用する際にはRuleコンポーネントを使わずに、各Prometheusに個別にRuleを定義し、管理することが推奨されている。

コンポーネントはgossipプロトコルを通してゆるふわに繋がるので、共通のserviceに繋げれば特に設定はいらない。

導入はとても楽であるが、Prometheus詳しい人に聞くと、口を揃えて「良さそうだけど、まだ微妙」みたいな意見が聞ける。

いまさらSSL/TLS証明書

今までSSL証明書をなんとなく雰囲気で使っていた感が否めないため、自信を持って解説ができるよう具体的な仕組みを調べたメモ。

X.509証明書

X.509証明書はISO/IECによって定められている証明書に関する仕様。

公開鍵証明書、属性証明書、特定証明書の三つがあり、主に公開鍵証明書が一般に「証明書」と呼ばれる。

公開鍵証明書は、CA証明書とエンドエンティティ(またはリーフ)証明書に別れる。

CA証明書はルートCA証明書と、中間CA証明書に別れ、ブラウザやOSはルートCA証明書の一覧をあらかじめ持ち検証に使う。ルートCA証明書は中間CA証明書を発行することができ、その中間CAも新しい中間CA証明書を作成することができるため、チェーンする。

CA証明書かどうかは、拡張領域のbasicConstraints(基本制約)フィールドに設定されるフラグにより判断され、CAであれば上位のCAをたどり、ルートCAまで遡れれば検証が完了する。

例えば、以下はGoogleにopensslを用いてアクセスをした例:

depth=1 /C=US/O=Google Trust Services/CN=Google Internet Authority G3
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
   i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
 1 s:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
   i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign

sがSubject(証明の対象)、iがIssuer(発行者)。 www.google.comに対する証明書から、Google Trust ServicesのCA、GlobalSignのルートCAと辿れていることがわかる。 (GlobalSignはGMOグループのルート認証局GoogleGMOに依存してるの意外。)

apacheだと中間証明書を指定するディレクティブがあるため意識しないが、nginxなどでは公開鍵に中間証明書を結合して設定する必要がある。 (PEMファイルの仕様 https://tools.ietf.org/html/rfc7468#page-5サーバ証明書、中間CA証明書の順で結合する。https://tools.ietf.org/html/rfc4346#page-41)

証明書の失効

証明書に記載されている有効期間(notBefore, notAfter)以外の理由で失効する場合、証明書の失効はCRLまたは、OSCPというプロトコルによってクライアントに伝えられる。CRLは証明書に付与されるシリアルナンバーのリストをWeb上でホストする方式で、古いTLSクライアントで用いられている。このリストは肥大化するため、デルタCRLという差分のみを提供する方式がある。

OSCPは認証局に証明書の状態を問い合わせるプロトコル。クライアントが直接叩くか、OSCP staplingを用いてサーバが代わりに認証局へ問い合わせる方式がある。

GoでSpannerを扱う際のポイント

そもそもSpannerって?

SpannerはGCPが提供する高可用性のあるリレーショナルデータベース。SQL文が使え、スキーマ定義・スキーマの変更・SELECT系のクエリを実行できる。(INSERT, UPDATE, DELETEは無い) プライマリーキーを適切に設定すれば、負荷に応じて自動でシャーディングを行ってくれる。トランザクションも使える。 この辺がよくまとまっている。 超実践 Cloud Spanner 設計講座

GoでSpannerを利用した開発を行う中で、何点かわかったことがあったのでそのまとめ。

CreateSessionは遅い

Spannerに対してリクエストを行うとき、まずCreateSessionというgRPCが走るのだが、これが500msぐらいかかるため、Spannerに対して初めてリクエストを送る際など遅延が発生する。 これを防ぐために、SessionPoolConfigを適切に設定する必要がある。 spanner - GoDoc SessionPoolConfigの値は、 https://cloud.google.com/spanner/docs/sessions この記事を見ながら設定すると良い。(Spannerはこの辺のドキュメントが全て日本語で読めるためありがたい…)

クエリの遅延が発生した場合、この辺の設定を見直すことをおすすめする。

DeleteでAllKeyは(基本的に)使えない

テーブル内の全データを削除したいと思ったとき、愚直に考えれば「DeleteにAllKeys渡せばいいんだろ」となるのだが、データ数が増えた場合にこの戦略は使えなくなる。 CloudSpannerは、変更系のクエリの影響範囲が20000件以内、という制限を持つ。これは、UPDATEやINSERTに関しては「影響を受ける列数が20000件以内」で、DELETEに関しては「影響を受ける行数が20000件以内」となる。あくまで「影響を受ける」件数であるため、20000件以上のデータを持つテーブルの初期化は、「一度消して作り直す」しか方法が無いらしい。

ALTERで追加するカラムにはNOT NULL制約が付けられない

SpannerのALTER文の文法にはしっかりと「NOT NULL」という規則が載っているのだが、 https://cloud.google.com/spanner/docs/data-definition-language#alter_table 実際には使うことができない。Spannerは標準で新しく作ったカラムにはNULLを入れるのだが、NOT NULL制約を指定すると矛盾が発生するため、指定することができない。

セカンダリインデックスの場合も、スプリットを意識したキーを選ぶ必要がある

SpannerのPKを選ぶ際、スプリットが入ることを意識してキーを選ぶ必要があるのはご承知の通りだと思うが、セカンダリインデックスについても、スプリットが入ることを意識し、ホットスポットが入らないようなキーを選ぶ必要がある。
ドキュメントにも明記されているのだが、セカンダリインデックスもテーブルとして実装される。よって、セカンダリインデックスに指定したキーは、そのテーブルの主キーとして使用され、スプリットもそのキーによって決められる。
よって、アクセスが集中しやすいテーブルでセカンダリインデックスの先頭にCommit Timestampなどの単調に増加・減少する値を設定した場合、ホットスポットが発生し、スケールしなくなる。

今後、また気づきが増えたタイミングで更新します。