Upload
masashi-umezawa
View
100
Download
0
Embed Size (px)
Citation preview
NanoStrandSmalltalkで分散ネットワーキング
第77回Smalltalk勉強会
合同会社ソフトウメヤ 梅澤真史
NanoStrandとは??● nanomsgのラッパー
● 気軽に高速なネットワークシステムが組めるよう
にするためのライブラリ
● Smalltalk間はもちろん他言語とのやりとりもス
ムーズに
● https://github.com/mumez/NanoStrand
nanomsgのこと
● 一言でいうと、Mini ZeroMQ (in C)● マルチプラットフォーム
● 様々な通信パターン(Scalability Protocol)を提供
○ PUSH/PULL, REQ/REP, PUB/SUB, PAIR, SURVEY, BUS ● マルチトランスポート
○ TCPのみならずIPC、INPROCも
● 豊富な言語バインディング
○ http://nanomsg.org/documentation.html
NanoStrandの構成
● NanoStrand-FFI○ FFIでnanomsg APIを呼ぶ部分
■ nanomsgのAPIをほぼそのまま使っている
■ NativeBoost版のみ (NanoStrand-NativeBoost-FFI)● Legacy FFI版を作るとSqueakやCuisでも利用可能になる
● DLLCC版だとVisualWorks
● NanoStrand-Core○ 上記FFI部を使いOO的なAPIを提供する
■ NnSocket(とそのサブクラス群)
インストール(1)● nanomsgのビルド
○ 32bitのCog VMを使う場合、32bit指定でコンパイル
○ Windowsの場合は32, 64bit用が両方できるので楽
● ビルドした共有ライブラリ(libnanomsg)をVMのディレクトリに
コピー
CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 ./configure
インストール(2)● ConfigurationOfNanoStrandのロード
● 共有ライブラリを置いていないと定数初期化に失敗する
○ NnNbNanoMessageConstantsプールに値が入らない ○ 失敗した場合、ライブラリを置いて
”NnNbNanoMessageConstants initialize”すること
Gofer new url: 'http://smalltalkhub.com/mc/MasashiUmezawa/NanoStrand/main'; package: 'ConfigurationOfNanoStrand'; load.(Smalltalk at: #ConfigurationOfNanoStrand) load
例: PULL/PUSHを書いてみる(1)
"Setup PULL socket"sock1 := NnPullSocket withBind: 'tcp://*:5575'.sock1 onReceiveReady: [:sock | Transcript cr; show: '#PULL: ', sock receive asString].
"Setup PUSH socket"sock2 := NnPushSocket withConnect: 'tcp://127.0.0.1:5575'.sock2 onSendReady: [:sock | sock send: '#PUSH: ', Time now asString].
● パイプラインな処理● NnPullSocketで受信、NnPushSocketで送信
例: PULL/PUSHを書いてみる(2)
"Start a Poller for multiplexing"
poller := NnPoller startWithSockets: {sock1. sock2}.
● NnPollerでポーリング● 異なるプロトコル、エンドポイントのSocketをまとめて登録できる● 適切なタイミングで、onReceiveReady:, onSendReady:のコールバックが呼
び出される
例: PULL/PUSHを書いてみる(3)
1 seconds wait. "The process ends after a second"
poller stopAndCloseSockets.
● stopAndCloseSocketsでNnPollerを止める
● 実際にはensure:で確実に止めるようにしたほうが良い
結果
● Transcriptに表示させなければ20000qpsほど捌ける
例: PUB/SUBで他言語との連携 (1)
# PUSHのクライアント起動。"HelloWorld"を1秒ごとに送る
$ nanocat --push --connect tcp://127.0.0.1:5585 --
data HelloWorld -i 1
● クライアント側をnanocatに○ Cで書かれたnanomsgの公式クライアント。テストに便利。
例: PUB/SUBで他言語との連携 (2)
# SUBのクライアント起動。全てのイベントを受け付ける
$ nanocat --sub --connect tcp://127.0.0.1:5586 -A
● PUSHの他、SUB役のクライアントを2つ起動
# SUBのクライアント起動。"Evt:Rem0"イベントを受け付ける
$ nanocat --sub --connect tcp://127.0.0.1:5586 --subscribe Evt:Rem0 -A
例: PUB/SUBで他言語との連携 (3)● サーバ側はPharo
○ PULLで受け取ったメッセージの数を10で割った余り(rem)を
計算
○ 余りが0または5のときイベントとしてPUBLISHする
例: PUB/SUBで他言語との連携 (4)received := OrderedCollection new. "A message box"
"Setup PULL socket"sock1 := NnPullSocket withBind: 'tcp://127.0.0.1:5585'.sock1 onReceiveReady: [:sock | | rec | rec := (sock receiveFor: 200 timeoutDo: ['']) asString. rec ifNotEmpty: [ received add: rec. "Stock the received message" Transcript cr; show: 'Received:', rec, ':', Time now printString].].
例: PUB/SUBで他言語との連携 (5)"Setup PUB socket"sock2 := NnPubSocket withBind: 'tcp://127.0.0.1:5586'.sock2 onSendReady: [:sock | |rem | rem := received size rem: 10. "10で割った余りを出す" "余りが0か5の時、イベントとして送る" rem = 0 ifTrue: [sock send: 'Evt:Rem0:', Time now printString]. rem = 5 ifTrue: [sock send: 'Evt:Rem5:', Time now printString].].
例: PUB/SUBで他言語との連携 (6)
poller := NnPoller new.poller startWithSockets: {sock1. sock2}.30 seconds wait.poller stopAndCloseSockets.
● 30秒ほどポーリングして終了させる
○ 実際にはensure:を使ってstopさせること
今後は?● Smalltalk-Smalltalk間
○ FFI部を充実させ、Squeak, CuisやVWに展開
○ シリアライザとしてはMessagePackや StOMPを使える
● 他言語間
○ Node.jsやVert.xなどとつなぐと広がりがありそう
NanoStrand-RPC● RPCのI/Fを提供し便利に使えるようにする
○ ZeroMQに対するZeroRPC的な位置づけ
■ http://www.zerorpc.io
● 同期、非同期、oneway(送りっぱなし)をサポートする予定
○ 現在は同期のみの実装
○ http://smalltalkhub.com/#!/~MasashiUmezawa/NanoStrand-RPC
例: 足し算サービスの利用 (1)● 足し算するのみの簡単なサービスクラスを用意
NnRpcSampleService class >> plus: a with: b^a+b
● #RpcSampleServiceという名前で登録しておく
NnRpcServer addService: NnRpcSampleService named: #RpcSampleService
例: 足し算サービスの利用 (2)● サーバの起動
server := NnRpcServer bind: 'tcp://127.0.0.1:6677'.server start.
● クライアントの接続、RPC呼び出し
client := NnRpcClient connect: 'tcp://127.0.0.1:6677'.client invoke: #RpcSampleService selector: #plus:with: arguments: {1. 2}. ”=> 3”
速度は?● 500回起動で80ms程度
[500 timesRepeat: [client invoke: #RpcSampleService selector: #plus:with: arguments: {1. 2}]] timeToRun. ”=> 0:00:00:00.078”
● なかなか速い
● Pure Smalltalkで書かれたRPCライブラリと比べてどうなのだろう
か?
Remote Messagint Toolkit (RMT)● 昔書いたPure SmalltalkのRPCライブラリ
○ http://smalltalkhub.com/#!/~MasashiUmezawa/RemoteMessagingToolkit
● 同期とonewayをサポート
● 某基幹系で毎日動いている
● Squeak用であったが、最近Pharo用に復活
○ シリアライザはDataStreamからFuelに置き換えた
RMTで計測
● 500回起動で1300ms程度
service := (RmtTcpService on: 4566) acceptorClass: RmtRpcAcceptor.service start.RmtRpcAcceptor receiverDictionary at: #RpcSampleService put: NnRpcSampleService.
client := RmtRpcConnector connect: 'localhost' port: 4566.[500 timesRepeat: [client invoke: #RpcSampleService selector: #plus:with: arguments: {1. 2}]] timeToRun. ”=> 0:00:00:01.33”
RPC系の予定
● 非同期のサポート
○ Futureを返し、値の取得後にコールバックされる仕組み
● ORB?
○ 非同期ベースでいまさらORBっぽいものを作りたい
○ E言語に似た感じの何か
まとめ
● NanoStrandで、気軽に高速なネットワークプログラムが書け
る
● いろいろなものとつないで楽しみましょう
● 今後の拡張にご期待ください!!