Project

Profile

Help

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 V2

Routerとの違いを記述。

Routerの位置付け

変更なし。

  • 実際の構成

参考: Cloud Foundry Open Tour - London

Routerの仕事

(変更なし)

  1. urlへのアクセスをアプリケーション・インスタンス(ホスト:ポート)に振り分ける
  2. アプリケーション・インスタンスからのレスポンスをクライアントに返す

URLへのアクセスをアプリケーション・インスタンス(droplet)に振り分ける

  • 上の図を少し詳細化
  • ◎そのためにしていること (ほとんど変更なし)
    • URLとdropletsのmapの管理

RouterULSServerが起動される

  • router/lib/router.rb#L119-122
        Router.server = Thin::Server.new(inet, port, RouterULSServer, :signals => false) if inet && port
        Router.local_server = Thin::Server.new(fn, RouterULSServer, :signals => false) if fn
    
        Router.server.start if Router.server
        Router.local_server.start if Router.local_server
    
  • 参考: 以前の版 (V1とする)
        Router.server = EM.start_server(inet, port, ClientConnection, false) if inet && port
        Router.local_server = EM.start_server(fn, nil, ClientConnection, true) if fn
    
    違いは,以下の2点
    • サーバーをEventMachineを利用して起動するのではなく,Thin::Serverを作って起動している点
    • サーバー上で動作するクラス(モジュール)がClientConnectionからRouterULSServerに変更されている点

クライアントから接続があると, luaのスクリプトが実行される

  • nginx.conf#L63-149 [2]
        location / {
    ..
            access_by_lua '
    ..
    
    L63-149には access_by_lua が2か所あるが,ここで扱うのは後( L119-147 )の方
    前( L80-98 )の方は,routerのstatus情報取得URLへのアクセスを扱うものなので,ここでは対象外とする
    1. RouterULSServerの'/'に対してsubrequestが発行される
                local res = ngx.location.capture(
                  "/vcapuls", { body = req }
                )
      
      このsubrequestは,見かけ上'/vcapuls'に対して発行されているが,

      実際はinternalなlocationとして 以下の定義 がなされているため,unix socket で待ち受けているRouterULSServerの'/'へのアクセスとなる
          location = /vcapuls {
            internal;
      ..
            proxy_pass http://unix:/tmp/router.sock:/;
          }
      
      [3]
      • RouterULSServerがURL(とcookie)に対応するdropletのホストとポートを(含む情報を)返す
        router/lib/router_uls_server.rb#L10-60:https://github.com/cloudfoundry/vcap/blob/a519ef2415a3f6acf899d6081635c7d3c8a0304e/router/lib/router/router_uls_server.rb#L10 で定義されている
        1. まずrequestからURLとcookieを取りだす
          router/lib/router_uls_server.rb#L16
              body = request.body.read
          

          router/lib/router_uls_server.rb#L20-25
              uls_req = JSON.parse(body, :symbolize_keys => true)
              raise ParserError if uls_req.nil? || !uls_req.is_a?(Hash)
              stats, url = uls_req[ULS_STATS_UPDATE], uls_req[ULS_HOST_QUERY]
              sticky = uls_req[ULS_STICKY_SESSION]
          
        2. URLからdropletを選択する
          router/lib/router/router_uls_server.rb#L30-41
                unless droplets = Router.lookup_droplet(url)
                  Router.log.debug "No droplet registered for #{url}" 
                  raise Sinatra::NotFound
                end
          
                # Pick a droplet based on original backend addr or pick a droplet randomly
                if sticky
                  _, host, port = Router.decrypt_session_cookie(sticky)
                  droplet = check_original_droplet(droplets, host, port)
                end
                droplet ||= droplets[rand*droplets.size]
          
        3. responseにdropletのhost:portを入れて返す
                uls_response = {
                  ULS_STICKY_SESSION => new_sticky,
                  ULS_BACKEND_ADDR => "#{droplet[:host]}:#{droplet[:port]}",
                  ULS_REQUEST_TAGS => uls_req_tags,
                  ULS_ROUTER_IP => Router.inet
                }
              end
          
              uls_response.to_json
            end
          
    2. 該dropletに対してsubrequestが発行される (ここはluaではなく,単にnginxの設定)
      nginx.conf#L137
              proxy_pass http://$backend_addr;
      
    3. (該subrequestのresponseを処理して返す)
      nginx.conf#L139-147
              # Handling response from backend servers
              header_filter_by_lua '
                -- add package.path and package.cpath
                package.path = package.path..";<%= node[:lua][:module_path] %>/?.lua" 
                package.cpath = package.cpath..";<%= node[:lua][:module_path] %>/?.so" 
                local uls = require ("uls")
      
                uls.post_process_response(ngx)
              ';
      

urlとdropletsのmapの管理


1 ちなみに'ULS'は'Upstream Location Server'の略のようだが( 根拠 ),その場合'RouterULSServer'は'Server'がダブっていることになる。上記 Open Tour London での表記は'Upstream Locator Svc'と若干異なっている。

2 このファイルは, router/ の下ではなく,リポジトリーでは vcap/dev_setup/cookbooks/nginx/templates/default/ に置かれる。理由は理解できるが,探しにくかったのもまた事実。

3 ここで交換されるデータ構造については,router/ext/nginx/uls.lua#L37-72 のコメントに記述がある。