読者です 読者をやめる 読者になる 読者になる

自作Linuxコンテナの時代

Linux Docker Container

最近、Docker以外のコンテナ型仮想化技術の流れとして、自作コンテナエンジンの時代が来るのではないかと感じている。

自作コンテナエンジンとは、コンテナ型仮想化技術を構成する個々の要素技術を組み合わせ、自分の用途にあわせて最適化したコンテナエンジンのことだ。 他のOSのコンテナ仮想化技術について疎いため、以下ではLinuxに限定して話を進める。

続きを読む

ウェブアプリケーション開発に新言語を採用したときにインフラで考えたこと

この文章は、サーバサイドのウェブアプリケーション開発において、社内実績の少ない新しい言語を採用したときにインフラ面で考慮したことを社内向けにまとめたものです。

はてなでは、長らくPerlでウェブアプリケーション開発を続けてきた一方、ここ数年で社内でScalaまたはGoの採用事例も増えてきました。 今後開発が始まるプロダクトにおいても、Perl、Scala、Goもしくは他の言語を採用するかどうかを開発開始時に選ぶことになるでしょう。

新言語を採用するときに、考慮すべきことの一つとして、「インフラ」への影響があります。 新言語に関する雑談をしていると、ウェブアプリケーションエンジニアに「インフラ」への影響について聞かれます。 もしくは、ウェブオペレーションエンジニアから考慮するポイントを伝えることもあります。 ScalaやGo以外に、Node.jsやサーバサイドSwiftはどうかというのも雑談レベルで話をしたりもしました。

そのような流れがあったため、ScalaまたはGoで書かれたプロダクトを2年ぐらい運用した結果をまとめておきます。

ウェブアプリケーション開発の言語として何を選ぶのか、といった技術選択そのものについては、はてなでの10年戦える新技術採用戦略の話 - Hatena Developer Blog を参考にしてください。

ウェブサーバアーキテクチャ

1つ目は、ウェブサーバアーキテクチャです。新言語を採用したときに、アプリケーションが動作するウェブサーバのアーキテクチャが変わる可能性があります。

ウェブサーバアーキテクチャ自体については、下記のエントリに書きました。詳しい内容はこのエントリを参照してください。

まず、採用しようとしている言語のウェブサーバが、上記エントリでいうところの、どのモデルなのかを確認します。

  • マルチプロセス(prefork)型
  • マルチスレッド型
  • イベント駆動型
  • ハイブリッド型
  • 軽量プロセス型

マルチプロセス(prefork)型

prefork型の場合、リクエスト処理コンテキストの単位がプロセスなので、コンテキストあたりのメモリ空間が独立しているという特徴があります。 MaxReqsPerChildのようなN回リクエストを処理しなおしたらforkし直すというようなこともできます。 したがって、運用観点でいうと、メモリリークや地雷リクエストへの対処がしやすいと言えます。

よほど1台あたりのパフォーマンスを求められない限りは比較的運用しやすいモデルといえます。

Perlの世界ではprefork型がデファクトになります。Rubyの場合はUnicornなどが相当するでしょう。 JVM上で動作する言語では普通やらない仕組みだと思います。

マルチスレッド型(スレッドプール)

マルチスレッド型は、リクエスト処理コンテキストの単位がスレッドなので、各コンテキストがメモリ空間を共有しているという特徴があります。 したがって、スレッド間でリソース競合を起こす可能性が高いため、プログラマが意識して競合を避ける必要があります。

意識といってもビジネスロジックのコードが問題になるというよりは、言語処理系の実装やライブラリの実装側に問題があることが多いと思います。 以前、Scalaのobjectのメソッド内のローカル変数の lazy valを使っている箇所のリソース競合問題により、著しくアプリケーションサーバのスループットが落ちるという現象がありました。

Javaの世界でよくみるモデルだと思います。他には、RubyのPumaなど。(追記: Pumaについては現在はマルチプロセスとマルチスレッドのハイブリッドモデルであるとコメントをいただきました。)

ウェブアプリケーション開発に新言語を採用したときにインフラで考えたこと - ゆううきブログ

Rubyのマルチスレッド型として紹介されるとMRIのGILが気になってしまいそうですが、Pumaは2以降のclustered modeだとマルチプロセス・マルチスレッドのハイブリッドなのでMRIでもコアを使い切れます。

2016/03/02 20:53
b.hatena.ne.jp

イベント駆動型

イベント駆動型は、イベントループにより1つのスレッドで複数のコンテキストを並行に処理します。 1スレッドで動作するので、マルチスレッド型以上にリソース競合に気をつける必要があります。

特にI/O処理をする場合、基本はノンブロッキングI/Oを使うことになります。 「ミドルウェアクライアント」の項にもでてきますが、意図せずブロッキングI/Oを使ってしまうと他のI/O処理をすべてブロックしてしまうので注意が必要です。

Node.js、RubyのThinなどで有名なモデルです。

ハイブリッド型

ハイブリッド型は上記の3種類のモデルの混合モデルを指します。 例えば、Play2のデフォルトはマルチスレッド+イベント駆動型になります。アプリケーションサーバにはあまり使われませんが、Nginxはマルチプロセス+イベント駆動型になります。

マルチプロセス/マルチスレッド+イベント駆動型の場合、たとえブロッキングI/Oを使っていても、ワーカープロセス/スレッド数分の並列度を維持できるので、あまり気にせずブロッキングI/Oを使うという選択肢もあると思います。

軽量プロセス型

Goのgoroutineベースのウェブサーバなどがこのモデルに相当します。 インフラ運用視点では、基本的にマルチスレッド型に近いと思います。

前述の3つのモデルはOSの仕組みを直接利用するものでしたが、軽量プロセスは、言語処理系上に実装されるため、言語ごとに特性を持っているといえます。 Goの場合、複数のgoroutineがOSの一つのスレッド上に多重化されます。

Goのネットワークサーバについては下記の資料が参考になります。 イベントループなしでのハイパフォーマンス – C10K問題へのGoの回答 | プログラミング | POSTD

JVMや軽量プロセス型の言語のように、言語処理系側で多くの制御をいれるような実装の場合、ロードアベレージやCPU利用率のようなOSのメトリックだけみてもボトルネックがわかりづらいです。

ミドルウェアクライアント

2つ目はMySQLやRedisなどのミドルウェアに接続するためのクライアントの実装に何が必要なのかについてです。

特にデータベースの接続管理まわりの話は以下のエントリにまとめています。

フェイルオーバ後の再接続

特に常時接続で問題になりやすいのが、ミドルウェア側がフェイルオーバした場合に、クライアントがフェイルオーバ先に再接続してくれるかどうかです。

再接続がうまくいかなければ、アプリケーションサーバを再起動するなどの対応が必要です。 これではいくらミドルウェア側で自動的に待機系に切り替わる仕組みをいれていたとしても意味がありません。

クライアントが再接続するためには、例えばRDBMSの場合、トランザクション開始時にpingして失敗したら再接続するような実装が必要です。 ただし、トランザクション中に再接続してしまうと、トランザクションがリセットされて、ACIDを満たせないことがあるからです。(再接続時にトランザクションがリセットされるかどうかはデータベースの実装によるところが大きいと思います。)

AWSのマネージドサービスであるRDS/ElasticCacheを利用する場合、DBのエンドポイントはDNSで参照することになります。 DNS参照の場合、再接続時に、DNSを引き直すような実装になっている必要があります。

このあたりはtkuchikiさんがわかりやすくまとめてくれています。

ブロッキングI/OとノンブロッキングI/O

ウェブアプリケーションサーバがイベント駆動型の場合、ミドルウェアクライアントのI/OがブロッキングI/OかノンブロッキングI/Oかはかなり重要です。

例えば、よくあるはまりどころに libmysqlclient はブロッキングI/Oしか対応していないため、libmysqlclientを用いたミドルウェアクライアントは仮にインタフェースが非同期であっても実際はブロックしてしまいます。

ScalaからJavaのライブラリを呼ぶ時などは注意が必要かもしれません。

ジョブキュー

ResqueやTheSchwartzのような汎用のジョブキューシステムが新しい言語では使えない可能性があることに注意が必要です。 実際、TheSchwartzやGearmanは基本的にPerlの実装です。ResqueやSidekiqは基本Rubyの実装ですが、他言語の実装もあります。しかし、挙動が一致している保証はないため、ある程度検証する必要はあると思います。

新言語を採用したときに、今までと同じジョブキューが使えない可能性があることは意外と盲点でした。 障害時にジョブキューの挙動を把握しておくことはかなり重要です。学習コストを抑えるために、できれば社内で言語ごとに異なる種類のジョブキューを運用するのは避けたいところです。

言語に依存しないジョブキューについて考えていた時期もありました。

実際には、特定言語に依存した汎用のジョブキューを使わずに、Redisを用いてアプリケーションに密結合する形で非同期処理をしていたりします。

DBスキーママイグレーション

DBスキーママイグレーションは、言語というより、ウェブアプリケーションフレームワークごとに管理の仕組みがあります。 Railsのmigrationが有名です。Play2ではevolutionという仕組みがあります。

Perlのプロダクトでは、スキーママイグレーションのための仕組みを用いずに、手動で丁寧にALTERするか、mysqldiffのような素朴なCLIツールを使っていました。

そこからスキーママイグレーションの仕組みに移ると、気軽にスキーマを変更しやすい反面、仕組みが複雑になりやすいというデメリットがあります。 データ量が増えているのに気づかず気軽にマイグレーションが発生した結果、ALTERによるテーブルロック時間が長くなり、無視できないダウンタイムが発生することもあるかもしれません。 (アプリケーションエンジニアが気をつけていてくれるので、自分はまだこの問題を実際に経験してはいませんが、今後を考えると不安にはなります。)

デプロイ

成果物の配置

インタプリタ型言語とコンパイラ型言語では、デプロイ先サーバへの成果物の配置方法が異なってきます。

PerlやRubyのようなインタプリタ型言語はビルドが不要なため、モジュールのインストールは必要ですが基本的にサーバ上でgit pullしてデプロイできます。 もしくは、管理サーバからデプロイ先にrsyncしてデプロイすることもできます。要はソースファイルを設置できればよいということになります。

ScalaやGoなどのコンパイラ型言語でも、ソースファイルをgit pullもしくはryncして各サーバでコンパイルすることも考えられなくはないです。しかし、本番サーバでCPU負荷のかかるコンパイルをやりたくはありません。コンパイルするための環境を用意するのも面倒です。

そこで、コンパイラ型の言語では、CIサーバかなにかで一旦ビルドしておき、ビルドした成果物をファイルサーバなりS3なりに置いて、デプロイ時に対象サーバに設置するというやり方でデプロイしています。

このとき、CIサーバと本番サーバとで、プロセッサのアーキテクチャ、OS、共有ライブラリなどを揃えておく必要があります。 ただし、JVM言語だとそのあたりの差分をある程度JVMが吸収してくれるため、そこまで気にしなくてよいかもしれません。さらに、Go言語はクロスコンパイルできてなおかつ、ポータビリティも高いので、JVM言語同様にそこまで気にしなくてもよいと思います。

ホットデプロイ(Graceful Restart)

言語ごとにホットデプロイ用のツール/ライブラリがある印象です。

PerlのPlackアプリケーションの場合、Server::Starterが有名です。 RubyのUnicornでServer::Starterに対応させたりもしているようです。「Server::Starterに対応するとはどういうことか」の補足 - sonots:blog Goの場合、Go言語でGraceful Restartをする - Shogo's Blog に紹介されている通り、いくつかの実装があります。ここに紹介されている以外にも、いくつか見た記憶があります。

JVM言語のホットデプロイの実装を見つけられなかったので、Scalaアプリケーションでは結局1台ずつローリングデプロイする手法をとっています。(追記:クラスローダによるホットデプロイの実装があるのは知っていますが、本番環境で使うものではないと聞いています。本番環境で使ってる事例があれば知りたいです。) 具体的には、SIGTERMシグナルを受け取ると、ロードバランサ用に生やしたヘルスチェックエンドポイントで503を返し、リクエストを振り分けられないようにします。その間、処理中のリクエストはそのまま処理しながら、N秒待ってからプロセスを停止します。 これら一連のフローを1or2台ずつ順番にやっています。 このような仕組みをPlay2のプラグインとして実装しています。

Server::Starter式に比べてデプロイに時間がかかるため、新旧のアプリケーションの共存時間が長くなってしまいます。 できればローリングデプロイをやめたいところです。

Server::StarterをJVM言語で使えるという話もあります Server::Starter から簡単に Java プロセスを起動できるようになった - tokuhirom blog。JVMのプロセスを2つたてたときのメモリ消費が気になるものの、そろそろこれを試すかという気持ちもあります。

もしBlue Green Deploymentができるなら、言語非依存な形でホットデプロイできることになります。

CI

インタプリタ型言語かコンパイラ型言語かによって、CIサーバのCPUリソースの消費特性が変わることがあります。

インタプリタ型の場合、CIではテストのみを実行するのが普通です。 しかし、コンパイラ型の言語だと、当然ですが、CIでコンパイルもします。 前述のデプロイの項目でも書いたとおり、成果物をCIサーバでビルドすることもあります。

特にScalaの場合、コンパイルが遅いことが有名です。 遅い上に自分の知る限りScalaの標準コンパイラはマルチコアスケールしないため、CIサーバにマイクロアーキテクチャが新しく、クロック周波数の高いCPUが求められます。(ということを実際のJenkins環境のCPUの使い方から観測していました。しかし、id:tarao さんによると、プロジェクトを複数のサブプロジェクトに分割していると並列ビルドされるということがあるようです。実際にサブプロジェクトに分割している環境でマルチコアスケールしていることを観測されたようです。)

一方で、インタプリタ型、コンパイラ型のどちらであっても、テスト実行にはCPUリソースを要します。 しかし、テストコードを工夫して、テスト実行を並列化できるため、テスト実行のためのCPUをコア数重視で選ぶこともできます。

モニタリング

ウェブアプリケーションサーバに必要なメトリックは、時間あたりに処理したリクエストの数や処理中のワーカー数などが一般的です。

当たり前ですが、言語処理系やウェブサーバごとに取得できるメトリックが異なります。 メトリックの取得方法も特に統一されたなにかがあるわけではありません。 メトリックがデフォルトで提供されていないことも普通です。 PerlだとPlack::Middleware::ServerStatus::Liteのような3rd partyのツールでメトリック取得用のエンドポイントを生やします。 Play2では、このようなプラグインが見当たらなかったので、stats取得用エンドポイントを生やしてもらいました。

ウェブサーバとしてのメトリック以外に、言語のランタイムに関するメトリックがほしいこともあります。 JVMの場合は、jstatもしくはjolokiaのようなツール/ライブラリで取得できます。 Goには標準的なものがなく、golang-stats-api-handlerのようなライブラリを使います。

あとがき

この文章で言いたいのは、開発言語の選択は単にプログラミング領域だけの問題ではないということです。

最初は開発言語の違いがどれくらいインフラに影響を及ぼすかはぼんやりとしかイメージできていませんでした。 実際にやってみて、結構あれこれと既存のものが使えないことに気づいていきました。

事前にわかっていればこの言語は選択しなかった、ということがないように、言語選択の議論に「インフラ」を絡める参考になればと思います。

「インフラ」と題打ってはいますが、実際には、ウェブアプリケーションエンジニアとウェブオペレーションエンジニアの境界の話です。 インフラの人がやってくれる、もしくはアプリの人がやってくれるというのではだめで、自分事として意識するのが大事だと思います。

※ 今回の話は 第3回関西ITインフラ系勉強会 - connpass で発表した内容を加筆修正したものです。

Linuxサーバにログインしたらいつもやっているオペレーション

Linux Performance

主にアプリケーション開発者向けに、Linuxサーバ上の問題を調査するために、ウェブオペレーションエンジニアとして日常的にやっていることを紹介します。 とりあえず調べたことを羅列しているのではなく、本当に自分が現場で使っているものだけに情報を絞っています。 普段使っているけれども、アプリケーション開発者向きではないものはあえて省いています。

MySQLやNginxなど、個別のミドルウェアに限定したノウハウについては書いていません。

ログインしたらまず確認すること

他にログインしている人がいるか確認(w)

wコマンドにより現在サーバにログインしてるユーザ情報をみれます。

$ w
 11:49:57 up 72 days, 14:22,  1 user,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
y_uuki   pts/0    x.x.x.x 11:49    1.00s  0.02s  0.00s w

再起動などシステム影響がありうるオペレーションをする場合、同僚が他の作業をしていないかどうかをチェックします。

サーバの稼働時間の確認 (uptime)

サーバが前回再起動してから現在までの稼働している時間をみれます。下記の例の場合、72日間稼働しています。

$ uptime
 11:55:39 up 72 days, 14:28,  1 user,  load average: 0.00, 0.02, 0.05

DOWNアラートがきたときに、このコマンドをよく打ちます。DOWNアラートが来ていても、実際にOSが再起動していないということはよくあります。 これは監視システムと対象ホスト間のネットワーク不調が原因で、DOWNアラートが来ることがあるためです。 AWS EC2のようなVM環境の場合、ハイパーバイザ側のネットワークスタック不調などにより、監視システムと疎通がなくなるということがありえます。

uptimeコマンドにより、前回のシャットダウンから現在までの経過時間を知れます。上記の例の場合、72日間ですね。 OSが再起動している場合、MySQLサーバのようなデータベースのデータが壊れている可能性があるので、チェックする必要があります。

プロセスツリーをみる (ps)

サーバにログインしたときに必ずと言っていいほどプロセスツリーを確認します。 そのサーバで何が動いているのかをひと目で把握できます。

ps auxf

ps コマンドのオプションに何を選ぶかはいくつか流派があるようです。自分はずっと auxf を使っています。 aux でみてる人もみたりしますが、 f をつけるとプロセスの親子関係を把握しやすいのでおすすめです。 親子関係がわからないと、実際には同じプロセスグループなのに、同じプロセスが多重起動していておかしいと勘違いしやすいです。

...
root     25805  0.0  0.1  64264  4072 ?        Ss    2015   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
nginx    25806  2.6  0.7  70196 15224 ?        S     2015 2691:21  \_ nginx: worker process
nginx    25807  2.7  0.8  71700 16416 ?        S     2015 2725:39  \_ nginx: worker process
nginx    25808  2.7  0.7  70672 15336 ?        S     2015 2725:30  \_ nginx: worker process
nginx    25809  2.7  0.7  71236 15976 ?        S     2015 2709:11  \_ nginx: worker process
nginx    25810  2.6  0.9  74084 18888 ?        S     2015 2646:32  \_ nginx: worker process
nginx    25811  2.6  0.6  69296 14040 ?        S     2015 2672:49  \_ nginx: worker process
nginx    25812  2.6  0.8  72932 17564 ?        S     2015 2682:30  \_ nginx: worker process
nginx    25813  2.6  0.7  70752 15468 ?        S     2015 2677:45  \_ nginx: worker process
...

pstree でも可。ただし、プロセスごとのCPU利用率やメモリ使用量をみることも多いので、ps をつかっています。

NICやIPアドレスの確認 (ip)

ifconfig コマンドでもよいですが、ifconfig は今では非推奨なので、 ip コマンドを使っています。 ipコマンドはタイプ数が少なくて楽ですね。

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:16:3e:7d:0d:f9 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.10/22 brd z.z.z.z scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.0.0.20/22 scope global secondary eth0
       valid_lft forever preferred_lft forever

上記の出力例ではよくみているとセカンダリIPがついています。セカンダリIPがついているということは、なんらかの特殊な役割をもつホストである可能性が高いですね。 特にVIPを用いた冗長構成をとっている場合、VIPがついているならばマスタであると判断できます。 社内では、eth0に対するセカンダリIPや、eth1にプライマリIPをVIPとして利用することが多いです。

このような事情もあり、サーバにログインするとIPアドレスのチェックを癖でやってしまっています。

ファイルシステムの確認(df)

ファイルシステムの容量確認は df コマンドを使います。-T をつけると、ファイルシステムの種別を確認できます。-h をつけると、サイズ表記がヒューマンリーダブルになります。

$ df -Th
Filesystem                                             Type      Size  Used Avail Use% Mounted on
rootfs                                                 rootfs     20G  2.4G   17G  13% /
udev                                                   devtmpfs   10M     0   10M   0% /dev
tmpfs                                                  tmpfs     3.0G  176K  3.0G   1% /run
/dev/disk/by-uuid/2dbe52e8-a50b-45d9-a2ee-2c240ab21adb ext4       20G  2.4G   17G  13% /
tmpfs                                                  tmpfs     5.0M     0  5.0M   0% /run/lock
tmpfs                                                  tmpfs     6.0G     0  6.0G   0% /run/shm
/dev/xvdf                                              ext4     100G   31G    69G   4% /data/redis

dfコマンドにより、ディスク容量以外にも、いくつかわかることがあります。

例えば、MySQLのようなデータをもつストレージサーバは、本体とは別の専用のディスクデバイスをマウントして使う(EC2のEBSボリュームやFusion-IOの ioDriveなど)ことがあります。

上記の出力例の場合、/data/redis に着目します。前述の「プロセスツリーをみる」により、Redisが動いていることもわかるので、RedisのRDBやAOFのファイルが配置されていると想像できます。

負荷状況確認

次は、Linuxサーバの負荷を確認する方法です。そもそも負荷とは何かということについて詳しく知りたい場合は、「サーバ/インフラを支える技術」の第4章を読むとよいです。

Mackerelのような負荷状況を時系列で可視化してくれるツールを導入していても、以下に紹介するコマンドが役に立つことは多いと思います。 秒単位での負荷の変化やCPUコアごと、プロセスごとの負荷状況など、可視化ツールで取得していない詳細な情報がほしいことがあるからです。

Mackerelである程度あたりをつけて、サーバにログインしてみて様子をみるというフローが一番多いです。

top

top -c をよく打ってます。 -c をつけると、プロセスリスト欄に表示されるプロセス名が引数の情報も入ります。(psコマンドでみれるのでそっちでも十分ですが)

さらに重要なのが、top 画面に遷移してから、 キーの 1 をタイプすることです。1 をタイプすると、各CPUコアの利用率を個別にみることができます。学生時代のころから当たり前に使ってたので、たまにご存知ない人をみつけて、意外に思ったことがあります。(mpstat -P ALL でもみれますが)

かくいう自分も これを書きながら、top の man をみてると知らない機能が結構あることに気づきました。

top - 16:00:24 up 22:11,  1 user,  load average: 1.58, 1.43, 1.38
Tasks: 131 total,   2 running, 129 sleeping,   0 stopped,   0 zombie
%Cpu0  : 39.7 us,  4.1 sy,  0.0 ni, 48.6 id,  0.3 wa,  0.0 hi,  6.9 si,  0.3 st
%Cpu1  : 24.4 us,  1.7 sy,  0.0 ni, 73.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 14.7 us,  1.7 sy,  0.0 ni, 83.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  2.0 sy, 98.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu4  :  3.3 us,  0.7 sy,  0.0 ni, 96.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu5  :  2.0 us,  0.3 sy,  0.0 ni, 97.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu6  :  2.3 us,  0.3 sy,  0.0 ni, 97.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu7  :  0.7 us,  0.3 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   7199160 total,  5764884 used,  1434276 free,   172496 buffers
KiB Swap:        0 total,        0 used,        0 free,  5161520 cached

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND
16659 root      39  19  8612  632  440 R 100.3  0.0   0:12.94 /bin/gzip
 2343 nginx     20   0 60976  14m 1952 S  23.2  0.2 112:48.51 nginx: worker process
 2328 nginx     20   0 61940  15m 1952 S  19.9  0.2 111:49.12 nginx: worker process
 2322 nginx     20   0 61888  15m 1952 S  19.3  0.2 113:44.95 nginx: worker process
 2324 nginx     20   0 61384  14m 1952 S  16.6  0.2 113:30.52 nginx: worker process
 2340 nginx     20   0 61528  14m 1952 S  11.0  0.2 114:02.36 nginx: worker process
 ...

上記の出力例は結構おもしろいタイミングを示していて、下のプロセスリストをみると、 /bin/gzip がCPU 100%使いきっています。 これはlogrotateがアクセスログを圧縮している様子を表しています。 上段のCPU利用率欄をみると、Cpu3 が 0.0 idとなっています。 id は idle の略であり、 id が 0% ということはCpu3を使いきっているということです。これらの状況から gzip プロセスが Cpu3 を使いきっているということが推測できます。

CPU利用率欄には他にも、us, sy、ni、wa、hi、si、stがあります。(カーネルバージョンにより多少異なります) これらは、CPU利用率の内訳を示しています。よくみるのは、us、sy、waの3つですね。

  • us(user): OSのユーザランドにおいて消費されたCPU利用の割合。userが高いということは、アプリケーション(上記の場合nginx)の通常の処理にCPU処理時間を要していることです。
  • sy(system): OSのカーネルランドにおいて消費されたCPU利用の割合。systemが高い場合は、OSのリソース(ファイルディスクリプタやポートなど)を使いきっている可能性があります。カーネルのパラメータチューニングにより、負荷を下げることができるかもしれません。fork 回数が多いなど、負荷の高いシステムコールをアプリケーションが高頻度で発行している可能性があります。straceでより詳細に調査できます。
  • wa(iowait): ディスクI/Oに消費されたCPU利用の割合。iowaitが高い場合は、次の iostat でディスクI/O状況をみましょう。

基本は各CPUコアのidleをざっと眺めて、idle が 0 に近いコアがないかを確認し、次に iowait をみてディスクI/Oが支配的でないかを確認し、user や system をみます。

ちなみに、自分は si (softirq) についてこだわりが強くて、 Linuxでロードバランサやキャッシュサーバをマルチコアスケールさせるためのカーネルチューニング - ゆううきブログ のような記事を以前書いています。

iostat

ディスクI/O状況を確認できます。-d でインターバルを指定できます。だいたい5秒にしています。ファイルシステムのバッファフラッシュによるバーストがあり、ゆらぎが大きいので、小さくしすぎないことが重要かもしれません。 -x で表示する情報を拡張できます。

$ iostat -dx 5
Linux 3.10.23 (blogdb17.host.h)     02/18/16    _x86_64_    (16 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda              0.00     3.09    0.01    3.25     0.13    36.27    22.37     0.00    1.45    1.59    1.45   0.52   0.17
xvdb              0.00     0.00    0.00    0.00     0.00     0.00     7.99     0.00    0.07    0.07    0.00   0.07   0.00
xvdf              0.01     7.34   49.36   33.05   841.71   676.03    36.83     0.09    8.08    2.68   16.13   0.58   4.80

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda              0.00     3.20    0.40    2.80     2.40    30.40    20.50     0.00    0.25    0.00    0.29   0.25   0.08
xvdb              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
xvdf              0.00     5.00  519.80    4.00  8316.80    96.00    32.12     0.32    0.61    0.60    1.40   0.52  27.36

iostat コマンドは癖があり、1度目の出力はディスクデバイスが有効になってから現在まのの累積値になります。 現在の状況を知る場合は、2度目以降の出力をみます。

自分の場合、IOPS (r/s、w/s)と%utilに着目することが多いです。 上記の場合、r/s が519と高めで、%util が 27%なので、そこそこディスクの読み出し負荷が高いことがわかります。

netstat / ss

netstat はネットワークに関するさまざまな情報をみれます。 TCPの通信状況をみるのによく使っています。

-t でTCPの接続情報を表示し、 -n で名前解決せずIPアドレスで表示します。-n がないと連続して名前解決が走る可能性があり、接続が大量な状況だとつまって表示が遅いということがありえます。(-n なしでも問題ないことも多いので難しい)

-l でLISTENしているポートの一覧をみれます。下記の場合、LISTENしているのは 2812, 5666, 3306, 53549, 111, 49394, 22, 25 ですね。

$ netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:2812            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:5666            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:53549           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:49394           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:25              0.0.0.0:*               LISTEN
tcp6       0      0 :::54282                :::*                    LISTEN
tcp6       0      0 :::111                  :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 :::53302                :::*                    LISTEN
tcp6       0      0 :::25                   :::*                    LISTEN

TCPの全部のステートをみるには -a を指定します。 -o はTCP接続のタイマー情報、 -pはプロセス名の表示 (-p には root権限が必要) ができます。

$ sudo netstat -tanop
...
tcp        0      0 10.0.0.10:3306         10.0.0.11:54321        ESTABLISHED 38830/mysqld keepalive (7190.69/0/0)
tcp        0      0 10.0.0.10:3306         10.0.0.12:39150       ESTABLISHED 38830/mysqld keepalive (7157.92/0/0)
tcp        0      0 10.0.0.10:3306         10.0.0.13:49036         TIME_WAIT  38830/mysqld timewait (46.03/0/0)
tcp        0      0 10.0.0.10:3306         10.0.0.14:41064         ESTABLISHED 38830/mysqld keepalive (7223.46/0/0)
tcp        0      0 10.0.0.10:3306         10.0.0.15:34839        ESTABLISHED 38830/mysqld keepalive (7157.92/0/0)
...

一番、よくみるのは、このホストはどのホストから接続されているかです。 なぜか本番サーバなのに、ステージングサーバから接続されているというようなことがわかったりすることもあります。

他にも、単にやたらと接続が多いなとかざっくりした見方もします。そのときに、TCPのステートでESTABLISHED以外がやたらと多くないかなどをみたりします。

netstat は非推奨なので、ss コマンドをつかったほうがよいようです。 ただし、自分の場合、ss コマンドの出力の余白の取り方があまり好きではないので、netstat をつかっています。

ログ調査

いうまでもなくログ調査は重要です。 ログをみるためには、OSや、各種ミドルウェア、アプリケーションが吐くログがどこに履かれているのかを知る必要があります。

基本的には /var/log 以下を眺めてそれっぽいものをみつけて tail してみます。

/var/log/messages or /var/log/syslog

まずはここを見ましょう。カーネルやOSの標準的なプロセスのログをみることができます。他にもcron実行するコマンドの標準出力や標準エラー出力を明示的に logger にパイプしている場合などはここにログが流れます。

/var/log/secure

ssh 接続の情報がみれます。他の人がssh接続しているのに接続できない場合、ここに吐かれているログをみると原因がわかることがあります。

/var/log/cron

cronが実行されたかどうかがわかります。ただし、cronが実行したコマンドの標準出力または標準エラー出力が /var/log/cron に出力されるわけではなく、あくまでcronのスケジューラが動いたかどうかがわかるだけです。cronが実行したコマンドの標準出力または標準エラー出力はどこに出力されるか決まっているわけではなく、crontab内でloggerコマンドにパイプしたり、任意のログファイルにリダイレクトしたりすることになります。

/var/log/nginx, /var/log/httpd, /var/log/mysql

ミドルウェアのログは /var/log/{ミドルウェア名} 以下にあることが多いです。 特によくみるのはリバースプロキシのアクセスログやDBのスロークエリログですね。

自分が開発しているシステムのログの位置は確認しておいたほうがよいです。

/etc

/var/log 以下にログを吐くというのは強制力があるものではないので、ログがどこにあるのか全くわからんということがあります。

ログファイルのパスは設定ファイルに書かれていることもあります。 設定ファイルは /etc 以下にあることが多いので、 /etc/{ミドルウェア名} あたりをみて、設定ファイルの中身を cat してログファイルのファイルパスがないかみてみましょう。

lsof

/etcをみてもわからんというときは最終手段で、lsofを使います。 ps や top でログをみたいプロセスのプロセスIDを調べて、lsof -p <pid> を打ちます。 そのプロセスが開いたファイルディスクリプタ情報がみえるので、ログを書き込むためにファイルを開いていれば、出力からログのファイルパスがわかります。

他には例えば、daemontools を使っていると、 /service 、もしくは /etc/service 以下に multilog が吐かれているなど、使用しているスーパーバイザによっては、特殊なディレクトリを使っている可能性があります。

関連

あとがき

ここに紹介した内容はあくまでy_uukiが普段やっていることであり、どんな状況でも通用するようなベストプラクティスではありません。 むしろ、自分はこうやってるとか、こっちのほうが便利だということがあれば教えてほしいです。

オペレーションエンジニアは息を吸うように当たり前にやっているのに、意外とアプリケーションエンジニアはそれを知らない、ということはよくあることだと思います。オペレーションエンジニア同士でも、基本的過ぎてノウハウを共有していなかったということもあるのではでしょうか。

知ってる人は今さら話題にするのもなとかみんな知ってるでしょとか思いがちです。しかし、これだけ毎日のように新しい話題がでてくると、基本ではあっても、意外と見落としているノウハウは結構あると思います。見落としていた話題にキャッチアップできるように、新卒研修の時期にあわせて定期的に話題になるとよいですね。

昨今は、No SSHと呼ばれるように、サーバにSSHしないという前提で、インフラを構築する発想があります。 少なくとも現段階では、No SSHは一切サーバにSSH(ログイン)しないという意味ではなく、あくまでサーバ投入や退役など、通常のオペレーションをするときにSSHしないという意味だと捉えています。 もしくは、Herokuのユーザになり、サーバ側の問題はなるべくPaaS事業者に任せるということかもしれません。

したがって、サーバにログインして問題調査するという形はまだしばらくは続くでしょう。

異常を発見した場合、より深く問題に踏み込むために、straceやgdbなどを駆使するという先のオペレーションの話もあります。そのうち書きたいと思います。

Keepalivedのシンタックスチェッカ「gokc」を作った

Go Keepalived

Keepalivedのシンタックスチェッカ「gokc」をGo言語で書きました。

github.com

執筆時点でのKeepalived最新版であるバージョン1.2.19まで対応していることと、include文に対応していることがポイントです。

使い方

https://github.com/yuuki/gokc/releases からバイナリをダウンロードします。OSXでHomebrewを使っていれば、

$ brew tap yuuki/gokc
$ brew install gokc

でインストールできます。

gokcコマンドを提供しており、-f オプションで設定ファイルのパスを指定するだけです。

gokc -f /path/to/keepalived.conf
gokc: the configuration file /etc/keepalived/keepalived.conf syntax is ok

シンタックスエラーのある設定ファイルを読み込むと、以下のようなエラーで怒られて、exit code 1で終了します。

gokc -f /path/to/invalid_keepalived.conf
./keepalived/doc/samples/keepalived.conf.track_interface:7:14: syntax error: unexpected STRING

なぜ作ったか

KeepalivedはIPVSによるロードバランシングと、VRRPによる冗長化を実現するためのソフトウェアです。 KeepalivedはWeb業界で10年前から使われており、はてなでは定番のソフトウェアです。 社内の多くのシステムで導入されており、今なお現役で活躍しています。

KeepalivedはNginxやHAProxy同様に、独自の構文を用いた設定ファイルをもちます。

  • しかし、Keepalived本体は構文チェックをうまくやってくれず、誤った構文で設定をreloadさせると、正常に動作しなくなることがありました。

そのため、これまでHaskellで書かれた kc というツールを使って、シンタックスチェックしていました。 initスクリプトのreloadで、kcによるシンタックスチェックに失敗するとreloadは即中断されるようになっています。

ところが、Haskellを書けるメンバーがいないので、メンテナンスができず、Keepalivedの新機能に対応できていないという問題がありました。 (Haskell自体がこのようなものを書くのに向いているとは理解しているつもりです。) さらに、kcについてはビルドを成功させるのが難しいというのもありました。Re: keepalived.confのシンタックスチェックツール「keepalived-check」「haskell-keepalived 」が凄い! - maoeのブログ

さすがに、Keepalivedの新しい機能を使うためだけに、Haskellを学ぶモチベーションがわかなかったので、Go言語とyaccで新規にgokcを作りました。 Go言語はインフラエンジニアにとって馴染みやすい言語だと思っています。 yaccは構文解析の伝統的なツールなので、情報系の大学で習っていたりすることもあります(僕は習わなかったけど、概念は習った)。

ちなみに、C言語+flex+yacc版のシンタックスチェッカである ftp://ftp.artech.se/pub/keepalived/ というものがあります。 新しい構文には対応しているのですが、include未対応だったり、動いてない部分が結構あるので、参考にしつつも一から作りました。

実装

シンタックスのチェックだけであれば、コンパイラのフェーズのうち、字句解析と簡単な構文解析だけで済みました。 「簡単な」と言ったのは、構文解析フェーズで、抽象構文木を作らなくて済んだということです。

一般に字句解析器は、自分で書くか、Flexのような字句解析器の自動生成ツールを使います。 後者の実装として、自分の知る限り、Go言語にはgolexnex があります。

ただし、include文のような字句解析をそこそこ複雑にする構文があるため、柔軟に書けたほうがよかろうということで自分で書くことにしました。 といっても、スキャナ部分はGo言語自体のスキャナであるtext/scannerを流用しました。 Go言語用のスキャナですが、多少カスタマイズできる柔軟性があるので、ユーザ定義の言語の字句解析器として利用できます。 Rational Number Calculator in Go を参照。

構文解析にはパーサジェネレータであるyaccを使いました。 yaccのGo版は標準でgo tool yaccがあります。 goyaccについて詳しくは、goyaccで構文解析を行う - Qiitaを参照してください。

多少面倒だったのはinclude文の対応です。 include対応とはつまり、字句解析器において、別の設定ファイルを開いて、また元の設定ファイルに戻るというコンテキストの切り替えをしつつ、トークンを呼び出し元の構文解析器に返すことが求められます。

字句解析器から構文解析器へトークンを渡す構造をどうするかが問題でした。 逐次的にトークンを構文解析器へ返すのを諦めて、一旦末尾まで字句解析した結果をメモリにすべてのせて、構文解析器から順に読ませるみたいなこともできました。

それでもよかったんですが、Rob Pikeの Lexical Scanning in Go の資料に、goroutineとchannelを利用して、字句解析器を作る方法が書かれており、この手法を部分的に真似てみました。

具体的には、字句解析を行うgoroutineと、構文解析を行うgoroutine(メインのgo routine)が2つがあり、字句解析goroutineが構文解析goroutineにemitetr channelを通じて、トークンを受け渡すという構造にして解決しました。 channelをキューとして扱うようなイメージです。

include文のもつ複雑さに対して、そこそこシンプルに書けたような気はしています。

参考

2015年の心に残った技術エントリ

日記

1年分の自分のはてなブックマークを見直した。 およそ 2,000 URLのエントリの中から、特に感銘を受けたり、記憶に残ったエントリを紹介したい。 2015年にブクマしたというだけで、必ずしも2016年に公開されたエントリばかりではないことに注意。

エントリ

Scalable Deployments

一昨年のRubyKaigiの講演スライド。 スクリプト言語のtar ballデプロイをみたのはこれが初めてだった。 大量のアプリケーションサーバに対するsshが遅いもしくは失敗する問題を、Serfを利用したpull型デプロイにより解決しているところがすごいアイデアだと思う。

Advanced Techinic for OS upgradeing in 3 minutes

昨年のYAPC::Asiaで直接拝聴したトーク。 前述のtar ballデプロイにも触れられている。 No sshという思想を軸に、目の前のアーキテクチャを変えずに確実に自動化していくという方法論が蒙を啓くようだった。

最近は、色濃い思想をもつ飛び道具系のツールがそこら中に飛び交っている。 いきなりそれらのツールを導入しようとした結果、自分も含めて、振り回されてしまう人たちにとって、一つの道標になる。

MySQLやSSDとかの話

前編と後編でセットになっている。 2000年代のMySQL運用から10年経った今というような視点で読める。 全く他人事ではないので、わかるわかると頷きながらスライドをめくっていた。

単に10年経ってつらいという話ではない。 ハードウェアの進化にあわせた最適な構成は何かということを考えさせるスライドだった。

モバイルアプリのスレッドプールサイズの最適化

コンピュータサイエンスの知識、ここでは待ち行列理論をモバイルアプリ開発に応用している例。 システムの振る舞いをモデル化して、検証するというサイクルを回せているのはすごい。 モバイルの人ってやっぱり計算機やネットワークのことはあまり考えないだろうという思い込みがあり、いい意味で裏切られた。

性能測定道

性能測定は技芸であり、技あるところに道ありとして、性能測定道というタイトルに行き着くまでの流れに魂みたいなものを感じた。 適当にベンチーマーク回して、最終結果の数値だけみて速いとか遅いとか言ってたりするんだけど、はたして本当にそれでいいのか。 性能測定のためにはシステムのブラックボックスを理解する必要があり、性能測定が本質的に難しいということを知れるだけでも、十分な発見だと思う。

情報科学における18のメタテクニック

キャッシング、パイプライニング、投機的実行、先読みなど、コンピュータサイエンスのあらゆるレイヤで利用される普遍的なテクニックを紹介したスライド。 切り口がよい。以前、Cache Nightとかやったらおもしろいんじゃないかとか言ってたことがある。CPUのキャッシュメモリからCDNまで幅広い話題がでてきそう。こういうレイヤを横断したトピックで、利用例を集めてみるのもおもしろいかもしれない。

Webオペレーションエンジニアのアウトプットと開発力

社外へアウトプットするということの大切さを再確認したエントリ。

自分は社内のインフラチームの中で最もアウトプットしているという自負がある一方で、自分一人ではなく、チーム全体のアウトプットを増やすにはどうしたらいいか悩むことがある。 悩みの中心はたぶんアウトプットに対する過小評価を感じている。 アウトプットの目的が単にプレゼンス向上のためだけだと社内で捉えられてしまうことがあり、揶揄も込めてプレゼンスばかりあっても意味ないという話で終わってしまう。 自分も気分が乗る人だけやればよくて無理することはないというスタンスだったんだけど、これで本当にいいのかと思うようになってきている。

改めてスライドを拝見して、アウトプットすることはより質の高い仕事をするためのステップ、もしくは成長のためのステップと捉えるのがよいのかなと思うようになってきた。

はてなに入った技術者の皆さんへ

10年前のエントリなんだけど、今でも全く色あせない。 matsumotoryさんのエントリとあわせて読むとよい。

僕たちが作るものは、会社の外から評価されることによって初めて価値が生まれるのです。

アウトプットに関しては、この一言に尽きると思う。 やはり社外へのアウトプットを単にプレゼンス向上とみなすのはもったないという気持ちが強くなってきた。

シンプルでかつ最高のJavaScriptプロファイラ sjsp を作りました!

後輩のブログなんだけど、まさにお手本のようなアウトプット。 他人が利用できる形であり、社外でも評価され、なおかつ、裏では社内のサービスのユーザ体験まで向上させている。

ペパボのインターネット基盤技術研究・開発の活動

2年間の自分の仕事を振り返ってみても、基盤技術がボトルネックでサービス開発を妥協していることは少なからずある。 開発チームからの要求があったときに、それはちょっと厳しいから、この辺で妥協するかとかよく言ってる。

一方で、もし圧倒的な基盤技術が開発できれば、例えば、コストを10倍下げて、その結果ユーザが保持できるデータ量を10倍にできるかもしれない。 基盤技術の開発により、競合サービスに対してリードできないかという視点を持ち始めるきっかけになった。

これからのWebサービスは新規性のある技術を自ら研究・開発し、ググっても解決できない問題を自分たちで解決しなければ一歩リードする事ができない時代へと突入

インフラチーム改め Site Reliability Engineering (SRE) チームになりました

昨年、Site Reliability Engineeringという言葉を初めて知った。 通常、自分たちのことをインフラ部とかサーバ管理者とか運用チームとか呼んだりするんだけど、どうにも保守的というか価値を生み出す感がなかった。 はっとしたのは次の一文だ。

...SREがソースコードを追って原因を特定し、パッチを充ててリリースをすることもあるようです。 GoogleのSREの特徴として、ソフトウェアエンジニアとしての業務の比重が大きい事が挙げれます。業務時間の20-80%は開発の業務に関わっているようです。

別の記事にもSREの役割として近い内容が書かれている。

現に、コア原則の一つは SRE が運営の作業に費やせる時間を 50% のみにすることを義務付けています。彼らは、可能な限り最大限の時間をコード書きとシステム構築に費やして、業績と運営効率を改善しなくてはならないのです。

https://www.atlassian.com/ja/help-desk/site-reliability-engineering-sre

自分の仕事を振り返ってみると、運用に手間を割くことが多く、正直そんなにコードを書いているわけではない。 自分たちのことを運用チームと呼んでいたりすると、運用チームだから運用に時間を割くのは当然だと思ってしまう。 @rrreeeyyyくんがよく「運用を消したい」って言っているのとつながる。

エンジニアとしての落としどころを作る

本当にすごい人には勝てないんじゃないか、勝てないとだめなのかとか誰しも考える悩みに正面から応えたエントリ。 落としどころを作るというのは、つまるところ、自分はこれでいいのだなと思えるところを発見することなんだなと思えた。

イメージできることを実践する

技術エントリではないけれど、ことあるごとに思い出すエントリ。 他の人がやってるわけではないんだけど、なぜかイメージできるものというのは確かにある。 例えば、会社でいま存在しないんだけど、こういうポジションがあったらうまくやれそうだなとかおもしろくやれそうだとか、ポジションをイメージできたりすることがある。 このエントリを読むと、他の人がやっているかやっていないかより、自分がイメージできるものをやってみようと思える。

今明かされる! シンラ・テクノロジーのインフラへの挑戦と舞台裏

資料はおそらく公開されていないが、JTF 2015の招待講演は圧巻だった。 中身は、シンラ・テクノロジー(「オンラインゲームを支える技術」の著者である中嶋謙互さんが所属されている会社)のプロジェクトの紹介だ。 クラウドにレンダリングサーバを配備することにより、クライアントではハイスペックなマシンを不要にするアーキテクチャの話。(リモートレンダリングアーキテクチャ)

あまり話題にならなかったのが不思議だ。 GPGPUとカーネルのネットワークスタックにある程度明るくないとピンとこない内容だったかもしれない。 ネットワークレイテンシをできるだけさげるために、RDMAを使って、CPUをバイパスして、NICからGPUのメモリに直接パケットをコピーするとかそういう話。 実はオンラインゲームの基盤技術には昔から興味があったので、こういうのやってみたいなと思ったりする。

こちらのエントリにメモが書かれている。 July Tech Festa 2015 - したためなければいきのこれない

オンラインゲームを支える技術  ??壮大なプレイ空間の舞台裏 (WEB+DB PRESS plus)

オンラインゲームを支える技術  ??壮大なプレイ空間の舞台裏 (WEB+DB PRESS plus)

あとがき

id:toya さんが書かれた 2015年にブックマークしたURLでよかったものの中からブクマコメントに代えて - Really Saying Something にインスパイアされて書いてみた。

こうして振り返ると、ここに挙げたエントリの内容は、おもしろいように昨年の自分のブログの文章にも反映されているなと感じる。 何を考えて、この一年を過ごしたのかということが意外とはっきりと現れる。

他人の心に残るということは、それだけ月日がたっても色あせない何かがあるということだと思う。 今年も他人の心に残るようなアウトプットを心がけたい。

2015年も技術しかしてない

日記

今年も技術しかしてない。

やけにブログを書くことに傾倒していた。

26歳になった。

YAPCで発表した。

ISUCONに負けた。

入社2年過ぎた。

振り返ってみると、今年は技術でも仕事でもプライベートでも、ものごとやものの考え方は5年後、10年後はどうなるのか、変わらないものは何か、色褪せないものは何かを考え始めた年だった。 具体的には、例えば、単にブログを書いて、1カ月にN回書いたとかNブクマついたとか、対外発表の数をこなしてたくさん発表したねだけで終わるのではなく、その先に何があるのかを考えるといったことだ。 他には、5年後でも使っている技術はなにかとか、それを見極めるためには何を理解している必要があるのかといったこともある。 去年は若者らしくあまりそういったことは考えなかった。 たぶん、DockerとかHashicorpを使ってモダンなインフラを作るのがかっこいいと思っていた。 結局、いきなりそれらのツールを導入して、仮にメリットが1つ増えたとしてもデメリットが2つ以上増えることがわかり、技術というのはそういうものではないと悟った。 最終的にはそれらのツールの良い思想だけをいただいて、Dockerやめてchrootでいいとか言い始めることになった。 Dockerとchrootを組み合わせたシンプルなコンテナデプロイツール - ゆううきブログ

昨年の目標

2014年、技術しかしてない - ゆううきブログ

今年の目標はどうやら下記の3つだったらしい。

  • ツールを作る
  • 計算機システムの理解
  • インフラ系の若者と交流

ツールを作るというのはあんまりうまくいってない。目標にないはずのブログのアウトプットに大半を費やしていた。

ふたつ目の計算機システムの理解というのもそんなにうまくいかなかった。あまり書籍とか論文とかまとまったものを読めなかった。

インフラ系の若者とは交流成功した。大成功と言ってもよい。

wakateinfra Slackとかあって、毎日なんか会話してる。平和。

f:id:y_uuki:20151231210951p:plain

ブログの振り返り

昨年は28本のエントリを書いた。合計ブクマ数は 5,055 users、年間PVは 172,878 views だった。 今年は13本のエントリを書いた。合計ブクマ数は 5,409 users、年間PVは 198,381 views だった。 1エントリあたりの平均ブクマ数は 416 users / entry 。 去年は東京はもう古いとか書いてたけど、今年は技術しか書いていない。 昔はもっと量を書かないと、とか思ってたけど、量だけあって一ヶ月で廃れる内容を書いても自分で満足できないので、あとで振り返っても色あせないものを目指した。 自分が満足できるアウトプットかどうかが重要だと思う。 採用活動にも奇跡的にうまくつながったので、会社でそんな賞ないはずないのになぜかブログで求人賞みたいなのをいただいた。

順位 エントリ
1位 2015年Webサーバアーキテクチャ序論 - ゆううきブログ
2位 Webシステムにおけるデータベース接続アーキテクチャ概論 - ゆううきブログ
3位 はてなで大規模サービスのインフラを学んだ - ゆううきブログ
4位 Linuxでロードバランサやキャッシュサーバをマルチコアスケールさせるためのカーネルチューニング - ゆううきブログ
5位 Dockerとchrootを組み合わせたシンプルなコンテナデプロイツール - ゆううきブログ
6位 Mackerelを支える時系列データベース技術 - ゆううきブログ
7位 Ansible + Mackerel APIによる1000台規模のサーバオペレーション - ゆううきブログ
8位 パフォーマンスの観点からみるDockerの仕組みと性能検証 #dockerjp - ゆううきブログ
9位 YAPC::Asia 2015で技術ブログを書くことについて発表しました - ゆううきブログ
10位 Serverspec + Mackerel APIによるインフラテストの実運用化 - ゆううきブログ
11位 ISUCON 5予選で5位通過した話 - ゆううきブログ

発表の振り返り

対外発表は確か3件だけだったと思う。

東京へ行く度に結構疲れてしまった反省をこめて、来年はピンポイントで興味のあるカンファレンスや勉強会で発表したい。

去年の感想によると、東京に疲れてた。今年はピンポイント感あってよかった。 セッションオーナーの話などをいただいたこともあったけど、申し訳ないと思いながらお断りしたりもした。

執筆の振り返り

去年まで雑誌に寄稿とかしたことなかったけど、気づけば今年はSoftware DesignとWeb+DBで執筆することになった。

雑誌の次はいつかは単著で書籍を書いてみたい気もするけどそれは来年とかではない。

OSSの振り返り

ツール書くとか言ってあまり書けなかった。

技術以外のことは何もしてない割にはアウトプットが少ない気がする。 発表やブログのアウトプットは、去年と今年でそれなりに満足したので、来年はブログも発表もできるかぎり抑えて、もっとコード書きたい。 みんなが飲み会とか結婚とかいってのんびりしている間にコード書くというのが半分冗談の来年のテーマだ。

今年もお世話になりました。来年もよろしくお願いします。

Serverspec + Mackerel APIによるインフラテストの実運用化

Mackerel Serverspec

この記事は Mackerel Advent Calendar 2015 の24日目の記事です。 前回は、id:hitode909 による 三度の飯より監視と通知!Mackerelで自分の心拍数を監視しよう - hitode909の日記 でした。

今回は、Mackerel APIを用いてServerspecによるサーバ構成テストを実運用化した話を紹介します。 Serverspec単体では手の届かないかゆいところをMackerelでサポートするところがポイントです。 Mackerelはもちろんですが、他のサーバ管理ツールにも通用する汎用的な話になるように心がけています。

続きを読む