鱒身(Masu_mi)のブログ

知った事をメモする場所。

Golang: contextを使ってみる

contextについて調べたので試しにos.Signal を受け取るとキャンセルを実行するcontext.WithCancelBySignal()を作った。

書いてから振り返るとcontextはトランザクション単位で用いるがos.Signalはプロセス全体に関わるため概念が一致しづらい。 exec.CommandContext()SIGKILLを飛ばしてしまうので子プロセスは直ちに死ぬ。そのままでは使えず相性が悪い。 ただ作ったのでとりあえず残す。

Read more...

Golang: contextを試す

勉強したことのメモ。

contextはv1.7から標準パッケージに含まれている。 関連処理をgoroutinによって非同期に実行する事が多いGo言語では対象トランザクションに関連した処理に対して横断的な制御をするのに苦労する。 contextパッケージがインタフェースを整えてくれる。

現在は主に2つの機能を提供している。

  • トランザクションの属性情報を共有
  • タスク間の依存関係をツリーを管理(キャンセル(完了)を下流に伝搬させる)

主に、キャンセル通知の伝搬経路としてcontextを捉えると考えやすい。 キャンセル対象は何でキャンセルされず実行するのは何かを分類するとcontextの親子関係のデザインが固まると思う。

またトランザクションは複数プロセス・ホストに関わることもある。 os/execCommandContext()net/httpRequest.WithContext()などがプロセスに閉じこもらないトランザクションの挙動やキャンセル処理に貢献している。 当然だけどプロセスが異なる場合はキャンセル処理を親側が実施する事で伝達されるがcontextのインタフェースとして伝達されるわけではない。

属性情報の共有の方針は賛否両論な2通り出てくると思っている。

  • トランザクション単位の情報(request_idなど)を横断的に共有する場合にcontextに含めて持ち回る
  • http.Requestをラップしたリクエスト構造体やインプット構造体を引数としてドメインレイヤーに渡す

一般的にはinteface{}を嫌うのでデータを入れることは避けられると思われる。 なので気軽にアプリケーションに閉じ込める場合はcontextを利用するよりリクエスト構造体を利用する方が好まれると考えている。

ログ用の情報などアプリケーションと関連しない一般的な横断情報とは何かの合意が取れたり慣例が貯まれば、 ミドルウェアやフレームワークがhttp.Requestをラップせず標準ライブラリと同レベルの抽象化を維持できるためcontextに寄せた実装も少しずつ出てくると想像している。 その場合contextをフレームワークやライブラリが利用する構造体にラップすることでユーザーはinteface{}を直接触らない様に提供されるのが原則になると想像している。

どちらの方針を取るにしても、バックエンドへのクライアントなどサービス機能についてcontextとは役割が違うので入れるべきではない。

Read more...

アルゴリズム練習: Chord

分散システムを自分で設計・実装できるようになりたいので基本的な分散アルゴリズムを勉強したり実際に書いてみることにした。 教科書に従って書いていて、用語などの前提には触れずメモを残すだけなので読むの辛いと思う。

tl;dr

DHT(Distributed Hash Table)を実現する代表的なアルゴリズムであるChordを実装してみた。

DHTっていうのは構造化オーバーレイネットワークの1つで多数の分散したノード上にハッシュテーブル(set, get)を提供するシステムを指す。 Chordはそのようなサービスを提供するアルゴリズムの1つで、ノードのアドレスとデータのキーを同一のS1集合へ射影することで資源探索を行う。 またノード数Nに対してリソース提供ノードを確定するのに必要なノード数をO(logN)にするように経路表を維持している。

../../../_images/new_ring_completed.png

多数のノードがつながりリングが形成されている (ピンク: succ, 青: pred, 点線: fingers)

とりあえず実装したのはRendezvous, Location, Routingのロジック部分で実際の通信やKVSサービスは実装してない。 簡単なコードのテストは書いたが複雑な部分はシナリオを通過したノードがどのようにつながっているかdot形式で出力して可視化した。 論文の他に教科書(Distributed Computing)も参考にした。詳しい解説スライドも読みました。

Read more...

内製技術を公開するにあたって

主にソフトウェアについて社内の既存のソフトウェアに対する競合技術が社外に現れたと感じた時の判断する目安について妄想してみた。 関連して新たに社内で開発する前に検討する事も考えてみた。

ミドルウェア・プラットフォームを内製するか迷ってる

既に社外に類似サービス・ソフトウェアがあるか調査して存在しなければ内製すればいい。 要望・要件と目的を整理して検索して出てきたシステム・サービスを列挙する。 満たせている/満たせていない、をカタログ的に分類する。目的や要望・要件に変更を加えられないか検討する。 変更を加えた時のデメリットを検討する(一般化できずに社内で使いまわせないなど)。

要件や要望が類似している場合には内製根拠が必要になる。 利用に際してライセンス料・サービス利用料が大きい、検証によって要件を満たせない事を示すの2択が考えられる。 検証によって要件・要望を満たせない事が示されたら、更に提案や要望による貢献で解決できないかも確認する。 長期的にみて改善しそうでも期日に間に合わない場合で、更に内製で間に合うと判断できる場合はそれを採用する。

  • 最適化の方向が異なり改善提案は成立しない
  • アーキテクチャ的な問題により長期的に改善が見込めない
  • 要望をコントロールできない。

内製してみる

社外エコシステムを取り込みやすい様に開発する。

既に独自開発していて競合(ソフトウェア・サービス)が力を付けてきた

気づいたら早めに課題を指摘して社内技術を公開して共存できる様にする。 これがコミュニティを育てて社内技術のレガシー化を防ぎつつ開発リソースをアウトソースするのに繋がる。

公開する内容の選択肢

4つの選択肢をを考えてみた。2つ目以降は(少なくとも間接的に)インタフェース公開が含まれる。 インタフェースについてはエコシステムに貢献して強い立場を作ったり、社内技術がガラパゴス化しない様にできるかを左右するので慎重に扱いやすく外部との相性も良くなるように整理しておく必要がある。

  • 課題 + 方法(特許, 論文, 白書, 記事)
  • 課題 + 方法 + インタフェース
  • 課題 + サービス (+ インタフェース)
  • 課題 + ソフトウェア (+ インタフェース)

公開する前に、内製ソフト・プラットフォームで満たしていて社外で満たせていない要件や要望や課題について整理する。

下手なものを公開できないけど早めに貢献したい

関連する内製ソフトウェアの要望・要件から外部と共通の一般化できるばしょを確認する。 外部では満たせない項目は何に依存しているのか調査する。 一般化ができたり自然に辿り着く様な事であれば上述の4つの選択肢などを実践して貢献するのが良さそう。

どの選択肢でも、技術力や主導権を維持してエコシステムが滅びないようにコミュニケーションを測るのが大事になる。 特にソフトウェア公開ではコミュニティの運用や宣伝が必要になったりとマネジメントコストが増す可能性がある。 コアコミッタやってた経験がある人がいたら聴いてみたい、案外そんなことないのかも。

社内要件というかアプリケーション要件がべったりな場合は要件整理のチャンスと考える。 整理の後で一般化されうる部分は、外部に貢献する社外システムを取り込みメンテナンスコストを押さえるか再び検討する。

社内開発をしつつ社外に対して孤立しないための技術マネジメントってこんな感じなんだろうなって思ってる。

メモ: ZeroMQの入り口

通信の基本的な意味でZeroMQ(v4)を勉強した。

通信状況を解析する

通信内容を解析したい

wiresharkで解析するDissectorを書いてる人がいたので利用する。

通信量を追いたい

トラフィック量だけでいいのであればやってみた的な記事がコミュニティ配下にあったので参考にする。

リーディング

ZeroMQのトランスポートプロトコル(QUIC,PCC,SCTP,…)を追加したくなったと仮定してコードを読んだ。

TL;DR

手始めにzmq_bindを起点にTCPに重点を置いてコードを追った。 bindを成功させるには下をすれば良いと思われる所までは読めた(はず)。

  • プロトコルに対応付けるオブジェクトをown_tを継承して作成する
  • zmq::socket_base_t::check_protocol, zmq::socket_base_t::bindを書き換えてプロトコルを許可する
  • zmq::socket_base_t::bindの追加したコードでzmq::socket_base_t::add_endpointを呼び出す

続けてconnect, recv, send系を読んで条件を確認すればZeroMQのトランスポートレイヤ追加も夢じゃない!(はず..) recvくらいは読むかもだけど本格的に追うかは迷い。 あとIPv6周辺のコードが未だに苦手だと感じたので勉強しておきたい。

Read more...

Nmapでスクリプトが利用できる

機会があってNmapスクリプトを動かせることを知った。 しかもLuaなのでとてもカジュアル。 組み込み向けで可搬性を意識した設計のためかLuaはWiresharkなどでも使えるし良い言語だと思います。 (久しぶりに開発環境整備して遊びたい) それはさておき使ってみた。

スクリプトは–scriptオプションでスクリプトを指定して実行する。

スクリプトはLinuxであればおそらく以下に位置している。

/usr/share/nmap/nselib        # スクリプトに使われるライブラリが配置される
/usr/share/nmap/scripts       # スクリプトは${script_name}.nse として配置される
/usr/share/nmap/nse_main.lua  # スクリプトを読み込んだりするコードが書かれてる

スクリプト: broadcast-dropbox-listener

以前Wiresharkで見つけたプロトコルが飛んでいるか確認するbroadcast-dropbox-listener スクリプトがインストール済みだったため試してみた。

$ nmap --script broadcast-dropbox-listener
../../../_images/result-of-broadcast-dropbox-listener.png

他にもheartbleed(CVE-2014-0160)対策済みか確認するssl-heartbleed なども存在する。 監視とか安全性検証に使えるはず。スクリプトの書き方はNmap Scripting Engineのドキュメント を参考にする。

Golang: 文字列比較

今回の結論は文字列比較はシンプルなのが良い。

今はgo1.8beta2とかのタグが切られているけれど、今年(2016)の8月Go1.7がリリースされたこの時の改善項目にbounds check elimination(BCE)最適化が含まれている

bounds check elimination(BCE)は配列にインデックスを用いてアクセスする際に適切な範囲か確認する必要があるが、静的に判定する事で実行時の確認を極力減らす事を目的としているらしい。

サンプルコードを用いた解説記事があるので読むと分かりやすい。 同じ配列に対して同一スコープ内で以前利用した添え字以下の添え字でのアクセスが確定している時に範囲確認を省略できる(bounds check eliminatd)というもの。 で、同じ人がベンチマークを取っていた。記事内では[]intを対象にしていたけど個人的には文字列が気になった。 go test -benchの練習も兼ねて文字列でBCEのコードを試した。

繰り返すと、さほど真面目な検証はしてないけど今回の結論としては文字列比較はシンプルな比較が最速。

Read more...

Wireshark: ZeroMQを解析する

今回はZeroMQを支えるZMTPプロトコルをWiresharkでみてみる。 前回のように仮想マシン2台を立ててTCP上で PUSH/PULL する。

Read more...

Wireshark: DB-LSP-DISCが飛んでいる

Wiresharkを使ってパケットを覗いていたらDB-LSP-DISC なるプロトコルがブロードキャストされていた。

../../../_images/wireshark-db-lsp-disc.png

調べたらDropboxLAN内同期を取るプロトコルだった。 LAN内同期が不要だったので切断しておいた。本当は家のWifi接続の時だけ有効にするとかが可能だと嬉しい。

../../../_images/dropbox-setting-lansync.png

ちなみにローカルネットワークへのブロードキャスト(255.255.255.255:17500)を利用してJSONを送っていた。 ペイロードの雰囲気は下(一部を書き換えている)。

User Datagram Protocol, Src Port: 17500, Dst Port: 17500
    Source Port: 17500
    Destination Port: 17500
    Length: 149
    Checksum: 0x278a [unverified]
    [Checksum Status: Unverified]
    [Stream index: 3]
Dropbox LAN sync Discovery Protocol
    JavaScript Object Notation
        Object
            Member Key: host_int
                Number value: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
                Key: host_int
            Member Key: version
                Array
                    Number value: 2
                    Number value: 0
                Key: version
            Member Key: displayname
                String value:
                Key: displayname
            Member Key: port
                Number value: 17500
                Key: port
            Member Key: namespaces
                Array
                    Number value: xxxxxxxx
                    Number value: yyyyyyyy
                Key: namespaces

Dropboxの仕様や実装を調べている人はいるAPIも公開されているので何かしたくなった時にでも思い出してみる。

ZeroMQ: EPGMの利用失敗

PGMやEPGM上でZeroMQを利用するためにVagrantをなんやかんや頑張っていた。 しかし(E)PGMの利用は以下の様に失敗した。EPGMでの実行内容をメモしているがPGMも同様に失敗した。 仕方ないけど、これまでに調べた事と実施した対応や検証をメモする。

Read more...