Router的实现主要由两部分组成: 一个是lib/router/router.rb,主要作用和nats服务器交互,管理router表。一个是lib/router/router_uls_server.rb,主要是处理各种外部请求。
Router(lib/router/router.rb)主要通过注册事件和nats服务器交互,处理其他模块发布的信息,并统计一些运行信息。
router在setup_listeners里主要注册了两个事件:分别是“router.register”和“router.unregister”。DEA模块会向nats server发布"router.register"消息和“router.unregister"消息,这主要根据DEA的状态以及instance的态等(在分析DEA时会详细介绍)。
register
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], msg_hash[:app]) } }
当router接收到'router.register'信息时,信息结构类似于:多个uri对应一个droplet instance(host,port,tags,app)。router在router表里面注册每个uri与droplet instance的对应关系,实现方法在 def register_droplet(url, host, port, tags, app_id)里面。
在路由表对于任意一个url,可以映射到app的多个droplet实例。
unregister
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在setup_sweepers方法里面添加了几个定时器,进行一些”清扫“工作。
calc_rps
计算最近一段时间间隔的请求数(requests per second),保存在VCAP::Component.varz[:requests_per_sec]中,并计算访问最多的apps
check_registered_urls
检测超过MAX_AGE_STALE未响应的droplet实例,取消注册
这是一个基于Sinatra实现的http server。
Server接受一个GET请求,请求路由"/"。
请求的信息存放在body中,如下:
{ "host":"mytest.cloudfoundry.com", "stats":[ { "response_latency":0, "request_tags":"BAh7BjoOY29tcG9uZW50SSIUQ2xvdWRDb250cm9sbGVyBjoGRVQ=", "response_codes":{"responses_2xx":1}, "response_samples":1 } ] }
当有请求到来之后,http server首先更新state信息,然后解析出请求“mytest.cloudfoundry.com”,根据“mytest.cloudfoundry.com”,寻找对应的droplet
droplets = Router.lookup_droplet(url) # 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]
当选中一个droplet实例之后,更新实例的tags和vaz,然后返回实例的信息。
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, ULS_APP_ID => droplet[:app] || 0, }
VCAP::Component.varz[:requests] Router接收到的所有请求数目
VCAP::Component.varz[:bad_requests] Router接收到的所有bad请求数目
VCAP::Component.varz[:latency]
VCAP::Component.varz[:responses_2xx]
VCAP::Component.varz[:responses_3xx]
VCAP::Component.varz[:responses_4xx]
VCAP::Component.varz[:responses_5xx]
VCAP::Component.varz[:responses_xxx]
VCAP::Component.varz[:urls] Router注册的所有的url数目,也是整个CF实例的url数目
VCAP::Component.varz[:droplets] Router注册的所有的droplet的实例的数目
VCAP::Component.varz[:tags] = {} Router搜集的所有的tags
VCAP::Component.varz[:requests_per_sec] Router最近一个统计周期的RPS
droplets记录了所有的平台的所有的实例信息:
一个url对应一个droplet的数组。多个实例服务于同一个url。
url.downcase=>[droplet,droplet,droplet,...]
一个droplet的信息包括如下
droplet = { :host => host, :port => port, :clients => Hash.new(0), :url => url, :timestamp => Time.now, :requests => 0, :tags => tags }host:运行的主机
port:监听的端口
clients:一个统计周期内请求的客户端ip和请求数目的映射
url :监听的url
timestamp: 上一个心跳时间
requests:一个统计周期内的请求次数
tags:该droplet的tag