分享

Cloud Foundry新版router源码分析

问题导读:
1、什么是Router?
2、新版本支持sticky session,如何使用?





Cloud Foundry在几个月前改进了它的router,我们可以在新版cloudfoundry解密中看到它的介绍:

上个版本中。Router作为一个nginx脚本存在。所以的请求都必须经过Ruby代码,然后加以转发。这个设计干净利落,不过Ruby也因此转发了大量的数据,容易引起性能问题,所以下个版本中做了如下的改进。
1.jpg


新版CloudFoundry揭秘
  在新版本的设计中,他们使用Lua脚本来代替原先的Ruby脚本。而Lua脚本会对请求加以分析,转发给Ruby程序,然后Ruby程序再将分析的结果返回。这样一来,proxied request已经不再经过Ruby代码。逻辑和数据完美分离。性能和稳定性都大幅提高了。

  在前版设计中,当Router接收到请求后,会随机分配一个Droplet来处理这个请求,这种方式使得用户没有办法使用Session,因为连续的HTTP请求会被分发到不同的应用实例上处理。新版本设计中增加了对SESSION的支持,当Router发现用户的请求中带了cookie信息,它会在Cookie里暗藏一个Droplet的host,port地址。当有新的请求进来,Router通过解析Cookie得到上次的应用实例,然后尽量转发到同一台Droplet上。

那么本文就在此基础上,依据源码来做更加详细的分析。


Router工程
Router有一个独立的app目录,在vcap下面的router文件夹下。我们只需要关注两个部分:ext和lib。ext中有两个lua脚本,而lib中是ruby文件。


Nginx通过lua脚本发送lookup请求
总的来讲,Nginx通过lua脚本把lookup请求发送给由ruby代码建立的http server(这个server叫做uls server,也就是上图中的upstream locator svc),获取用户请求所指向的node的ip。那么本节主要研究Nginx如何通过lua发送这个lookup消息。

Nginx使用lua脚本是通过它的配置文件实现的。这个文件一般在:~/cloudfoundry/.deployments/devbox/deploy/nginx/nginx-0.8.54/conf/nginx.conf。我们可以看一下这个文件的内容,如果没有安装过,可以在vcap的源码的/dev_box/cookbooks/nginx/templates/defaults/ubuntu-nginx.conf.erb文件看。这个erb文件就是在chef安装cf时,填入参数,然后放到上述的conf目录下的。

那么这个文件的主要内容是:
  1. [plain] view plaincopy
  2. access_by_lua '  
  3. -- add package.path andpackage.cpath  
  4. package.path = package.path..";/root/cloudfoundry/.deployments/devbox/deploy/lua/lua-5.1.4/lib/lua/5.1/?.lua"  
  5. package.cpath = package.cpath..";/root/cloudfoundry/.deployments/devbox/deploy/lua/lua-5.1.4/lib/lua/5.1/?.so"  
  6. local uls = require ("uls")  
  7.    
  8. ngx.log(ngx.DEBUG,"monitor trigger stats syncup")  
  9.    
  10. local req = uls.generate_stats_request()  
  11.    
  12. -- generate one subrequest to uls to update stats  
  13. ngx.location.capture(  
  14. "/vcapuls", { body = req }  
  15. )  
  16. ';  
复制代码


access_by_lua就是Nginx调用lua脚本来发送请求的配置,可以看http://wiki.nginx.org/HttpLuaModule#access_by_lua学习。那么在这个代码块中,首先把lua配置好了,包括lua文件,在package.path的路径中,就是上文提到的两个lua脚本。然后local req = uls.generate_stats_request()这行代码,其实是调用lua脚本中的一个函数,产生http request。这个函数可以在uls.lua文件中找到。
至此已经基本清楚了:Nginx配置好了lua,然后调用lua产生http request,然后Nginx将这个request发送给server。其他就不详细了,具体可以自己看代码


sticky session
新版本支持sticky session,这部分可以参考lua脚本:uls.lua,其中有函数专门解析request中的session,然后将这个信息加入到lookup request中,那么ruby在回应的时候会将其考虑在内。具体可以自己看代码。

请求的格式

这里码一下这个请求的格式,这段文字在uls.lua文件中:
  1. [plain] view plaincopy
  2. Message between nginx and uls (as http body)  
  3. nginx -> uls  
  4. {  
  5. "host": api.vcap.me,  
  6. "backend_addr": 10.117.9.178:9022,  
  7. "stats": [  
  8. {  
  9. "request_tags": xxx,  
  10. "response_latency": xxx,  
  11. "response_samples": xxx,  
  12. "response_codes": {  
  13. {"responses_xxx":xxx},  
  14. {"responses_2xx":xxx}  
  15. }  
  16. },  
  17. {  
  18. "request_tags": xxx,  
  19. "response_latency": xxx,  
  20. "response_samples": xxx,  
  21. "response_codes": {  
  22. {"responses_xxx":xxx},  
  23. {"responses_2xx":xxx}  
  24. {"responses_5xx":xxx},  
  25. }  
  26. }  
  27. ]  
  28. }  
  29.    
  30. nginx <- uls{  
  31. "backend_addr": xxx,  
  32. "request_tags": xxx,  
  33. "router_ip": xxx  
  34. }
复制代码


第一部分是Nginx发出的请求格式,包括了host,tag,host就是用户发来的需要访问的url,而tag则是加密之后的参数。一个实际的例子:
  1. {"host":"api.vcap.me","stats":[{"response_latency":0,"request_tags":"BAh7BjoOY29tcG9uZW50SSIUQ2xvdWRDb250cm9sbGVyBjoGRVQ=","response_codes":{"responses_2xx":1},"response_samples":1}]}
复制代码


第二部分则是返回的response,包括了转发的ip以及tag。


Ruby端http server
现在的ruby文件主要负责建立一个http server供lua脚本查询ip,那么在router工程的lib文件中主要是/router/router_uls_server.rb文件。这个文件基于sinatra建立了一个server,而这个server在router.rb文件中被启动。而其他ruby则负责从NATS拿到其他组件的register信息,然后更新自己的router表。这部分也不是太难懂,就不展开了。

已有(1)人评论

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条