HostedRedmine.com has moved to the Planio platform. All logins and passwords remained the same. All users will be able to login and use Redmine just as before. *Read more...*
A little more about Router¶
Router V2 についての補足→A little more about Router V2
Routerの位置付け¶
- 実際の構成
参考: Setup SSL on cloudfoundry landscape
Routerの仕事¶
- urlへのアクセスをアプリケーション・インスタンス(ホスト:ポート)に振り分ける
- アプリケーション・インスタンスからのレスポンスをクライアントに返す
URLへのアクセスをアプリケーション・インスタンス(droplet)に振り分ける¶
(この辺りの呼び出し関係についてはプロファイラーの出力結果 ruby-prof-call-tree-Router-extracted.maff も参考にした)
◎基本的な仕組み- EventMachine.start_serverでクライアントからの接続を待ち受ける
- 引数に ClientConnection を取る
- クライアントからの接続があると, EventMachine からClientConnection#receive_dataが呼び出される
- ClientConnection#receive_data
- URLに対応するdropletsを探す
- dropletが複数ある場合は,その中から一つ選ぶ
- 選んだdroplet(のホスト:ポート)に AppConnection で接続する
- URLに対応するdropletsを探す
- URLとdropletsのmapの管理
EventMachine.start_serverでクライアントからの接続を待ち受ける¶
- (EventMachine.start_server)
↓ - https://github.com/cloudfoundry/vcap/blob/f3a7ca956a9098aef3690dc3e3d6a6a9f7e645eb/router/lib/router.rb#L115
- https://github.com/cloudfoundry/vcap/blob/f3a7ca956a9098aef3690dc3e3d6a6a9f7e645eb/router/lib/router.rb#L116
クライアントからの接続があると,EventMachineからClientConnection#receive_dataが呼び出される¶
- まずpost_initが呼び出される
- 次にreceive_dataが呼び出される
ClientConnection#receive_data¶
- HTTP::Parserインスタンスの作成
@parser = Http::Parser.new(self)
(参考: http_parser.rb ) - ヘッダーの処理
@parser << @headers
呼び出されるメソッドは Http::Parser#<<
その中で- ClientConnection#on_headers_complete
- dropletsの検索
# Lookup a Droplet unless droplets = Router.lookup_droplet(host) Router.log.debug "No droplet registered for #{host}" VCAP::Component.varz[:bad_requests] += 1 send_data(Router.notfound_redirect || ERROR_404_RESPONSE) close_connection_after_writing return end
- 接続先のdropletを一つ選ぶ
- cookieがある場合はcookieを発行したdropletを選択
# Check for session state if VCAP_COOKIE =~ headers[COOKIE_HEADER] url, host, port = Router.decrypt_session_cookie($1) Router.log.debug "Client has __VCAP_ID__ for #{url}@#{host}:#{port}" # Check host? droplets.each { |droplet| # If we already now about them just update the timestamp.. if(droplet[:host] == host && droplet[:port] == port) @droplet = droplet break; end } Router.log.debug "Client's __VCAP_ID__ is stale" unless @droplet end
- dropletをランダムに選択
# pick a random backend unless selected from above already @droplet = droplets[rand*droplets.size] unless @droplet
- cookieがある場合はcookieを発行したdropletを選択
- 選択したdropletに接続
- 既存コネクションがある場合は再利用
@bound_app_conn = @droplet[:connections].pop if (@bound_app_conn && !@bound_app_conn.error?) Router.log.debug "Reusing pooled AppConnection.." @bound_app_conn.rebind(self, @headers)
- なければ新たに接続
else host, port = @droplet[:host], @droplet[:port] @bound_app_conn = EM.connect(host, port, AppConnection, self, @headers, @droplet) end
- EventMachine#connect
上の呼び出しのself, @headers, @droplet
の3つが*args
になるbind_connect nil, nil, server, port, handler, *args, &blk
- EventMachine#bind_connect
↓klass = klass_from_handler(Connection, handler, *args) s = if port if bind_addr bind_connect_server bind_addr, bind_port.to_i, server, port else connect_server server, port end else connect_unix_server server end c = klass.new s, *args ..
- EventMachine#bind_connect
- EventMachine#connect
- 既存コネクションがある場合は再利用
- dropletsの検索
- ClientConnection#on_headers_complete
- ボディの処理
# Process left over body fragment if any process_request_body_chunk(@buf) if @parser
クライアントからのリクエストをアプリケーション(droplet)に振り分けるためにしていること¶
- urlとdropletsのマッピングの管理
- データ構造: Router@droplets
- 登録: Router#register_droplet
- 削除: Router#unregister_droplet
- 登録/削除が行われる契機
- NATSでrouter.register,router.unregisterメッセージを受け取った時
Router#setup_listeners 内NATS.subscribe('router.register') { |msg| msg_hash = Yajl::Parser.parse(msg, :symbolize_keys => true) return unless uris = msg_hash[:uris] uris.each { |uri| register_droplet(uri, msg_hash[:host], msg_hash[:port], msg_hash[:tags]) } } NATS.subscribe('router.unregister') { |msg| msg_hash = Yajl::Parser.parse(msg, :symbolize_keys => true) return unless uris = msg_hash[:uris] uris.each { |uri| unregister_droplet(uri, msg_hash[:host], msg_hash[:port]) } }
- (定期的な)チェック: Router#check_registered_ulrs
- 定期チェックの登録: Router#setup_sweeper 内
EM.add_periodic_timer(CHECK_SWEEPER) { check_registered_urls log_connection_stats }
- 定期チェックの登録: Router#setup_sweeper 内
- NATSでrouter.register,router.unregisterメッセージを受け取った時
アプリケーション・インスタンスからのレスポンスをクライアントに返す¶
(略)
Interfaces¶
HTTP¶
NATS messages¶