余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

nginScript 系列:使用 nginScript 将客户端重定向到新服务器

xiyangw 2023-05-14 11:41 10 浏览 0 评论

nginScript 的一个关键优势在于它提供了读取和设置 NGINX 配置变量的能力。变量可以用于自定义路由规则。也就是说,我们可以使用 JavaScript 来实现复杂的功能,这些功能可以直接对请求的处理产生影响。

将客户端重定向到新的应用服务器

nginScript 系列:使用 nginScript 将客户端重定向到新服务器

在这篇文章里,我们将介绍如何使用 nginScript 来实现优雅的服务器间切换。我们不打算进行“一次性”的切换,而是定义了一个时间窗口,客户端在事件窗口内循序渐进地切换到新的服务器。我们可以逐渐地自动给新服务器增加流量。

我们定义了一个两个小时的时间窗口,我们希望切换就在这两个小时内完成,也就是下午 5 点到 7 点。我们预期在第一个 12 分钟内,有 10% 的客户端被重定向到新的服务器,24 分钟之后有 20%,并以此类推。下图展示了切换过程。

(点击放大图像)

在两个小时内将客户端从旧的服务器重定向到新的服务器

这种“渐进式切换”要求已经切换到新服务器的客户端不能又回到旧的服务器,也就是说,一旦一个客户端被重定向到新的服务器,那么从今以后它就一直被定向到那里。

我们会在稍后描述完整的配置,不过简单地说,NGINX 和 NGINX Plus 在处理已经被切换过来的请求时,会遵循如下规则。

  • 如果切换时间窗口还没有开始,那么请求就被重定向到旧的服务器。

  • 如果切换时间窗口已经结束,那么请求就被重定向到新的服务器。

  • 如果切换在进行当中,那么:

  1. 计算当前时间在切换时间窗口中的位置。

  2. 计算客户端 IP 地址的散列值。

  3. 计算散列值在所有散列值中的位置。

  4. 如果散列值的位置比切换时间窗口的当前位置要大,那么请求就被重定向到新的服务器,否则重定向到旧的服务器。

为 HTTP 应用配置 NGINX 和 NGINX Plus

在这个例子里,我们将使用 NGINX 和 NGINX Plus 作为一个 Web 应用服务器的反向代理,所以所有的配置都是关于 HTTP 的。

首先,我们分别为旧应用程序和新应用程序所在的服务器定义单独的 upstream 配置块。虽然切换过程是渐进式的,NGINX 和 NGINX Plus 在切换期间会一直充当负载均衡器的角色。

upstream old {
 server 10.0.0.1;
 server 10.0.0.2;
}

upstream new {
 server 10.0.0.9;
 server 10.0.0.10;
}

接下来,我们定义前端的服务,NGINX 和 NGINX Plus 通过它们将呈现内容发送给客户端。

js_include /etc/nginx/progressive_transition.js;
js_set $upstream transitionStatus; # 基于时间窗口位置返回"old|new"

server {
 listen 80;

 location / {
 set $transition_window_start "Wed, 31 Aug 2016 17:00:00 +0100";
 set $transition_window_end "Wed, 31 Aug 2016 19:00:00 +0100";

 proxy_pass http://$upstream;
 error_log /var/log/nginx/transition.log info; # 启用 nginScript 日志 
 }
}

我们使用 nginScript 来决定应该使用哪个 upstream 组,所以我们需要指定 nginScript 代码的位置。在 NGINX Plus R11 及其后的版本里,所有的 nginScript 代码必须被放置在单独的文件里,然后通过 js_include 指令来指定它们的位置。

js_set 指令用于设置 $upstream 变量。要注意,这个指令并不是要让 NGINX 或 NGINX Plus 去调用 nginScript 函数 transitionStatus。NGINX 变量是按需进行计算的,也就是在处理请求期间用到变量时才会进行计算。所以,js_set 指令是要告诉 NGINX 或 NGINX Plus 在必要的时候如何计算 $upstream 变量。

server 代码块定义 NGINX 和 NGINX Plus 如何处理 HTTP 请求。listen 指令告诉 NGINX 和 NGINX Plus 对 80 端口(默认 HTTP 端口)进行监听,不过生产环境一般配置成 SSL/TLS 来保护传输中的数据。

location 代码块的作用域包括了整个应用空间(/)。在这个代码块里,我们使用了 set 指令和两个新的变量 $transition_window_start 和 $transition_window_end 来定义切换时间窗口。时间可以被声明成RFC 2822 格式(例子里所示)或ISO 8601 格式(包含毫秒)。两种格式必须包含它们各自的本地时区标识符。因为 JavaScript 的 Date.now 函数总是返回 UTC 日期和时间,所以只有提供本地时区才能进行准确的时间比较。

proxy_pass 指令将请求重定向到 upstream 组,transitionStatus 函数会对它进行计算。

最后,error_log 指令启用了 nginScript 事件日志,级别为 info 及以上(默认情况下,只有 warn 及以上级别的事件会被记录下来)。将这个指令放在 location 代码块里,并指定单独的日志文件,这样就可以避免将主要的错误日志与其他 info 日志消息混杂在一起。

HTTP 应用的 nginScript 代码

我们假设你已经启用了 nginScript 模块。

我们将 nginScript 代码放在/etc/nginx/progressive_transition.js文件里,正如 js_include 指令所指定的那样。所有的函数都包含在这个文件里。

被调用的函数必须在函数调用者之前出现,于是我们定义了一个函数用于返回客户端 IP 地址的散列值。如果应用服务器的主要用户处于相同的局域网内,那么我们的客户端就会有相似的 IP 地址,所以我们的散列函数需要为小区间的输入值返回平均分布的散列值。

在这个例子里,我们使用了FNV-1a 散列算法,这个算法短小精悍,很快,而且具有良好的平均分布能力。它的另一个优势在于,它返回的是一个 32 位的正整数,这样可以很方便地计算每一个客户端 IP 地址在输出区间的位置。下面的代码是 FNV-1a 算法的 JavaScript 实现。

function fnv32a(str) {
 var hval = 2166136261;
 for (var i = 0; i < str.length; ++i ) {
 hval ^= str.charCodeAt(i);
 hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
 }
 return hval >>> 0;
}

接下来,我们定义 transitionStatus 函数,这个函数将 js_set 指令里的 $upstream 变量设置到 NGINX 配置里。

function transitionStatus(req) {
 var vars, window_start, window_end, time_now, timepos, numhash, hashpos;

 // 从 NGINX 配置里获取切换时间窗口 
 vars = req.variables;
 window_start = new Date(vars.transition_window_start);
 window_end = new Date(vars.transition_window_end);

 // 是否处于切换时间窗口内?
 time_now = Date.now();
 if ( time_now < window_start ) {
 return "old";
 } else if ( time_now > window_end ) {
 return "new";
 } else { // 处于切换时间窗口内 
 // 计算切换时间窗口内的位置 (0-1)
 timepos = (time_now - window_start) / (window_end - window_start);

 // 获取客户端 IP 地址的散列值 
 numhash = fnv32a(req.remoteAddress);

 // 计算散列值在输出区间里的位置 (0-1)
 hashpos = numhash / 4294967295; // Upper bound is 32 bits
 req.log("timepos = " + timepos + ", hashpos = " + hashpos); //error_log [info]

 // 需要切换这个客户端吗?
 if ( timepos > hashpos ) {
 return "new";
 } else {
 return "old";
 }
 }
}

transitionStatus 函数只有一个参数 req,这个参数代表的是一个 HTTP request 对象。request 对象的 variables 属性包含了 NGINX 的所有配置变量,包括用于设置切换时间窗口的 $transition_window_start 和 $transition_window_end。

外面的 if/else 代码块检查切换时间窗口是否启动、结束或者正在进行当中。如果在进行当中,我们通过向 fnv32a 函数传递 req.remoteAddress 来获取客户端 IP 地址的散列值。

然后我们计算散列值在区间中的位置。因为 FNV-1a 算法返回的是一个 32 位的正整数,我们可以直接将散列值除以 4,294,967,295(32 位整数的十进制表示)。

这个时候,我们调用 req.log() 来记录散列位置和切换时间窗口的当前位置。我们使用 info 级别将这些信息记录到之前在 NGINX 和 NGINX Plus 里配置的 error_log 文件里,并生成如下所示的日志条目。其中 js: 前缀表示从 JavaScript 代码中获得的日志条目。

2016/09/08 17:44:48 [info] 41325#41325: *84 js: timepos = 0.373333, hashpos = 0.840858

最后,我们比较散列值在输出区间中的位置和切换时间窗口的当前位置,并返回相应的 upstream 组的名字。

总结

在这篇文章里,我们介绍了如何使用 nginScript 复杂的编程式配置循序渐进地切换客户端到新的服务器。通过部署自定义逻辑来实现可控地选择合适的上游组,这只是 nginScript 提供的众多解决方案里一个特性。

相关推荐

辞旧迎新,新手使用Containerd时的几点须知

相信大家在2020年岁末都被Kubernetes即将抛弃Docker的消息刷屏了。事实上作为接替Docker运行时的Containerd在早在Kubernetes1.7时就能直接与Kubelet集成使...

分布式日志系统ELK+skywalking分布式链路完整搭建流程

开头在分布式系统中,日志跟踪是一件很令程序员头疼的问题,在遇到生产问题时,如果是多节点需要打开多节点服务器去跟踪问题,如果下游也是多节点且调用多个服务,那就更麻烦,再者,如果没有分布式链路,在生产日志...

Linux用户和用户组管理

1、用户账户概述-AAA介绍AAA指的是Authentication、Authorization、Accounting,即认证、授权和审计。?认证:验证用户是否可以获得权限,是3A的第一步,即验证身份...

linux查看最后N条日志

其实很简单,只需要用到tail这个命令tail-100catalina.out输入以上命令,就能列出catalina.out的最后100行。...

解决linux系统日志时间错误的问题

今天发现一台虚拟机下的系统日志:/var/log/messages,文件时间戳不对,跟正常时间差了12个小时。按网上说的执行了servicersyslogrestart重启syslog服务,还是不...

全程软件测试(六十二):软件测试工作如何运用Linux—读书笔记

从事过软件测试的小伙们就会明白会使用Linux是多么重要的一件事,工作时需要用到,面试时会被问到,简历中需要写到。对于软件测试人员来说,不需要你多么熟练使用Linux所有命令,也不需要你对Linux...

Linux运维之为Nginx添加错误日志(error_log)配置

Nginx错误日志信息介绍配置记录Nginx的错误信息是调试Nginx服务的重要手段,属于核心功能模块(nginx_core_module)的参数,该参数名字为error_log,可以放在不同的虚机主...

Linux使用swatchdog实时监控日志文件的变化

1.前言本教程主要讲解在Linux系统中如何使用swatchdog实时监控日志文件的变化。swatchdog(SimpleWATCHDOG)是一个简单的Perl脚本,用于监视类Unix系统(比如...

syslog服务详解

背景:需求来自于一个客户想将服务器的日志转发到自己的日志服务器上,所以希望我们能提供这个转发的功能,同时还要满足syslog协议。1什么是syslog服务1.1syslog标准协议如下图这里的fa...

linux日志文件的管理、备份及日志服务器的搭建

日志文件存放目录:/var/log[root@xinglog]#cd/var/log[root@xinglog]#lsmessages:系统日志secure:登录日志———————————...

运维之日志管理简介

日志简介在运维过程中,日志是必不可少的东西,通过日志可以快速发现问题所在。日志分类日志分类,对不同的日志进行不同维度的分析。操作系统日志操作系统是基础,应用都是在其之上;操作系统日志的分析,可以反馈出...

Apache Log4j 爆核弹级漏洞,Spring Boot 默认日志框架就能完美躲过

这两天沸沸扬扬的Log4j2漏洞门事件炒得热火朝天:突发!ApacheLog4j2报核弹级漏洞。。赶紧修复!!|Java技术栈|Java|SpringBoot|Spring...

Linux服务器存在大量log日志,如何快速定位错误?

来源:blog.csdn.net/nan1996jiang/articlep/details/109550303针对大量log日志快速定位错误地方tail/head简单命令使用:附加针对大量log日志...

Linux中查看日志文件的正确姿势,求你别tail走天下了!

作为一个后端开发工程师,在Linux中查看查看文件内容是基本操作了。尤其是通常要分析日志文件排查问题,那么我们应该如何正确打开日志文件呢?对于我这种小菜鸡来说,第一反应就是cat,tail,vi(或...

分享几款常用的付费日志系统,献给迷茫的你!

概述在前一篇文章中,我们分享了几款免费的日志服务器。他们各有各的特点,但是大家有不同的需求,有时免费的服务器不能满足大家的需要,下面推荐几款付费的日志服务器。1.Nagios日志服务器Nagio...

取消回复欢迎 发表评论: