京东老司机:巧用Nginx+Lua解决数据托底大痛点

随着京东商城的发展,内部也出现了一些比较有意思的小系统小模块来解决一些业务系统的痛点,而这些小系统小模块虽说不复杂但是解决了当时的痛点。数据托底就是其中一个痛点,因为依赖系统或者其他方面的不稳定性导致用户访问页面是404或者503、或者出现天窗(页面局部内容没出来),这在一个大流量系统中是不允许的。因此就需要更健壮的系统设计来解决此问题,解决此问题的方法大家又都是类似的,因此作者就抽象了一个小模块来解决更多人的兜底问题。

大多数以读为主的系统为了提高系统的可用性,会用到各种策略来增强用户体验;其中数据托底就是其中一种策略;数据托底也可以叫做数据兜底,一般来解决如下几个问题:

  • 保证数据”永不消失”(不能开天窗),即假设依赖的服务出问题了,内容还可以展示给用户;
  • 保证数据的正确性,如果以来的服务数据不正确,可以暂时走托底数据;
  • 甚至要保证托底数据的高性能,大促时可以直接走托底数据,因为托底数据一般会通过缓存或者静态化技术完成。

实际项目中数据托底的方式也是多种多样,最简单直接的一种方式是将托底功能完全耦合在自己业务系统中,后续每开发一个系统,甚至每增加一种业务功能都要重新实现一次托底功能,并且当系统本身挂掉后托底也就无能为力了。

为了减少代码的冗余,降低代码的维护成本,可以把这块功能抽象数出来(如果业务系统是Java语言,可以以jar包的形式提供服务),然后收集出所有需要托底的业务(可以收集url、业务方法等),将其放到一个配置文件中,用worker去更新托底数据。比如京东三级列表页通过Worker去爬所有页面的内容然后静态化存储,即存储整个HTML片段,当动态列表页依赖的服务出现问题了,则直接走托底数据;假设有些页面没有爬到,可以将列表页第一页作为托底数据返回。这种形式显然要比第一种好许多(比如耦合性降低),但仍然没有足够好。首先他需要准确的知道是哪些业务要托底(明确url或方法入参),不能跨语言使用,系统本身挂掉后托底也会失败。

另一种方式是将这块功能完全独立成一个系统,并且以http的形式和目标系统通信。假设目标系统有10个页面需要做托底处理,那么我们可以将这10个页面的url告诉托底系统,托底系统可以定时的去抓取我们的页面,然后将正确的数据放到存储设备上,目标系统可以通过Nginx做判断决定如何以及何时去读取这些数据。可以看到这种方式可以做到对目标系统无侵入,也可以跨语言,并且即使目标系统挂掉只要Nginx不挂就仍然可以提供服务。但是这种方法无法动态获取要托底的资源,他在抓取托底数据时需要明确url,试想如果目标系统有几亿的页面要托底,根本没法告知托底系统;多个目标系统依赖同一个托底系统,会有单点风险。

可以看到以上方法都或多或少有些缺陷,因此为了更好地解决这些问题,本文使用aop原理基于Nginx+Lua的一种组件化托底方法。

该方法具有以下几个特性:

  1. 对目标系统零侵入
  2. 可动态拦截请求(不需要预先配置url)
  3. 可以选择数据存储设备
  4. 可以选择何时更新托底数据
  5. 可以校验托底数据
  6. 记录性能日志
  7. 配置简单

数据流向图:

具体执行过程:

1、当用户发起请求时,该组件将其拦截,然后由该组件负责向后端发起请求;在这个过程中我们可以对请求进行限流,这样就可以有效的保护后端服务器,这边我用的是Lua-resty-lock和lLua-resty-limit-traffic实现的。Lua-resty-lock是一个基于nginx的时间事件实现的非阻塞锁,使用他可以有效的防止dog-pile效应;Lua-resty-limit-traffic基于漏桶算法实现的限流组件。

2、如果回源失败则直接获取托底数据并返回;回源成功则继续向下走。

3、回源成功后需要检查数据是否正确,比如校验数据格式是否正确、是否缺少某个字段、是否缺少某个html元素等,这些校验器可以根据各自的业务自行扩展。如果校验失败则字节取托底数据并返回;校验成功则继续向下走。

4、检查是否可以更新托底数据。这里有三种策略可供选择,一种是实时更新,也就是每次请求都要更新一次托底数据;一种是每隔多长时间更新一次;最后一种是按照固定访问次数来更新。第一种策略实现简单,第二种和第三种都需要为请求打上标识。

用第二种方式解释如何实现,可以使用nginx的共享字典存储标记,伪代码如下:

5、如果不需要更新则直接将回源数据返回,如果需要更新则继续向下走,到第6步。

6、这一步会将回源的响应数据存入到托底存储中。托底存储可以是Redis、memcached、MySQL、Nginx共享缓存、本地文件等,分别使用Lua-resty-redis、Lua-resty-memcached、Lua-resty-mysql、Lua_shared_dict、popen来实现。所有的托底存储都要实现规定的动作,比如get、set、del等动作。

使用Redis存储的实现伪代码如下:

另外在请求过程、请求回源、请求托底时都会记录性能日志,以备后续分析接口性能和报警使用。

使用方法对目标系统无侵入,使用简单;但是Nginx需要集成Lua功能才能使用,如OpenResty,首先在Nginx.conf中配置如下指令:

(注:/backend/demo是/demo的回源调用uri,即此处要按照约定写回源uri)

该实现暂时没有开源出去,有兴趣的可以留言联系作者私聊。该模块是纯Lua实现,如下是该模块的简介:

网站系统在完成其业务功能外,为保证系统高可用需要做数据兜底;为保证系统的高性能,尽可能的提高系统的GPS,一般会做数据缓存。

该项目基于Nginx+lua的形式来解决数据托底和提升系统qps,并且对原系统零侵入,操作上只需要对Nginx做一些简单的配置。

该项目目前支持两种模块,分别是bottom和cache:

  • bottom模块 该模块可以保证你的网站永不消失(后端应用可以随便挂、各种挂)。
  • cache模块 可以让你系统的qps轻松过万。

可以自由选择将数据存储在不同的存储上:

  • Redis 任何支持Redis协议的存储(例如,Redis,jimdb,ssdb等)
  • dict nginx共享缓存(支持数据分片)

对于bottom模块,多种数据更新策略供选择:

  • default 默认策略是实时更新
  • time 按照一定的时间间隔更新,比如可以规定每10分钟更新一次
  • num 按照请求的次数来更新数据,比如可以规定每10次请求可以更新一次

监控、报警:

  • 基于ump监控协议实现

总结:

从以上描述可以看到, 该组件对目标系统无任何侵入性;使用简单,只需要在Nginx层做一些简单的配置;并且只要Nginx不挂,目标系统即使挂掉仍然可以提供服务。整体思路其实很简单,就是在目标系统外加一层代理,然后我们就可以在代理层做各种事情;即总体思想是遵循AOP。目前京东一些频道页、三峡项目在使用该方案。

原文发布于微信公众号 - nginx(nginx-study)

原文发表时间:2018-05-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

OpenSSH曝高危漏洞,Linux主机面临暴力破解威胁

OpenSSH软件被爆出一个简单却高危的漏洞,攻击者可以在短时间内进行数千次的登录尝试。 ? OpenSSH是最流行的Linux系统进行远程控制的软件。一般来说...

33070
来自专栏更流畅、简洁的软件开发方式

js的动态加载、缓存、更新以及复用(二)恼人的命名冲突

  上一篇发出来后得到了很多回复,在此首先感谢大家的热情捧场!有的推荐第三方框架,比如 In.js、requrieJS、sea.js、lab.js等。这个开阔了...

27880
来自专栏Java后端技术栈

记一次解决业务系统生产环境宕机问题!

Zabbix告警生产环境应用shutdown,通过堡垒机登入生产环境,查看应用容器进程,并发现没有该业务应用的相应进程,第一感觉进程在某些条件下被系统杀死了,然...

10010
来自专栏happyJared

Linux私房菜:磁盘文件系统管理及常见命令

12530
来自专栏小白课代表

软件分享 | 3DS MAX 2018安装教程

3D Studio Max,常简称为3d Max或3dsMAX,是Discreet公司开发的(后被Autodesk公司合并)基于PC系统的三维动画渲染和制作软件...

12310
来自专栏散尽浮华

Linux系统是否被植入木马的排查流程梳理

在日常繁琐的运维工作中,对linux服务器进行安全检查是一个非常重要的环节。今天,分享一下如何检查linux系统是否遭受了入侵? 一、是否入侵检查 1)检查系统...

88480
来自专栏零基础使用Django2.0.1打造在线教育网站

零基础使用Django2.0.1打造在线教育网站(十七):我要学习配置

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

23010
来自专栏腾讯大讲堂的专栏

全民K歌后台编译优化:从40分钟到30秒

编者注 全民K歌上线1年半的从0发展到1.5亿,用户越来越多,后台代码库越来越大,编译速度也与日俱慢,编译一下整个工程需要30-40分钟,如何实现秒编至关重要。...

42750
来自专栏QQ音乐技术团队的专栏

全民K歌后台编译优化:从40分钟到30秒

编者注 :全民K歌上线1年半的从0发展到1.5亿,用户越来越多,后台代码库越来越大,编译速度也与日俱慢,编译一下整个工程需要30-40分钟,如何实现秒编至关重要...

43870
来自专栏orientlu

Linux 端蓝牙调试工具

毕业大半年一直从事Ble外设开发,发现linux上可以使用bluez进行蓝牙开发,更加便捷的是,有一个python模块对bluez接口进行封装,叫bluepy,...

72930

扫码关注云+社区

领取腾讯云代金券