llsの開発背景
Weekend OSSです。今日も話をポッドキャストをやっていきたいと思います。よろしくお願いします。
よろしくお願いします。では早速ですが、まずはllsを作ったきっかけから伺ってみたいと思います。
どうして標準のlsではなく、こういうツールを作ろうと思われたんでしょうか。
そうですね。まず、lsって実は結構いろんなことをやっているんですね。
lsってよく打つと思うんですけど、実はファイルが順番に出るようにデフォルトだと相当してたりとか、
あと設定によってはディレクトリだと色が変わったりとか、いろいろ実はするんですよね。
あと、-lとか付けると実際のファイルの情報とかも出してくれたりとかしてます。
なんですけど、これが欠点になることってあって、例えば数十万とか数百万とか数千万とか、
すごい大量のファイルが同じディレクトリに入ってたりすると、
lsだと打っても何も返ってこなかったりするんですよね。
なので、そういう問題を解決したいというのでllsを作りました。
なるほど。つまりlsが便利な反面、大量のファイルがあるときには、
その便利さが逆に足がせになってしまうんですね。
じゃあそのllsは、そういった数十万数百万ファイルみたいな状況でも
サクサク動くように工夫されてるわけですね。あれは面白いです。
llsの動作原理
ちなみに、具体的にどうやってその高速化を実現してるのか、
もう少し詳しく教えてもらえますか。
先ほど言った相当とかもあるんですけど、実はls相当止めるオプションっていうのもあります。
なんですが、それをやっても限界があるんですよね、lsには。
これが何でかっていうと、システムコールを叩くときに、
システムコール自体の設定なんですけど、内部でバッファーが指定されていて、
システムコール自体というか、libcの制約ですかね。
バッファーが決まってしまっているので、大量のファイルを取ってこようとすると、
そのバッファーが小さすぎて、何回も何回も情報を取ってこないといけなくなるんですね。
なので、とっても重くなってしまって、途中で失敗、ハングアップしてしまうっていうふうになるんです。
なので、lsはGetDense64っていうシステムコールを直接叩く。
直接叩くときに、自分たちでちょっと大きめのバッファーを設定して、
そのバッファーを使って、そのシステムコールの結果を直接取ってきて、
そのシステムコールの結果を相当せずにそのまま出すっていうような設計になっています。
なるほど、そういうことなんですね。
つまり、lsは標準のlsが持っているバッファ制限や相当の負荷を回避するために、
自分で直接GetDense64を叩いて、大きめのバッファーでまとめてファイル一覧を取ってくるっていう感じなんですね。
しかも相当もしないから余計な処理が減って、結果的に高速化できると。
面白いアプローチですね。
観念する話ですが、こういった低レイヤーを直接扱うことで、
ゴーラシさや安全性をどう維持しているのか、その辺りもぜひもう少し聞かせてもらえますか。
そうですね。lsとかってC言語で書かれているんですけれども、
lsはゴーで書かれています。
なんでCで実装されることが多いのかというと、
システムコールを触るっていうのが基本C言語とかでないと難しいんですよね。
他の言語だとシステムコールを直接触るっていうのはなかなかできなかったりします。
なんですが、ゴーの場合はシステムコールを直接触る仕組みがいくつか用意されていまして、
標準パッケージのシスコールとか、
あとは純公式パッケージのExcess Unixとかもあるんですけど、
lsに関してはシスコールパッケージだけで対応できています。
そのシスコールパッケージを使って直接システムコールを触ることによって、
それがゴーで実装ができているという形になりますかね。
なるほど。ゴーにはそういうシステムコールを扱う仕組みがちゃんと用意されているからこそ、
LLSもゴーで安全に実装できているというわけなんですね。
llsの実用例と今後の展望
そういう意味でC言語のような低レイヤーの力を借りつつ、
ゴーならでは異色性や安全性を確保できるっていうのはまさにゴらしさですよね。
すごく面白いです。
じゃあもう少し掘り下げると、実際にLLSを現場で使ったときにどういった課題が解決できたとか、
ユーザーからどんな反応があったか、そういったエピソードがあればぜひ教えてください。
そうですね。実際に自分の身近に起こった問題なんですけど、
3000何百万というファイルがあるディレクトリがありまして、
そちらのファイルのLLSがどうしても出せなくて、
それによって他のサーバーに移行することすらできなくなってしまったという問題がありました。
なので、他のサーバーに移行しないと、いつかディスクが全部埋まってしまって、
サービス動かなくなってしまうので、そういったことがないように、
全てのファイルのリストを出力した上で移行し切るということが実際に可能になりました。
なるほど。まさに数千万ファイルみたいな極端な状況で、
LSが全く使えないという問題を実際に解決したわけですね。
それでサーバー移行ができるようになって、ディスクがあふれる心配もなくなったと。
実に実用的ですね。
関連する話ですが、同じようなアプローチを取っている他のプロジェクトやツールって何かありますか?
もしあればその違いなんかも気になります。
そうですね。自分が把握しているものはないんですけど、
実はこれ元ネタというか、僕そもそもこれ不可能だと思ってたんですよね。
以前からこういった局面にあったときに解決できたことはなかったので、
分からなかったんですが、実はハッカーニュースで、
GetAgent64を直接バッパー大きめにして渡して直接叩くと、
たくさんのファイルが入っているディレクトリのLSもできるよっていうのが出てきて、
ハッカーニュースでちょっと話題になっていたんですね。
それの記事を見つけまして、実際に実装してみたと。
その記事を書いた人は実際の実装っていうのを配ってなかったので、
実際にそれができる実装を作ってみて、それを実際に投入したらうまくいったっていうところですね。
なるほど。もともとはそんなことできないだろうと思っていたのが、
たまたまハッカーニュースでそういう手法が話題になっているのを見つけて、
それをヒントに実装してみたというわけですね。
実際にその実装例がなかったからこそ、
自分で実際にやってみてうまくいったっていうのは、
まさにオリジナルな貢献ですよね。面白いです。
じゃあ、今後の改善や発展の方向性って何か考えてますか?
例えば、こういう機能を追加したいとか、
ここをもっと良くしたいみたいな展望があれば、ぜひ教えてください。
そうですね。普段使うコマンドではないんですよね。
LSの完全な大体を目指しているわけじゃなくて、
大量のファイルがあるときにだけピンポイントで使うようなものを想定していて、
バッファーサイズを調整する機能とかはあるんですけど、
基本的にファイルのリストを標準出力に出す機能しかなくて、
リダイレクトして基本的なファイルに書き込んでくださいということを
お勧めしているんですけれども、
それぐらいの使い方しかないので、
基本機能追加とかは今のところ考えてないですかね。
なるほど。あくまで特定の状況でピンポイントに使う
ユーキリティとして割り切っているわけですね。
日常的なLSの大体を目指すんじゃなくて、
大量ファイルのときだけサッと使う感じで余計な機能は増やさない方針なんですね。
とてもシンプルで筋が通っていていいと思います。
もう少し関連する話ですが、
実際にこのLSを使ってみたい人がいたら、
どこで手に入れられるか、簡単に教えてもらえますか。
GitHub、自分のGitHubで実際にコンパイル済みのバイナリを配っていますので、
そちらでご利用いただけます。
ちょっと気をつけてほしいのは、Goってクロスプロットフォームなんで、
一つのGoのプログラムが複数のOSに対してコンパイルできるっていうのが特徴だと思うんですけど、
今回のLSはSyscallパッケージ使っていて、
SyscallパッケージってOSによって当然実装されてたりされてなかったり、
LLSの基本とフィードバック
実装されてる関数とされてない関数があるものなので、
OSによってコンパイルできたりできなかったりするんですよ。
今回のLSはLinuxにしか実装されてないものを使っているので、
Linuxのパッケージしかないですし、
そもそもMacだとコンパイルも昔はできなかったんですけど、
今はMacでもLinuxのバイナリだったらコンパイルできます。
ただMacのバイナリは当然コンパイルできないし、
VS Codeとかで表示しても実は波線が出てきたりとか、
そういうちょっと特殊なプログラムになっているので、
合成だけどLinux版のバイナリしか存在していません。
ただ両方とも、IntelとARM両方ともバイナリ配布してますので、
そちらから気軽にお使いいただけるかなと思ってます。
了解です。つまりGitHubで配布しているLinux向けのバイナリを使えばOKということですね。
Goのクロスプラットフォーム性はあるけれど、
今回はLinux限定の実装になっていると、
IntelとARMの両方のバイナリも用意されているから、
Linux環境であれば気軽に使えるという感じですね。
ではもう少し掘り下げていくと、
実際に使ってみたユーザーさんからのフィードバックで何か印象的なものや
面白い反応があったら教えてください。
そうですね。実際に知り合いで使ったという人がいたんですけど、
やっぱりサーバー上にたくさんファイルが大きな実装になっていて、
リストが出せなくなってしまったというところで、
気軽に使えて、本当にファイルのリストが出てきたのでびっくりした
みたいなフィードバックを得られたことはありましたね。
僕自身も使って、本当に出るんだ、ファイルのリスト全部出るんだみたいな
結構驚きがありましたね。
それはいい反応ですね。
実際に困っていた人が、本当に全部ファイルのリストが出たって
驚いてくれたっていうのは、作った側としても嬉しいですよね。
システムコールとOSS開発の学び
じゃあ、関連する話題として、今後このLLSを他の人が参考にしたり、
似たような問題を与えている人がいれば、どんなふうにアドバイスしますか。
例えば、自分でカスタムツールを作りたい人に向けて何か一言あればお願いします。
そうですね。以前、YapCで発表したことがあるんですが、
Goでシステムコール、触る方法みたいな記事書いたことあるので、
ぜひGoでシステムコールを直接触りたいという人がいたら、
参考にしてもらえたらなと思っています。
やっぱりシステムコールを直接触れる言語って、CとかGoぐらいしかないと思うので、
せっかくGoを使ってるんだったら、システムコールを直接触るプログラムも
そこまで難しくなく書けるので、ちょっと特殊なプログラムにはなるんですよね。
ちょっとGo運営っぽくないっていうのはあるんですよね。
GoってIO周りとか、結構Goウェイっぽくいろいろ作られてるんですけど、
あれってライブラリーの機能なんですよ、当たり前なんですけど。
システムコールってやっぱりLinuxの機能が向き出しになってるところなので、
そこを単体だけ見るとちょっとGoっぽくない部分もあるんですけど、
そこは関数とかにラップしてあげればGoウェイっぽくできますので、
そういうところを工夫してやってもらえると、うまくいくのかなと思ってます。
ありがとうございます。
なるほど、Goでシステムコールを直接触る方法の記事も書かれているんですね。
それを参考にすれば、他の人も同じような低レイヤーのプログラムにチャレンジしやすくなりそうです。
確かにGoは普段は高レベルなIOとかをうまく抽象化してくれているから、
直接システムコールを触るとちょっとGoっぽくない感じもあるけれど、
そこを自分でうまくラップすればGoらしさも維持できるということですね。
とても参考になります。
では最後にもう一つ関連する話題として、このLLSの開発を通じて得られた学びや、
他のOSS開発者へのメッセージがあればお願いします。
そうですね、やっぱりGoでシステムコールを直接触るプログラムは、
普段書き慣れていない人多いと思うんですけど、
実際やってみると結構楽しかったりします。
欠点というか、ちょっと特殊なのがGo側のドキュメントがほとんどないので、
Linuxのシステムコール自体だったりとか、
あとLibcのドキュメントだったりとか読まないといけないというのはあるんですけど、
ただGoはシステムコールを本当に呼び出しているだけなので、
そういうところをドキュメント読めば、どういう使い方をすればいいかというのは分かりますし、
ぜひ機会があったら触ってOSSのツールをどんどん作っていけたら面白いんじゃないかなと思っています。
ありがとうございます。
確かにGoでシステムコールを直に触るのはちょっと珍しい体験かもしれませんが、
やってみると楽しいし、新しい発見もあるんですね。
確かにドキュメントが少ない部分はありますけど、
Goはシステムコールを呼び出す仕組み自体はシンプルなので、
LinuxやGLMCの時を参照すれば意外と何とかなるということですね。
OSSツールを作ってみたい人はぜひチャレンジしてみてほしいというメッセージ、
すごく心強いと思います。
ということで、まだまだお話は尽きないですが、
こんなふうにいろんな話題を掘り下げていければと思います。
次はまた別の視点から何か面白い話題を引き出していきたいと思いますので、
引き続きよろしくお願いします。
お願いします。
LLSに関してはこれぐらいで終わりにしたいと思います。
あとでリンクとかドキュメントに貼っておきますので、
そちらで確認してください。よろしくお願いします。
了解です。それではLLSのお話はここまでということで、
インクやドキュメントは後ほど確認していただければと思います。
それじゃあ、引き続き別の話題や気になるトピックがあれば、
どんどん聞いていきますね。よろしくお願いします。
お願いします。