打造安全易运维的高性能Web平台朱照远(叔度)王晓哲(清无)——淘宝网Nginx定制开发实战2011-12-06大纲• 背景介绍• 前端优化• 安全增强• 典型业务模块• 运维增强• 动态脚本与数据库层1、背景介绍淘宝网的面临的技术挑战• 亚洲最大的电子商务网站,Alexa排名12• 巨大的商品量– 商品总数超过10亿– 每天在线的商品数超过5亿– 每天更新的商品数超过6000万• 巨大的访问量– 每秒钟几百个G的网络流量– 日PV超过几十亿的业务线很多淘宝网使用Nginx的过程• 2009年开始使用和探索• 2010年开始开发大量模块– 基础的– 业务的• 2011年开始– 修改Nginx的内核– Tengine项目并开源淘宝网应用Nginx的收益• 业务更加稳定– Nginx大连接数目支持非常好– Nginx本身的内存占用很少,更不会吃swap• 业务性能更高– QPS比Apache要好– 节省机器数目– 基于Nginx的模块性能往往是之前业务的数倍2、前端优化组合JavaScript和CSS文件• Yahoo!前端优化第⼀一条原则– MinimizeHTTPRequests– 减少三路握手和HTTP请求的发送次数• 淘宝CDNcombo– concat模块– 将多个JavaScript、CSS请求合并成⼀一个淘宝CDNCombo的使用• 以两个问号(??)激活combo特性• 多个文件之间用逗号(,)分开• 用⼀一个?来表示时间戳– 突破浏览器缓存• 例子=2011092320110301.js强制gzip压缩• 来自Google的最佳实践– 2009、2010年Velocity大会• 做强制gzip的原因– 代理软件、杀毒软件对Accept-Encoding头的修改或去除– 访问淘宝的请求15%没有带Accept-Encoding头强制gzip的基本原理• 如果请求中没有Accept-Encoding头或不支持gzip且没有GZ的cookie设置• 判断浏览器(User-Agent)是否支持gzip• 发送的内容中插入JavaScript脚本• 脚本请求⼀一个永远都gzip的URL• 如果gzip的内容被执行了,说明支持gzip• 设置GZ对应的cookie值,注明支持gzip3、安全增强单机安全方案• 连接数限制– 使用limit_conn模块• 访问频率限制– 加强版的limit_req模块• 白名单支持• 指定跳转页面支持• 同⼀一个location下多limit_req支持系统过载保护• 判断依据– 系统的loadavg– 内存使用(swap的比率)– QPS• sysgurad模块sysguardon;sysguard_loadload=4action=/high_load.html;sysguard_memswapratio=10%action=/mem_high.html过载保护的等待页面• 过载处理方式– 直接弹回(用户不友好,而且没有保护作用)– 返回等待页面(用户友好,有保护)• 等待页面的处理– 将用户原来的请求内容返给用户(脚本)– 定时器倒计时– 时间到了自动发起新的请求分布式防攻击系统• 应对的问题– 小型的DDoS攻击– 恶意的爬虫• 为什么单机版还不够– 单机版无法知道全局• 淘宝TMD(TaobaoMissileDefense)系统– Nginx作为防攻击系统的终端– TMDServer做策略分析– TMDConsole执行汇总和控制台TMD防攻击系统架构TMDConsoleTMDServerNginxTMD模块NginxTMD模块TMDServerNginxTMD模块NginxTMD模块4、典型业务模块Comet服务器• Nginx本身的极限测试– 单机支持200万连接以上• 淘宝消息推送系统– 部署容量60万连接/台– 实际跑到30万连接/台Comet服务器架构 集群(Nginx)LB2(LVS/NAS) 接ID/IP映射表(Cache) 控(ZooKeeper)消息推送集群消息中⼼心(MC)消息推送(HSF)⽤用 消息推送(TCP)源地址HASH登 IP⼼心跳 机器列列表⽤用 所 机器IPLB1(LVS/NAS)源地址HASH灰度发布• 逐渐放量• 方便的管理接口用户PcJboss-buy-AJboss-buy-Btair名单管理员后台应用(tradeadmin)编辑策略配置名单写入Nginx/apacheModel解析abCookie,IPURL,nickCookie写用户的abcookie策略略配置非灰度灰度是否在名单中推送到model淘宝开源分布式文件系统方案• TFS模块– 非upstream机制– RESTful接口– 简化了分布式存储方案的使用难度淘宝开源分布式K/V存储方案• Tair模块– 非upstream机制– RESTful接口• 特点– 性能很高– 灵活– 返回JSON格式给客户端5、运维增强多种日志方式• 本地和远程syslog支持• 管道支持• 抽样支持– 减少写日志的数量,避免磁盘写爆access_logsyslog:user:info:127.0.0.1:514combined;access_logpipe:/path/to/cronologcombined;access_log/path/to/filecombinedratio=0.01;Server头的伪装• 伪装$curl-I:Apache/2.2.21Date:Sun,04Dec201118:36:53GMTContent-Type:text/htmlContent-Length:205Last-Modified:Tue,01Nov201105:18:57GMTConnection:keep-aliveserver_tagApache/2.2.21;Server头的隐藏• 隐藏server_tagoff;$curl-I:Sun,04Dec201118:41:16GMTContent-Type:text/htmlContent-Length:205Last-Modified:Tue,01Nov201105:18:57GMTConnection:keep-alive主机信息调试• Tengine的footer模块• 输出效果$curl!/title/headbodybgcolor=whitetext=blackcenterh1Welcometonginx!/h1/center/body/html!--shudu-desktopSat,03Dec201109:27:47GMT--footer$host_comment;Tengine错误信息提示• 便于定位用户反馈的4xx和5xx错误server_infoon;server_adminshudu@taobao.com;worker进程和CPU亲缘性• 好处– 利用多核– 防止CPU的cache失效• 问题– 不同的硬件,CPU核数可能不同– 绑定多核的CPU亲缘性比较繁琐Tengine对于进程设置的简化• 使用对比#standardnginxworker_process8;worker_cpu_affinity0000000100000010000001000000100000010000001000000100000010000000#tengine#worker_processauto;#worker_cpu_affinityauto;Nginx命令行参数的增加• 列出已经编译的模块– nginx-m• 列出支持的指令– nginx-l• 输出配置文件的全部内容– nginx-d– 支持include的内容Nginx监控增强使用淘宝开源监控工具Tsar• tsar--nginx6、动态脚本与数据库层背景• 淘宝量子统计业务快速发展– 原架构无法满足业务需要• 量子统计页面和数据特征– 页面主体框架基本不变– 查询复杂速度慢– 结果集数据量大– 重复查询少思考• 优点– 易于理解,开发上手快• 缺点– 页面主体内容重复浪费带宽– 单机并发服务能力极为有限– 存在慢连接攻击风险– PHP代码处理大数据时速度低下方案• 更改服务模型• 静态资源CDN化• 服务侧页面组装过程移至浏览器侧演进思考• 优点– 避免带宽浪费– 减少服务端计算量– 提升并发服务能力,可抵御慢连接攻击• 缺点– 开发效率受限– PHP+FastCGI限制整体吞吐量提升方案• 要在Nginx中高效访问MySQL数据库– ngx_drizzle诞生!• 要有适用NginxI/O模型的高速脚本引擎– ngx_lua诞生!ngx_drizzle• 实现Nginx中同步非阻塞方式访问MySQL• 具备长连接、进程级可控大小连接池和负载均衡功能• 返回数据可通过ngx_rds_json/csv等模块转换为JSON/CSV格式ngx_drizzle示例http{...upstreamdbgroup{drizzle_serverhost1:3306dbname=testpassword=some_passuser=aliceprotocol=mysql;drizzle_serverhost2:3306dbname=test2password=some_passuser=bobprotocol=mysql;}...server{location/mysql{set$sqlselect*fromcats;drizzle_query$sql;drizzle_passdbgroup;rds_jsonon;}}}NginxC模块构建业务逻辑的问题• 开发效率低• 部署灵活性差但是……• 人人都喜欢脚本语言!• ngx_lua用Lua脚本构建业务逻辑!WhyLua?• 内存开销小• 运行速度快• VM可中断/重入原理• ngx_lua实现Proactor模型– 业务逻辑以自然逻辑书写– 自动获得高并发能力– 不会因I/O阻塞等待而浪费CPU资源原理• 每Nginx工作进程使用⼀一个LuaVM,工作进程内所有协程共享VM• 将NginxI/O原语封装后注入LuaVM,允许Lua代码直接访问• 每个外部请求都由⼀一个Lua协程处理,协程之间数据隔离• Lua代码调用I/O操作接口时,若该操作无法立刻完成,则打断相关协程的运行并保护上下文数据• I/O操作完成时还原相关协程上下文数据并继续运行 resolverip.to.dns.server;location/http_client{internal;proxy_pass$arg_url;}location/web_iconv{content_by_lua'localfrom,to,url=ngx.var.arg_f,ngx.var.arg_t,ngx.var.arg_ulocalcapture=ngx.location.capturelocaliconv=requireiconvlocalcd=iconv.new(toorutf8,fromorgbk)localres=capture(/http_client?url=..url)ifres.status==200thenlocalostr,err=cd:iconv(res.body)ngx.print(ostr)elsengx.say(erroroccured:rc=..res.status)end';}演进效果思考• 优点– 服务侧开发语