A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 xiaozuoquan 于 2019-2-26 16:25 编辑

此处可以看到,不管是图二还是图三架构,都需要Worker去进行数据推送;假设本机数据丢了可
怎么办?因此实际大部分应用不会是完全单机闭环的,而是会采用如下架构:

没数据会回源到相应的Web应用从数据源拉取原始数据进行处理。这种架构的大部分场景本机都
可以命中数据,只有很少一部分情况会回源到Web应用。
如京东的实时价格/动态服务就是采用类似架构。
3、分布式闭环
单机闭环会遇到如下两个主要问题: 1、数据不一致问题(比如没有采用主从架构导致不同
服务器数据不一致);2、遇到存储瓶颈(磁盘或者内存遇到了天花板)。
解决数据不一致的比较好的办法是采用主从或者分布式集中存储;而遇到存储瓶颈就需要进
行按照业务键进行分片,将数据分散到多台服务器。
如采用如下架构,按照尾号将内容分布到多台服务器。

即第一步先读取分布式存储(JIMDB是京东的一个分布式缓存/存储系统,类似于Redis);如果
不命中则回源到Tomcat集群(其会调用数据库、服务总线获取相关数据)来获取相关数据。可以
参考《构建需求响应式亿级商品详情页》来获取更详细的架构实现。
JIMDB集群会进行多机房主从同步,各自机房读取自己机房的从JIMDB集群,如下图

4、接入网关
接入网关也可以叫做接入层,即接收到流量的入口,在入口我们可以进行如下事情:


4.1、核心接入

Nginx会做如下事情:
1、动态负载均衡;1、普通流量走一致性哈希,提升命中率;热点流量走轮训减少单服务器
压力;2、根据请求特征将流量分配到不同分组并限流(爬虫、或者流量大的IP);3、动态流
量(动态增加upstream或者减少upstream或者动态负载均衡)可以使用balancer_by_lua或者微博
开源的upsync;
2、防DDOS攻击限流:可以将请求日志推送到实时计算集群,然后将需要限流的IP推送到核
心Nginx进行限流;
3、非法请求过滤:比如应该有Referer却没有,或者应该带着Cookie却没有Cookie;
4、请求聚合:比如请求的是http://c.3.cn/proxy?methods=a,b,c,核心接入Nginx会在服务端
把Nginx并发的请求并把结果聚合然后一次性吐出;
5、请求头过滤:有些业务是不需要请求头的,因此可以在往业务Nginx转发时把这些数据过
滤掉;
6、缓存服务:使用Nginx Proxy Cache实现内容页面的缓存;
4.2、业务Nginx会做如下事情:
1、缓存:对于读服务会使用大量的缓存来提升性能,我们在设计时主要有如下缓存应用:首
先读取Nginx本地缓存 Shared Dict或者Nginx Proxy Cache,如果有直接返回内容给用户;如果本
地缓存不命中,则会读取分布式缓存如Redis,如果有直接返回;如果还是不命中则回源
到Tomcat应用读取DB或调用服务获取数据。另外我们会按照维度进行数据的缓存。
2、业务逻辑:我们会进行一些数据校验/过滤逻辑前置(如商品ID必须是数字)、业务逻辑
前置(获取原子数据,然后在Nginx上写业务逻辑)。3、细粒度限流:按照接口特征和接口吞吐量来实现动态限流,比如后端服务快扛不住了,那
我们就需要进行限流,被限流的请求作为降级请求处理;通过lua-resty-limit-traffic可以通过编程实
现更灵活的降级逻辑,如根据用户、根据URL等等各种规则,如降级了是让用户请求等待(比
如sleep 100ms,这样用户请求就慢下来了,但是服务还是可用)还是返回降级内容。
4、降级:降级主要有两种:主动降级和被动降级;如请求量太大扛不住了,那我们需要主动
降级;如后端挂了或者被限流了或者后端超时了,那我们需要被动降级。降级方案可以是:1、返
回默认数据如库存默认有货;2、返回静态页如预先生成的静态页;3、部分用户降级,告诉部分
用户等待下再操作;4、直接降级,服务没数据,比如商品页面的规格参数不展示;5、只降级回
源服务,即可以读取缓存的数据返回,实现部分可用,但是不会回源处理;
5、AB测试/灰度发布:比如要上一个新的接口,可以通过在业务Nginx通过Lua写复杂的业务
规则实现不同的人看到不同的版本。
6、服务质量监控:我们可以记录请求响应时间、缓存响应时间、反向代理服务响应时间来详
细了解到底哪块服务慢了;另外记录非200状态码错误来了解服务的可用率。
京东的交易大Nginx节点、无线部门正在开发的无线Nginx网关、和单品页统一服务都是接入
网关的实践,而单品页统一服务架构可以参考《京东商品详情页服务闭环实践》。
整体处理过程和普通Web应用没什么区别:首先接收请求并进行解析;然后读取JIMDB集群数据
、如果没有则回源到Tomcat获取;然后进行业务逻辑处理;渲染模板;将响应内容返回给用户。
三、如何使用Nginx+Lua开发Web应用
开发一个Web应用我们需要从项目搭建、功能开发、项目部署几个层面完成。
3.1、项目搭建
整个项目结构从启停脚本、配置文件、公共组件、业务代码、模板代码几块进行划分。
1、启停脚本
启停脚本放在项目目录/export/App/nginx-app/bin/下。
start.sh是启动和更新脚本,即如果nginx没有启动则启动起来,否则reload:
stop.sh是停止Nginx脚本:
2、配置文件
配置文件放在/export/App/nginx-app/config目录下,包括了nginx.conf配置文件、nginx项目配
置文件和资源配置文件。
nginx.confg配置文件
对于nginx.conf会进行一些通用的配置,如工作进程数、超时时间、压缩、日志格式、反向代
理等相关配置;另外需要指定如下配置:
lua_package_path、lua_package_cpath指定我们依赖的通用Lua库从哪里加载;
include /export/App/nginx-app/config/domains/*:用于加载server相关的配置,此处通过*可
以在一个nginx下指定多个server配置;
init_by_lua_file “/export/App/nginx-app/lua/init.lua”:执行项目的一些初始化配置,比如加载
配置文件。
nginx项目配置文件
/export/App/nginx-app/config/domains/nginx_product.conf用于配置当前web应用的一
些server相关的配置:
我们需要指定如upstream、共享字典配置、server配置、模板文件从哪加载、url映射,比如
我们访问http://item.jd.com/1856584.html将交给/export/App/nginx-app/lua/product_controller.lua
处理;也就是说我们项目的入口就有了。
资源配置文件resources.properties包含了我们的一些比如开关的配置、缓存服务器地址的配
置等等。
3、业务代码
/export/App/nginx-app/lua/目录里存放了我们的lua业务代码,init.lua用于读取
如resources.properties来进行一些项目初始化;product_controller.lua可以看成Java Web中
的Servlet,接收、处理、响应用户请求。
4、模板
模板文件放在/export/App/nginx-app/template/目录下,使用相应的模板引擎进行编写页面
模板,然后渲染输出。
5、公共Lua库
存放了一些如redis、template等相关的公共Lua库,还有一些我们项目中通用的工具库
如product_util.lua。
到此一个简单的项目的结构就介绍完了,对于开发一个项目来说还会牵扯到分模块等工作,
不过对于我们这种Lua应用来说,建议不要过度抽象,尽量小巧即可。
3.2、功能开发
接下来就需要使用相应的API来实现我们的业务了,比如product_controller.lua:
开发完成后将项目部署到测试环境,执行start.sh启动nginx然后进行测试。
详细的开发过程和API的使用,请参考《跟我学Nginx+Lua开发》。此处不做具体编码实现。
参考源码:Nginx+Lua(OpenResty) HelloWorld
四、基于Nginx+Lua的常用功能总结
到此我们对于Nginx开发已经有了一个整体的认识,对于Nginx粘合Lua来开发应用可以说是
一把锋利的瑞士军刀,可以帮我们很容易的解决很多问题,可以开发Web应用、接入网关、API
网关、消息推送、日志采集等应用,不过个人认为适合开发业务逻辑单一、核心代码行数较少的
应用,不适合业务逻辑复杂、功能繁多的业务型或者企业级应用;最后我们总结下基
于Nginx+Lua的常用架构模式中一些常见实践和场景:
动态负载均衡;
防火墙(DDOS、IP/URL/UserAgent/Referer黑名单、防盗链等);
限流;
降级;
AB测试/灰度发布;
多级缓存模式;
服务端请求聚合;
服务质量监控。
一些问题
1、在开发nginx应用时使用UTF-8编码可以减去很多麻烦;
2、GBK转码解码时使用GB18030,否则一些特殊字符会出现乱码;
3、cjson库对于如\uab1这种错误的unicode转码会失败,可以使用纯Lua编写的dkjson;
4、社区版nginx不支持upstream的域名动态解析;可以考虑proxy_pass
http://p.3.local/prices/mgets$is_args$args,然后配合resolver来实现;或者在lua中进行http调用
;如果DNS遇到性能瓶颈可以考虑在本机部署如dnsmasq来缓存;或者考虑使用balancer_by_lua
功能实现动态upstream;
5、为响应添加处理服务器IP的响应头,方便定位问题;
6、根据业务设置合理的超时时间;
7、走CDN的业务当发生错误时返回的500/503/302/301等非正常响应不要设置缓存。
五、参考文资料
深入 Nginx:我们是如何为性能和规模做设计的Nginx变量漫谈/配置指令的执行顺序ngx_lua
文档OpenResty最佳实践跟我学Nginx+Lua开发构建需求响应式亿级商品详情页京东商品详情页
服务闭环实践Upsync:微博开源基于Nginx容器动态流量管理方案










7.PNG (39.5 KB, 下载次数: 37)

7.PNG

1 个回复

倒序浏览
感谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马