makotan _at_ gmail dot com

HTTPベンチマークを見ながら思うこと

注:今年感じた個人的感想です

HTTPな各種サーバを大きく分けると


純粋な非同期サーバの開発言語として有名なのはGoとNodeの2つ
色んなベンチマークで優秀な結果を残してるので最近の高トラフィックな環境でもよく使われてる感じ
特徴的なのはランタイムも非同期がベースに構成されててCPUを生かし切る為に生まれてるような言語とランタイムになってる
特にコネクション数が増えたときの安定性は抜群


純粋なブロッキングサーバは最近減ってきたけど、まだ多少残ってる感じ
各種ベンチマークでボロクソに比較されて悲しい感じになる
問題はソケットの処理のためにスレッドを立てる必要があるのでコネクション数=スレッド数になってC10K問題にキッチリぶち当たる
ただし、コネクションが少ない状態でのレスポンスの安定性は抜群だし、プログラムが凄く楽


非同期とブロッキングのハイブリッド
新しめのTomcatとか含めて純粋な非同期の前の主流な感じ
ソケットの処理そのものは非同期でやっておいて、メインの処理はブロッキングで書くみたいな感じ
特徴もやっぱり間くらいw
同時処理数+コネクション管理用スレッド=スレッド数になるので実はC10K問題はそんなに起きない


HTTPなベンチマークの特徴

  • 同時コネクション数をどのくらい処理出来るのかをひたすら試す
  • コネクションを張ってからレスポンスを受けるまでの時間の測定
  • コネクションを再利用しつつ、レスポンスを受けるまでの時間の測定
  • コネクションの再利用無しでレスポンスを受けるまでの時間の測定


この4種類くらいがあって、同時コネクション数が優秀な場合最初の1個しかやってないパターンが多い気がした
実際には実用的なコネクション数でレスポンスの良さを測定する必要があると思ってる
というのは、HTTPサーバの場合に限って言えば1台のマシンでC10Kを処理するWebサーバを作る事は世の中的に滅多に無くて、複数台使って秒間で1000reqの処理が安定して出来ていれば良いことの方が圧倒的に多いから。(CDNに逃がせる画像とかを除いて1000req/sは相当大きめの数値だと思ってる)


絶対的なコネクション数を試すベンチマークより、適当な数のコネクション数でどの程度のパフォーマンスが出るかの方が結構大事な気がする


そんなことを思った2017年もあと少し
今年は紅と白どっちが勝つんでしょう・・・

若手が平均的に優秀に感じる理由を考えてみた

最近(といっても10年以上経ってる気がする)、10代、20代のレベルが高くて40代前後のレベルが低い気がしててその理由をぼんやり考えてみた(若手を圧倒する能力を常に維持してる人も普通に居るので、これが誰にでも当てはまる常に有効な結論だと言ってるわけじゃない)

高速道路説

若手は高速道路に乗ってサクッとレベルを上げれるので優秀っていう説
おじさんたちも高速道路に乗ればさらにレベルアップするって事だよね?
高速道路は知ってる範囲でこの20年ほど常に整備されてたので40代のレベルが低く感じる理由としては弱い気がする

年齢的な限界説

40代といえば既にソフトウェアエンジニアの定年説の定年を超えてるから、後ろから高速道路に乗った人に一気に追い越されたっていう説
年齢が学習効果を低くするのは事実だけど、一般道で凄く先行してる人が高速道路に乗ってる人に数年で追いつくかなぁ〜っていう疑問は残るので、年齢的なものは他の理由も関係していそうな気がする

年代的な原因説

40代と言えば通常子育てとかに時間を取られる世代なので、後ろから技術面でショートカットして来るエンジニアに追いつかれて追い越される説
周りのエンジニアを見てると一般的にはこの可能性が凄く大きい気がする

逃げ切り希望説

20代で仕事を始めて20年ほど経って色々な仕事を経験したのでもうこのまま逃げ切りたい説
20代で覚えたことをギリギリで使いながら新しい世代を部下に持って新規の事に対して積極的にならなくてもあと20数年で定年を迎えれるし、このまま逃げ切りたい感じになってる
っていう人も一部居そうだなぁ〜って思う

若手スポンジ説

実は若手はスポンジみたいに周りにある物を吸収していく説
スポンジがスカスカの若手とスポンジに要らないもの含めていっぱい入った状態の40代とは比較することすらおかしいのではないか
時代に応じてスポンジに詰まった古い物を捨てていかない40代が居たら一瞬で若手に追い越されるのは当たり前な気がする

個人的に感じてる結論

年代的な原因説が重要な要因だとおもうけど、個人差も大きいな〜って感じるので
若手スポンジ説と逃げ切り希望説その次の大きな要因な気がした
ということで、純粋な年齢は無関係だと思ってる

だいぶ前から考えてる理想的なPC環境

用意するもの

  • 軽くて液晶が綺麗で使いやすいノートPC
  • とにかくハイスペックなマシン

とにかくハイスペックなマシンにノートPCからリモートデスクトップを使って操作する


って言う風に考えて色々探してたんだけど・・・
ハイスペックなマシンって高いな〜とw
クラウドならインスタンス起動分のお金しかかからないのになぁ〜


ハッ!(゜∇゜;)


クラウドでハイスペックなマシンを用意して軽くて液晶が綺麗で使いやすいノートPCから繋げば良いのでは!?
って思ったら、クラウドでハイスペックなマシンの選択肢はWindows(しかもサーバ)かLinuxのいずれかしかない
Windowsにするとライセンス費用分値段が上がるので理想はLinuxだなと
Linuxを他のマシンから操作するのにVNCとか使いたくないし
Xそのままが良いなぁ・・・


XRDP!?
キタ━(・∀・)━!!!! <いまここ



ということで試算してみた
Core i9/32GB メモリ/512GB SSD+3TB HDD/GTX1080Ti搭載モデルが約40万
これに対抗出来るAWSはっとg2.8xlargeかな
週に16時間ほど動かしてディスクをSSDだけ同容量にして、付きに500GほどI/Oするとして・・・月に$373で大体4万円
10ヶ月ほどでAWS費用が本体費用を上回る事が判った
電気代とか入ってないのでその辺含めても1年か・・・(その頃にはもっとハイスペックなマシンに乗り換えたくなったりしてるかな〜)
(そもそもネットワークの遅延を考えてないので微妙なのはあるけどw)


ちなみに、GPU無しでc4.4xlargeにすると$195とかなので、やることによってマシンスペック変えていけばもっと安い値段で済みそうな気がしてる
だれかやってないかな・・・(他人任せ)

エンジニアにも色んな人が居るなと思ったこの数年

だいぶ前からエンジニアの中に、新規に環境を作るのが得意な人とある程度揃った環境にコードを追加していくのが得意な人が居るなぁ〜っていうのはなんとなく気がついてた
この数年色んな現場をみてて、さらに細かい分類に成功した気がする

  • そもそもどんな開発環境が良いのかを試行錯誤する人
  • 新規に環境を構築して最初のコードを書く人
  • コードを追加していく人
  • 人のコードに最低限の手を加えて機能拡張していく人
  • ざっくりした要望から要件を作れる人
  • ある程度の要望からDB設計を含めたざっくりした設計が出来る人
  • ざっくりした設計を詳細に詰めて仕上げる人
  • 設計を守りつつ新しい機能を追加していける人
  • 設計の最小限の修正で機能を追加出来る人


個人の優劣ではなく、明確にタイプの違いがあるなぁ〜って思った
かけ離れた複数のタイプを持ってるレアな人も居るけどレアすぎて考慮出来ない気がする
タイプの違う人に違うロールを与えるとあんまりパフォーマンスが出なかったりするのはなかなか面白い
あとはこれらのタイプの違いをどうやって早期に見つけるのかが判ればProjectの困ったことが起きにくい気がする


ちなみに、個人的にはこんな感じだと思ってるので自分の中では保守系タスクは不向きな感じですw

  • そもそもどんな開発環境が良いのかを試行錯誤する人
  • 新規に環境を構築して最初のコードを書く人
  • ざっくりした要望から要件を作れる人
  • ある程度の要望からDB設計を含めたざっくりした設計が出来る人

Smalltalk, Clojure, Lispと並んでるのを見てふと・・・

Smalltalkは使ったこと無いけど、ClojureLISPは良い言語だと思ってる(という前提で)
言語とVMにある程度のエコシステムとお金を沢山出す人の中核部分にどれくらい深入りしてるかがその言語の寿命を決定すると思ってて
その点で言えば、COBOL、C、Javaの優位性は圧倒的だなぁ〜と
その次にPython,RubyとかVB(&.NET)とJavascriptが来て・・・・
逆に言えばそれ以外の言語とVMは今のところ結構辛い立場にありそうな気がするなと(という流れがあるなという感想)


お金を出す人が居ればそこに群がる人も出てくるので、能力とか言語の良さ云々とかとは別のところで人が集まる
結果としてその言語とVMでは生産性10倍とかそういうのが当たり前の世界になる
逆にそこまでお金を無駄遣い出しても惜しくないほどの所にその言語かVMが入り込んでるって証拠じゃ無いかと


ということは、お金が集まる言語には色んな人が集まって巨大なエコシステムが構築される
お金がそれほど集まらない言語には少数精鋭が集まって小さいながらも良質なエコシステムが構築される
という結構自然な流れがある気がする


巨大な物は小さい物に駆逐されていくイノベーションのジレンマの通りだとすると、
大量の人とお金が集まって巨大なエコシステムを持てば持つほど、次のステップでは良質なエコシステムを持ってる所に人とお金が集まるような流れになる
ただし、次の所に移る前に圧倒的な優位性を獲得した言語とVMは、大きすぎて潰せないのでそれを維持するためのお金も人も集まるので安定的継続(成長は無いとして)が見込める
小さいエコシステムのまま沢山のお金と人が集まらず次のエコシステムへ流れる事もあるのでゆっくり消滅の流れがありそう


ということで、結論としてClojureは良い言語だと思います。
そんなこと言いつつ、Elixirが後々流行りそうだと思ってます。
他の言語は・・・今後のエコシステム次第かなぁ〜
Rustはだいぶ期待してる
JSはさっさと他のに変わって欲しい
LISP(系列の言語)はある種のエンジニアが手を出すべき言語ような気はしてる
そんな感じ

エラーを一級市民にしたいなぁ〜とふと思ってた

ここ数年そんなことを考えてた
例外で飛ばすのも別に良いんだけど、例外が本来例外では無いことにも多用されすぎてるのが嫌だなぁ〜って某ライブラリ(?)使ってて思ってた
そこで仕様としてのエラーはプログラムの一級市民(値)として扱いたいなと。(VMレベルは例外で良いと思ってる)
そろそろそういうのを普通のプログラム言語も普通にサポートして欲しい
あの言語とかあれ使えば書けるのは判ってるんだけど、個人的に好きじゃ無い言語とかまだ安定してる気がしないライブラリとかに全力で依存したくないなぁ〜って考え中
ってことで相変わらず言語探しの旅に出てる今日この頃

といいつつ、Javaで書くときは普通に例外使ってますw

‎REST APIでロールバック的な処理を考えてみた

REST APIで困るのが複数のAPIを呼び出したときのロールバック処理
何がどう困るかというと、API-1,API-2,API-3って更新処理をするAPIがあって、API-3でエラーが出たときにAPI-1とAPI-2のロールバック処理は行えない!

これまではどうやってたか

API-1とAPI-2の呼び出し前の状態を保持して、API-3がエラーになるとAPI-1とAPI-2を呼び出し前に更新する
この問題は、呼び出し前の状態を意識的に保持する必要があるのと、最初の更新方法(追加・更新・削除)によってその逆を実行する必要がある
しかもAPI-1とAPI-2の呼び出しが両方成功しないとロールバックができたことにもならない
設計と実装に結構な負担を強いる方法なのでだいぶ辛かった(実体験)

ロールバックの実現方法

APIの呼び出し時にヘッダにTransaction-ID(以後TID)を呼び出し側が指定する
TIDが指定されてる変更系の呼び出しでは必ず呼び出し前の状態に戻せるような情報を保持する
あと、安全なロールバック手段も一緒に。
一定時間(TID指定とペアで指定することもある)過ぎたTIDに紐づく情報は破棄する(Transactionが成功したものとみなす)
呼び出し元のAPIロールバックすべき状況と判断すると、rollbackにTIDを渡して呼び出すとAPI呼び出し前の処理が無かったことになる

この方法のメリット

呼び出し元がロールバック方法をいちいち検討しなくていいので全体の設計と実装は相当楽になる
呼び出し先のAPIロールバックを任意に実装できるので適切なロールバックが可能になる
呼び出しの経路全てで同じTIDを使用すると情報をトレースできる

この方法のデメリット

呼び出し先のAPIの負担は確実に上がる(ロールバック実現についてAPI別に検討と実装が必要)
サーバの障害などでロールバックが呼び出せなかったときの対処は呼び出し元に必要
呼び出し先のAPIロールバックを受け入れてないとやっぱり面倒なまま