经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Redis » 查看文章
nginx+lua+redis实现灰度发布
来源:cnblogs  作者:京东云开发者  时间:2023/12/18 16:28:59  对本文有异议

前言:

授人以鱼不如授人以渔.先学会用,在学原理,在学创造,可能一辈子用不到这种能力,但是不能不具备这种能力。这篇文章主要是沉淀使用nginx+lua+redis实现灰度,当我们具备了这种能力,随时可以基于这种能力和思想调整实现方案:比如nginx+lua+(其他数据源)、nginx+(其他脚本语言)

一、灰度方案:

常见的灰度实现方案:

  1. 请求路由:通过请求中的标识(如用户ID、设备ID、请求头等)来决定是否将请求路由到灰度环境。可以使用反向代理(如Nginx、Envoy)或API网关(如Kong、Apigee)来实现路由规则。

  2. 权重控制:将流量按照一定的权重比例分配到不同的环境中。可以通过负载均衡器(如HAProxy、Kubernetes Ingress)或代理服务器(如Nginx、Envoy)来实现权重控制。

  3. 特性开关:通过在代码中嵌入特性开关(Feature Flag)来控制功能的开启与关闭。可以使用配置文件、数据库、键值存储或特性管理平台(如LaunchDarkly、Unleash)来管理特性开关。

  4. 分阶段发布:将功能的发布分为多个阶段,从内部测试到灰度环境再到全量发布。可以使用部署工具(如Jenkins、GitLab CI/CD)或云平台(如AWS、Azure)来支持分阶段发布。

  5. A/B测试:将流量分为多个不同版本的应用程序,比较它们的性能和用户反馈。可以使用A/B测试平台(如Optimizely、Google Optimize)来管理和监控A/B测试。

  6. 金丝雀发布:将新版本的应用程序逐步引入生产环境,仅将少量流量导向新版本,并根据其性能和稳定性逐步增加流量。可以使用部署工具、容器编排平台或云平台来实现金丝雀发布。

常用的灰度发布方案:

  1. 基于用户ID的灰度发布:基于用户ID来划分灰度用户或百分比灰度,例如根据用户ID的哈希值或随机数来决定用户是否路由到灰度环境。

  2. 基于IP地址的灰度发布:根据用户的IP地址来划分灰度用户,例如将某一范围的IP地址指定为灰度用户,将请求从这些IP地址路由到灰度环境。

  3. Cookie/Session的灰度发布:通过在用户的Cookie或会话中设置特定的标识来划分灰度用户。例如,将特定的Cookie或会话变量设置为灰度标识,将具有该标识的请求路由到灰度环境。

  4. 请求头的灰度发布:基于请求头中的特定标识来划分灰度用户。例如,根据请求头中的自定义标识或特定的HTTP Header来路由请求到灰度环境。

  5. 权重或百分比的灰度发布:将请求随机分配给不同的环境,可以通过给不同环境设置不同的权重或百分比来控制流量的分配。

  6. A/B测试:将流量分为多个不同版本的应用程序,在实验期间比较它们的性能和用户反馈,最终选择最佳版本进行全量发布。

二、nginx+lua+redis实现灰度

理论:

1、安装并配置 Nginx 和 Redis。确保 Nginx 启用 Lua 模块,并可以访问 Redis。

2、在 Nginx 配置中定义灰度规则。您可以使用 Lua 脚本来判断用户是否应该被路由到灰度环境。示例配置如下:

  1. server {
  2. listen 80;
  3. server_name example.com;
  4. location / {
  5. access_by_lua_block {
  6. local redis = require "resty.redis"
  7. local red = redis:new()
  8. -- 连接到 Redis
  9. local ok, err = red:connect("redis_host", redis_port)
  10. if not ok then
  11. ngx.log(ngx.ERR, "failed to connect to Redis: ", err)
  12. ngx.exit(500)
  13. end
  14. -- 使用 Redis 根据用户 ID 判断是否路由到灰度环境
  15. local user_id = ngx.req.get_headers()["X-User-ID"]
  16. local is_gray = red:get("gray:" .. user_id)
  17. if is_gray == "1" then
  18. ngx.var.upstream = "gray_backend"
  19. end
  20. }
  21. proxy_pass http://backend;
  22. }
  23. location /gray {
  24. # 灰度环境的配置
  25. proxy_pass http://gray_backend;
  26. }
  27. location /admin {
  28. # 管理后台的配置
  29. proxy_pass http://admin_backend;
  30. }
  31. }

在上面的示例中,我们连接到 Redis,并根据请求中的用户 ID 判断是否将请求路由到灰度环境。ngx.var.upstream 变量用于动态设置上游地址,从而实现灰度环境的路由。

3、在 Redis 中设置灰度用户。您可以在 Redis 中维护一个键值对,其中键是用户 ID,值表示是否是灰度用户(例如,1 表示是灰度用户,0 表示不是)。您可以使用 Redis 的 SET 和 GET 命令来操作这些值。

  1. -- 设置用户为灰度用户
  2. local ok, err = red:set("gray:" .. user_id, 1)
  3. if not ok then
  4. ngx.log(ngx.ERR, "failed to set gray status for user: ", err)
  5. ngx.exit(500)
  6. end
  7. -- 设置用户为非灰度用户
  8. local ok, err = red:set("gray:" .. user_id, 0)
  9. if not ok then
  10. ngx.log(ngx.ERR, "failed to set gray status for user: ", err)
  11. ngx.exit(500)
  12. end

通过在 Redis 中设置用户的灰度状态,您可以动态地控制用户是否应该被路由到灰度环境。

4、根据需要,配置其他路径或功能的灰度规则。您可以根据需要在 Nginx 配置中添加其他路径或功能的灰度规则,以实现更复杂的灰度发布策略。

实践:

这里主要使用OpenResty

nginx+lua 实现灰度----主要使用OpenResty

OpenResty(又称:ngx_openresty) 是一个基于 NGINX 的可伸缩的 Web 平台,OpenResty 是一个强大的 Web 应用服务器,Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块

openresty的api文档: https://www.kancloud.cn/qq13867685/openresty-api-cn/159190

1、根据post请求url参数匹配进行路由

nginx配置如下:

  1. #user nobody;
  2. worker_processes 1;
  3. #error_log logs/error.log;
  4. #error_log logs/error.log notice;
  5. #error_log logs/error.log info;
  6. #pid logs/nginx.pid;
  7. events {
  8. worker_connections 1024;
  9. }
  10. http {
  11. include mime.types;
  12. default_type application/octet-stream;
  13. #log_format main '$time_local 客户端地址:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求地址:$http_host HTTP请求状态:$status upstream状态:$upstream_status 负载地址:$upstream_addr url跳转来源:$http_referer $body_bytes_sent $http_user_agent $request_uri';
  14. log_format logFormat '$group $time_local 客户端:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求:$http_host HTTP状态:$status upstream状态:$upstream_status 负载:$upstream_addr
  15. url跳转:$http_referer $body_bytes_sent $http_user_agent $request_uri 请求参数 $query_string $args $document_root $uri
  16. -----$request_uri $request_filename $http_cookie';
  17. access_log logs/access.log logFormat;
  18. sendfile on;
  19. #tcp_nopush on;
  20. #keepalive_timeout 0;
  21. keepalive_timeout 65;
  22. server{
  23. listen 80; #监听端口
  24. server_name 域名; #监听地址
  25. access_log logs/xx.com.access.log logFormat;
  26. location /hello {
  27. default_type 'text/plain';
  28. content_by_lua 'ngx.say("hello ,lua scripts")';
  29. }
  30. location /myip {
  31. default_type 'text/plain';
  32. content_by_lua '
  33. clientIP = ngx.req.get_headers()["x_forwarded_for"]
  34. ngx.say("Forwarded_IP:",clientIP)
  35. if clientIP == nli then
  36. clientIP = ngx.var.remote_addr
  37. ngx.say("Remote_IP:",clientIP)
  38. end
  39. ';
  40. }
  41. location / {
  42. default_type 'text/plain';
  43. lua_need_request_body on;
  44. #content_by_lua_file /etc/nginx/lua/dep.lua;
  45. #content_by_lua_file D:/sortware/openresty/openresty-1.17.8.2-win64/conf/dep.lua; # 指定由lua文件处理http请求
  46. content_by_lua_file D:/user/Downloads/openresty-1.19.9.1-win64/conf/dep.lua; # 指定由lua文件处理http请求
  47. }
  48. location @default_version {
  49. proxy_pass http://default;
  50. proxy_set_header Host $http_host;
  51. proxy_set_header X-Real-IP $remote_addr;
  52. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  53. }
  54. location @new_version {
  55. proxy_pass http://new_version;
  56. proxy_set_header Host $http_host;
  57. #proxy_redirect default;
  58. proxy_set_header X-Real-IP $remote_addr;
  59. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  60. }
  61. location @old_version {
  62. proxy_pass http://old_version;
  63. proxy_set_header Host $http_host;
  64. proxy_set_header X-Real-IP $remote_addr;
  65. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  66. }
  67. }
  68. #标准预发环境
  69. upstream default {
  70. server ip:port;
  71. }
  72. #预发2
  73. upstream new_version {
  74. server ip:port;
  75. }
  76. #预发3
  77. upstream old_version {
  78. server ip:port;
  79. }
  80. }

lua脚本如下:

  1. --get请求uri参数
  2. function SaveTableContent(file, obj)
  3. local szType = type(obj);
  4. print(szType);
  5. if szType == "number" then
  6. file:write(obj);
  7. elseif szType == "string" then
  8. file:write(string.format("%q", obj));
  9. elseif szType == "table" then
  10. --把table的内容格式化写入文件
  11. --file:write("{\n");
  12. for i, v in pairs(obj) do
  13. SaveTableContent(file, i);
  14. file:write(":");
  15. SaveTableContent(file, v);
  16. file:write(",");
  17. end
  18. --file:write("}\n");
  19. else
  20. error("can't serialize a "..szType);
  21. end
  22. end
  23. function SaveTable(obj)
  24. local file = io.open("D:\\user\\Downloads\\openresty-1.19.9.1-win64\\logs\\parmas.txt", "a");
  25. assert(file);
  26. SaveTableContent(file,obj);
  27. file:close();
  28. end
  29. local request_method = ngx.var.request_method
  30. local getargs = nil
  31. local args = nil
  32. local read_body = nil
  33. local body_data = nil
  34. local thirdPolicystatus = nil
  35. if "GET" == request_method then
  36. args = ngx.req.get_uri_args()
  37. elseif "POST"== request_method then
  38. getargs = ngx.req.get_uri_args()
  39. args = ngx.req.get_post_args()
  40. read_body = ngx.req.read_body()
  41. body_data = ngx.req.get_body_data()
  42. end
  43. if getargs ~= nil then
  44. SaveTable(getargs);
  45. thirdPolicystatus= getargs["thirdPolicystatus"];
  46. if thirdPolicystatus ~= nil then
  47. SaveTable(thirdPolicystatus);
  48. end
  49. end
  50. if args ~= nil then
  51. SaveTable(args);
  52. end
  53. if read_body ~= nil then
  54. SaveTable(read_body);
  55. end
  56. if body_data ~= nil then
  57. SaveTable(body_data);
  58. end
  59. if getargs ~= nil then
  60. thirdPolicystatus = getargs["thirdPolicystatus"]
  61. if thirdPolicystatus ~= nil and thirdPolicystatus == "1" then
  62. SaveTable("new_version-getargs");
  63. ngx.exec('@new_version')
  64. elseif thirdPolicystatus ~= nil and thirdPolicystatus == "2" then
  65. SaveTable("old_version-getargs");
  66. ngx.exec('@old_version')
  67. else
  68. SaveTable("default_version-getargs");
  69. ngx.exec('@default_version')
  70. end
  71. end
  72. if args ~= nil then
  73. if type(args) == "table" then
  74. thirdPolicystatus = tostring(args["thirdPolicystatus"])
  75. if thirdPolicystatus ~= nil and thirdPolicystatus == 1 then
  76. SaveTable("new_version-args-table");
  77. ngx.exec('@new_version')
  78. elseif thirdPolicystatus ~= nil and thirdPolicystatus == 2 then
  79. SaveTable("old_version-args-table");
  80. ngx.exec('@old_version')
  81. else
  82. SaveTable("default_version-args-table");
  83. ngx.exec('@default_version')
  84. end
  85. elseif type(args) == "string" then
  86. local json = require("cjson")
  87. local jsonObj = json.decode(args)
  88. thirdPolicystatus = jsonObj['thirdPolicystatus']
  89. if thirdPolicystatus ~= nil and thirdPolicystatus == 1 then
  90. SaveTable("new_version-args-string");
  91. ngx.exec('@new_version')
  92. elseif thirdPolicystatus ~= nil and thirdPolicystatus == 2 then
  93. SaveTable("old_version-args-string");
  94. ngx.exec('@old_version')
  95. else
  96. SaveTable("default_version-args-string");
  97. ngx.exec('@default_version')
  98. end
  99. end
  100. end
  101. return

host如下:

  1. 127.0.0.1 域名

访问地址:

  1. 域名

菜单运营数据---保单数据,默认走default集群,保单状态承保成功走new_version集群,保单状态终止走old_version集群

2、根据请求参数或ip等进行匹配redis缓存数据进行路由,灵活性更高。

redis下载地址:https://github.com/tporadowski/redis/releases

nginx配置如下:

  1. #user nobody;
  2. worker_processes 1;
  3. #error_log logs/error.log;
  4. #error_log logs/error.log notice;
  5. #error_log logs/error.log info;
  6. #pid logs/nginx.pid;
  7. events {
  8. worker_connections 1024;
  9. }
  10. http {
  11. include mime.types;
  12. default_type application/octet-stream;
  13. #log_format main '$time_local 客户端地址:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求地址:$http_host HTTP请求状态:$status upstream状态:$upstream_status 负载地址:$upstream_addr url跳转来源:$http_referer $body_bytes_sent $http_user_agent $request_uri';
  14. log_format logFormat '$group $time_local 客户端:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求:$http_host HTTP状态:$status upstream状态:$upstream_status 负载:$upstream_addr
  15. url跳转:$http_referer $body_bytes_sent $http_user_agent $request_uri 请求参数 $query_string $args $document_root $uri
  16. -----$request_uri $request_filename $http_cookie';
  17. access_log logs/access.log logFormat;
  18. sendfile on;
  19. #tcp_nopush on;
  20. #keepalive_timeout 0;
  21. keepalive_timeout 65;
  22. server{
  23. listen 80; #监听端口
  24. server_name 域名; #监听地址
  25. access_log logs/xx.com.access.log logFormat;
  26. location /redis {
  27. default_type 'text/plain';
  28. content_by_lua 'ngx.say("hello ,lua scripts redis")';
  29. }
  30. location / {
  31. default_type 'text/plain';
  32. lua_need_request_body on;
  33. content_by_lua_file D:/user/Downloads/openresty-1.19.9.1-win64/conf/redis.lua; # 指定由lua文件处理http请求
  34. }
  35. location @pre-prd {
  36. proxy_pass http://pre-prd;
  37. proxy_set_header Host $http_host;
  38. #proxy_redirect default;
  39. proxy_set_header X-Real-IP $remote_addr;
  40. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  41. }
  42. location @prd {
  43. proxy_pass http://prd;
  44. proxy_set_header Host $http_host;
  45. proxy_set_header X-Real-IP $remote_addr;
  46. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  47. }
  48. }
  49. #预发2演示线上
  50. upstream prd {
  51. server ip:port;
  52. }
  53. #预发演示预发线上
  54. upstream pre-prd {
  55. server ip:port;
  56. }
  57. }

lua脚本如下:

  1. --get请求uri参数
  2. function SaveTableContent(file, obj)
  3. local szType = type(obj);
  4. print(szType);
  5. if szType == "number" then
  6. file:write(obj);
  7. elseif szType == "string" then
  8. file:write(string.format("%q", obj));
  9. elseif szType == "table" then
  10. --把table的内容格式化写入文件
  11. --file:write("{\n");
  12. for i, v in pairs(obj) do
  13. SaveTableContent(file, i);
  14. file:write(":");
  15. SaveTableContent(file, v);
  16. file:write(",");
  17. end
  18. --file:write("}\n");
  19. else
  20. error("can't serialize a "..szType);
  21. end
  22. end
  23. function SaveTable(obj)
  24. --local file = io.open("D:\\user\\Downloads\\openresty-1.19.9.1-win64\\logs\\parmas.txt", "a");
  25. local file = io.open("D:\\user\\Downloads\\openresty-1.19.9.1-win64\\logs\\redis.txt", "a");
  26. assert(file);
  27. SaveTableContent(file,obj);
  28. file:close();
  29. end
  30. local request_method = ngx.var.request_method
  31. local getargs = nil
  32. local args = nil
  33. local read_body = nil
  34. local body_data = nil
  35. local thirdPolicystatus = nil
  36. if "GET" == request_method then
  37. args = ngx.req.get_uri_args()
  38. elseif "POST"== request_method then
  39. getargs = ngx.req.get_uri_args()
  40. args = ngx.req.get_post_args()
  41. read_body = ngx.req.read_body()
  42. body_data = ngx.req.get_body_data()
  43. end
  44. if getargs ~= nil then
  45. SaveTable("getargs");
  46. SaveTable(getargs);
  47. thirdPolicystatus= getargs["thirdPolicystatus"];
  48. if thirdPolicystatus ~= nil then
  49. SaveTable("thirdPolicystatus");
  50. SaveTable(thirdPolicystatus);
  51. end
  52. end
  53. if args ~= nil then
  54. SaveTable("args");
  55. SaveTable(args);
  56. end
  57. if read_body ~= nil then
  58. SaveTable("read_body");
  59. SaveTable(read_body);
  60. end
  61. if body_data ~= nil then
  62. SaveTable("body_data");
  63. SaveTable(body_data);
  64. end
  65. local redis = require "resty.redis"
  66. local cache = redis.new()
  67. cache:set_timeout(60000)
  68. local ok, err = cache.connect(cache, '127.0.0.1', 6379)
  69. if not ok then
  70. SaveTable("not ok");
  71. ngx.exec("@prd")
  72. return
  73. end
  74. local local_ip = ngx.req.get_headers()["X-Real-IP"]
  75. if local_ip == nil then
  76. local_ip = ngx.req.get_headers()["x_forwarded_for"]
  77. SaveTable("local_ip1");
  78. if local_id ~= nil then
  79. SaveTable(local_id);
  80. end
  81. end
  82. if local_ip == nil then
  83. local_ip = ngx.var.remote_addr
  84. SaveTable("local_ip2");
  85. if local_id ~= nil then
  86. SaveTable(local_id);
  87. end
  88. end
  89. -- redis 中根据客户端 ip 获取是否存在值
  90. local res, err = cache:get(local_ip)
  91. -- 如果存在则转发到 @pre-prd
  92. if res == "1" then
  93. SaveTable(res);
  94. SaveTable("pre-prd");
  95. ngx.exec("@pre-prd")
  96. return
  97. else
  98. SaveTable("-------");
  99. SaveTable(local_ip);
  100. SaveTable(res);
  101. cache:set(local_ip)
  102. end
  103. -- 如果不存在,则转发到 @prd
  104. SaveTable("prd");
  105. ngx.exec("@prd")
  106. local ok, err = cache:close()
  107. if not ok then
  108. ngx.say("failed to close:", err)
  109. return
  110. end
  111. return

使用时这里根据redis缓里缓存的ip地址进行负载路由。

三、相关配置与语法

1、Nginx配置文件详解

源码:https://trac.nginx.org/nginx/browser

官网:http://www.nginx.org/

windows 安装包下载地址:https://nginx.org/en/download.html

nginx.conf

  1. ########### 每个指令必须有分号结束。#################
  2. # 全局块 比如工作进程数,定义日志路径;
  3. #配置用户或者组,默认为nobody nobody。
  4. #user nobody;
  5. #user administrator administrators;
  6. #允许生成的进程数,默认为1,一般建议设成CPU核数1-2倍
  7. worker_processes 1;
  8. #worker_processes 8;
  9. #指定nginx进程运行文件存放地址
  10. #pid /nginx/pid/nginx.pid;
  11. #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别依次为:#debug|info|notice|warn|error|crit|alert|emerg
  12. error_log logs/error.log error;
  13. #error_log logs/error.log;
  14. #error_log logs/error.log notice;
  15. #error_log logs/error.log info;
  16. #Events块 设置处理轮询事件模型,每个工作进程最大连接数及http层的keep-alive超时时间;
  17. events {
  18. #使用epoll的I/O 模型处理轮询事件。
  19. #可以不设置,nginx会根据操作系统选择合适的模型
  20. #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
  21. #use epoll;
  22. #工作进程的最大连接数量, 默认1024个
  23. worker_connections 2048;
  24. #设置网路连接序列化,防止惊群现象发生,默认为on
  25. accept_mutex on;
  26. #设置一个进程是否同时接受多个网络连接,默认为off
  27. multi_accept on;
  28. }
  29. # http块 路由匹配、静态文件服务器、反向代理、负载均衡等
  30. http {
  31. # 导入文件扩展名与文件类型映射表 mime.types
  32. include mime.types;
  33. #默认文件类型,默认为text/plain
  34. default_type application/octet-stream;
  35. #取消服务日志
  36. #access_log off;
  37. #日志格式及access日志路径 自定义格式
  38. log_format myFormat '$time_local 客户端地址:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求地址:$http_host HTTP请求状态:$status upstream状态:$upstream_status 负载地址:$upstream_addr url跳转来源:$http_referer $upstream_addr $body_bytes_sent $http_user_agent';
  39. #combined为日志格式的默认值
  40. access_log logs/access.log myFormat;
  41. #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
  42. sendfile on;
  43. #sendfile开启时才开启。
  44. tcp_nopush on;
  45. server_names_hash_bucket_size 64;
  46. #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
  47. sendfile_max_chunk 100k;
  48. #连接超时时间,默认为75s,可以在http,server,location块。
  49. keepalive_timeout 65;
  50. #--------------------静态文件压缩-----------------------------#
  51. #Nginx可以对网站的css、js 、xml、html 文件在传输前进行压缩,大幅提高页面加载速度。经过Gzip压缩后页面大小可以变为原来的30%甚至更小。使用时仅需开启Gzip压缩功能即可。你可以在http全局块或server块增加这个配置。
  52. # 开启gzip压缩功能
  53. #gzip on;
  54. gzip on;
  55. # 设置允许压缩的页面最小字节数; 这里表示如果文件小于10k,压缩没有意义.
  56. gzip_min_length 10k;
  57. # 设置压缩比率,最小为1,处理速度快,传输速度慢;
  58. # 9为最大压缩比,处理速度慢,传输速度快; 推荐6
  59. gzip_comp_level 6;
  60. # 设置压缩缓冲区大小,此处设置为16个8K内存作为压缩结果缓冲
  61. gzip_buffers 16 8k;
  62. # 设置哪些文件需要压缩,一般文本,css和js建议压缩。图片视需要要锁。
  63. gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  64. #--------------------静态文件压缩-----------------------------#
  65. server {
  66. listen 80;
  67. server_name localhost;
  68. location / {
  69. root html;
  70. index index.html index.htm;
  71. }
  72. error_page 500 502 503 504 /50x.html;
  73. location = /50x.html {
  74. root html;
  75. }
  76. }
  77. #http server块
  78. server {
  79. keepalive_requests 120; #单连接请求上限次数。
  80. listen 8081; #监听端口
  81. server_name 域名 #监听地址
  82. #ssi on;
  83. #autoindex on;
  84. charset utf-8;
  85. client_max_body_size 10M; # 限制用户上传文件大小,默认1M
  86. #access_log logs/host.access.log myFormat; #定义访问日志,可以针对每一个server(即每一个站点)设置它们自己的访问日志。
  87. # 转发动态请求到web应用服务器
  88. #location ^~ /api {
  89. #rewrite ^/api/(.*)$ /$1 break;
  90. #proxy_pass https://stream;
  91. #break;#终止匹配
  92. #}
  93. location / {
  94. # 使用proxy_pass转发请求到通过upstream定义的一组应用服务器
  95. proxy_pass http://stream ;
  96. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  97. proxy_set_header Host $http_host;
  98. proxy_redirect off;
  99. proxy_set_header X-Real-IP $remote_addr;
  100. }
  101. location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
  102. proxy_pass http://stream ; #请求转向stream 定义的服务器列表
  103. }
  104. #location / {
  105. #autoindex on;
  106. #try_files $uri $uri/ /index.html?$args;
  107. #}
  108. # 规则1:通用匹配
  109. #location / {
  110. #ssi on;
  111. #autoindex on; #自动显示目录
  112. #autoindex_exact_size off; #人性化方式显示文件大小否则以byte显示
  113. #autoindex_localtime on; #按服务器时间显示,否则以gmt时间显示
  114. #root /root; #定义服务器的默认网站根目录位置
  115. #index index.html index.htm; #定义首页索引文件的名称 设置默认页
  116. # 使用proxy_pass转发请求到通过upstream定义的一组应用服务器
  117. #proxy_pass http://mysvr; #负载配置
  118. #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  119. #proxy_set_header Host $http_host;
  120. #proxy_redirect off;
  121. #proxy_set_header X-Real-IP $remote_addr;
  122. #deny ip; # 拒绝的ip
  123. #allow ip; # 允许的ip
  124. #}
  125. # 规则2:处理以/static/开头的url
  126. location ^~ /static {
  127. alias /usr/share/nginx/html/static; # 静态资源路径
  128. }
  129. #= 精确匹配 1
  130. #^~ 以某个字符串开头 2
  131. #~ 区分大小写的正则匹配 3
  132. #~* 不区分大小写的正则匹配 4
  133. #!~ 区分大小写的不匹配正则 5
  134. #!~* 不区分大小写的不匹配正则 6
  135. #/ 通用匹配,任何请求都会匹配到 7
  136. #location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
  137. #root path; #根目录
  138. #index vv.txt; #设置默认页
  139. #proxy_pass http://stream; #请求转向stream 定义的服务器列表
  140. #deny 127.0.0.1; #拒绝的ip
  141. #allow ip; #允许的ip
  142. #}
  143. #-----------------------------静态文件缓存--------------------#
  144. #缓存可以加快下次静态文件加载速度。我们很多与网站样式相关的文件比如css和js文件一般不怎么变化,缓存有效器可以通过expires选项设置得长一些。
  145. # 使用expires选项开启静态文件缓存,10天有效
  146. location ~ ^/(images|javascript|js|css|flash|media|static)/ {
  147. root /var/www/big.server.com/static_files;
  148. expires 10d;
  149. }
  150. #-----------------------------静态文件缓存--------------------#
  151. # 错误页面
  152. error_page 500 502 503 504 /50x.html;
  153. location = /50x.html {
  154. root html;
  155. }
  156. }
  157. #-------------$符号的全局变量含义--------------#
  158. #$args, 请求中的参数;
  159. #$content_length, HTTP请求信息里的"Content-Length";
  160. #$content_type, 请求信息里的"Content-Type";
  161. #$document_root, 针对当前请求的根路径设置值;
  162. #$document_uri, 与$uri相同;
  163. #$host, 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名;
  164. #$limit_rate, 对连接速率的限制;
  165. #$request_method, 请求的方法,比如"GET"、"POST"等;
  166. #$remote_addr, 客户端地址;
  167. #$remote_port, 客户端端口号;
  168. #$remote_user, 客户端用户名,认证用;
  169. #$request_filename, 当前请求的文件路径名
  170. #$request_body_file,当前请求的文件
  171. #$request_uri, 请求的URI,带查询字符串;
  172. #$query_string, 与$args相同;
  173. #$scheme, 所用的协议,比如http或者是https,比如rewrite ^(.+)$
  174. #$scheme://example.com$1 redirect;
  175. #$server_protocol, 请求的协议版本,"HTTP/1.0"或"HTTP/1.1";
  176. #$server_addr, 服务器地址;
  177. #$server_name, 请求到达的服务器名;
  178. #$server_port, 请求到达的服务器端口号;
  179. #$uri, 请求的URI,可能和最初的值有不同,比如经过重定向之类的。
  180. #-------------$符号的全局变量含义--------------#
  181. #错误页面
  182. #error_page 404 https://www.baidu.com; #错误页
  183. #error_page 404 500 502 503 504 403 /error.shtml;
  184. # 负载均衡
  185. upstream insurance-pre {
  186. #weigth参数表示权值,权值越高被分配到的几率越大
  187. #--------------------负载均衡方式------------------#
  188. #1.轮询(默认)
  189. #2.权重,weight越大,承担任务越多
  190. #server ip:port weight=5
  191. #3.ip_hash
  192. #ip_hash;
  193. #4.url_hash
  194. #hash $request_uri;
  195. #5. fair(第三方)--按后端服务器的响应时间来分配请求,响应时间短的优先分配。使用这个算法需要安装nginx-upstream-fair这个库。
  196. #fair;
  197. #--------------------负载均衡方式------------------#
  198. server ip:port weight=5; # weight越高,权重越大
  199. server ip:port weight=1;
  200. server ip:port weight=1;
  201. server ip:port backup; # 热备
  202. }
  203. # 转发动态请求
  204. #server {
  205. #listen 80;
  206. #server_name localhost;
  207. #client_max_body_size 1024M;
  208. #location / {
  209. #proxy_pass http://localhost:8080;
  210. #proxy_set_header Host $host:$server_port;
  211. #}
  212. #}
  213. # http请求重定向到https请求
  214. #server {
  215. #listen 80;
  216. #server_name 域名;
  217. #return 301 https://$server_name$request_uri;
  218. #}
  219. server {
  220. keepalive_requests 120; #单连接请求上限次数。
  221. listen 80; #监听端口
  222. server_name 域名 #监听地址
  223. #ssi on;
  224. #autoindex on;
  225. charset utf-8;
  226. client_max_body_size 10M; # 限制用户上传文件大小,默认1M
  227. #access_log logs/host.access.log myFormat; #定义访问日志,可以针对每一个server(即每一个站点)设置它们自己的访问日志。
  228. # 转发动态请求到web应用服务器
  229. #location ^~ /api {
  230. #rewrite ^/api/(.*)$ /$1 break;
  231. #proxy_pass https://域名;
  232. #break;#终止匹配
  233. #}
  234. location / {
  235. # 使用proxy_pass转发请求到通过upstream定义的一组应用服务器
  236. proxy_pass http://tomcat_gray1;
  237. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  238. proxy_set_header Host $http_host;
  239. proxy_redirect off;
  240. proxy_set_header X-Real-IP $remote_addr;
  241. }
  242. location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
  243. proxy_pass http://域名; #请求转向域名 定义的服务器列表
  244. }
  245. }
  246. #标准预发环境
  247. upstream tomcat_gray1 {
  248. server ip;
  249. server 域名;
  250. }
  251. upstream tomcat_gray2 {
  252. server 域名;
  253. }
  254. }

host 配置

  1. 127.0.0.1 域名

浏览器访问 域名

可以通过观察access.log发现请求接入日志。

2、lua基础语法

教程:https://www.runoob.com/lua/if-else-statement-in-lua.html

lua的IDE编辑器:https://github.com/rjpcomputing/luaforwindows

3、nginx实现灰度

根据前端请求参数进行灰度到不同节点。

  1. #user nobody;
  2. worker_processes 1;
  3. #error_log logs/error.log;
  4. #error_log logs/error.log notice;
  5. #error_log logs/error.log info;
  6. #pid logs/nginx.pid;
  7. events {
  8. worker_connections 1024;
  9. }
  10. http {
  11. include mime.types;
  12. default_type application/octet-stream;
  13. #log_format main '$time_local 客户端地址:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求地址:$http_host HTTP请求状态:$status upstream状态:$upstream_status 负载地址:$upstream_addr url跳转来源:$http_referer $body_bytes_sent $http_user_agent $request_uri';
  14. log_format logFormat '$group $time_local 客户端:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求:$http_host HTTP状态:$status upstream状态:$upstream_status 负载:$upstream_addr
  15. url跳转:$http_referer $body_bytes_sent $http_user_agent $request_uri 请求参数 $query_string $args $document_root $uri
  16. -----$request_uri $request_filename $http_cookie';
  17. access_log logs/access.log logFormat;
  18. sendfile on;
  19. #tcp_nopush on;
  20. #keepalive_timeout 0;
  21. keepalive_timeout 65;
  22. #gzip on;
  23. server {
  24. listen 80; #监听端口
  25. server_name 域名; #监听地址
  26. access_log logs/xx.com.access.log logFormat;
  27. #方式二、nginx+lua实现灰度
  28. ## 1、将对localhost访问由/opt/app/lua/dep.lua进行处理
  29. ## 2、根据逻辑处理后,决定回调如下两个其中1个内部跳转
  30. #方式三根据请求参数值匹配进行路由
  31. #/policy/policyInfoList?thirdPolicystatus=2
  32. set $group "default";
  33. if ($query_string ~* "thirdPolicystatus=1"){ #动态控制路由
  34. set $group new_version;
  35. }
  36. if ($query_string ~* "thirdPolicystatus=2"){
  37. set $group old_version;
  38. }
  39. location /
  40. {
  41. default_type "text/html";
  42. #content_by_lua_file D:/sortware/openresty/openresty-1.17.8.2-win64/conf/dep.lua; # 指定由lua文件处理http请求
  43. proxy_pass http://$group;
  44. proxy_set_header Host $host;
  45. proxy_set_header X-Real-IP $remote_addr;
  46. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  47. index index.html index.htm;
  48. }
  49. }
  50. #标准预发环境
  51. upstream default {
  52. server ip:port;
  53. }
  54. #预发2
  55. upstream new_version {
  56. server ip:port;
  57. }
  58. #预发3
  59. upstream old_version {
  60. server ip:port;
  61. }
  62. }

host如下:

  1. 127.0.0.1 域名

访问地址:

  1. 域名

菜单运营数据---保单数据,默认走default集群,保单状态承保成功走new_version集群,保单状态终止走old_version集群

根据cookie内的参数进行负载

  1. #user nobody;
  2. worker_processes 1;
  3. #error_log logs/error.log;
  4. #error_log logs/error.log notice;
  5. #error_log logs/error.log info;
  6. #pid logs/nginx.pid;
  7. events {
  8. worker_connections 1024;
  9. }
  10. http {
  11. include mime.types;
  12. default_type application/octet-stream;
  13. #log_format main '$time_local 客户端地址:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求地址:$http_host HTTP请求状态:$status upstream状态:$upstream_status 负载地址:$upstream_addr url跳转来源:$http_referer $body_bytes_sent $http_user_agent $request_uri';
  14. log_format logFormat '$http_cookie $group $time_local 客户端:$remote_addr–$remote_port 请求的URI和HTTP协议:$request 请求:$http_host HTTP状态:$status upstream状态:$upstream_status 负载:$upstream_addr
  15. url跳转:$http_referer $body_bytes_sent $http_user_agent $request_uri 请求参数 $query_string $args $document_root $uri
  16. -----$request_uri $request_filename ';
  17. access_log logs/access.log logFormat;
  18. sendfile on;
  19. #tcp_nopush on;
  20. #keepalive_timeout 0;
  21. keepalive_timeout 65;
  22. #gzip on;
  23. server {
  24. listen 80; #监听端口
  25. server_name 域名; #监听地址
  26. access_log logs/xx.com.access.log logFormat;
  27. #方式二、nginx+lua实现灰度
  28. ## 1、将对localhost访问由/opt/app/lua/dep.lua进行处理
  29. ## 2、根据逻辑处理后,决定回调如下两个其中1个内部跳转
  30. #方式三根据请求参数值匹配进行路由
  31. #域名policy/policyInfoList?thirdPolicystatus=2
  32. set $group "default";
  33. if ($query_string ~* "thirdPolicystatus=1"){ #动态控制路由
  34. set $group new_version;
  35. }
  36. if ($query_string ~* "thirdPolicystatus=2"){
  37. set $group old_version;
  38. }
  39. if ($http_cookie ~* "sso.xx.com=BJ.E2C7D319112E7F6252BF010770269E235820211121073248"){
  40. set $group pro_version;
  41. }
  42. if ($http_cookie ~* "sso.xx.com!=BJ.E2C7D319112E7F6252BF010770269E235820211121073248"){
  43. set $group grey_version;
  44. }
  45. location /
  46. {
  47. default_type "text/html";
  48. #content_by_lua_file D:/sortware/openresty/openresty-1.17.8.2-win64/conf/dep.lua; # 指定由lua文件处理http请求
  49. proxy_pass http://$group;
  50. proxy_set_header Host $host;
  51. proxy_set_header X-Real-IP $remote_addr;
  52. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  53. index index.html index.htm;
  54. }
  55. }
  56. #标准预发环境
  57. upstream default {
  58. server ip:port;
  59. }
  60. #预发2
  61. upstream new_version {
  62. server ip:port;
  63. }
  64. #预发3
  65. upstream old_version {
  66. server ip:port;
  67. }
  68. #预发2
  69. upstream pro_version {
  70. server ip:port;
  71. }
  72. #预发3
  73. upstream grey_version {
  74. server ip:port;
  75. }
  76. }

根据cookie内容转发到不同的集群

四、相关可操作和替换性

想法一:如果这个时候我门需要一个动态化配置控制台则可以通过javaweb等工程进行操作redis实现实时更新redis数据从而控制灰度

想法二:切换其他数据源比如

  1. MySQL/MariaDB: 使用 Lua 的 lua-mysql 或 LuaSQL 库,您可以在 Lua 中连接和查询 MySQL 或 MariaDB 数据库。

  2. PostgreSQL: 使用 Lua 的 lua-postgres 或 LuaSQL 库,您可以在 Lua 中连接和查询 PostgreSQL 数据库。

  3. MongoDB: 使用 Lua 的 mongo-lua-driver 库,您可以在 Lua 中连接和操作 MongoDB 数据库。

  4. HTTP API: 使用 Lua 的 LuaHTTP 库,您可以在 Lua 中发起 HTTP 请求,并与远程的 HTTP API 进行通信。

  5. Cassandra: 使用 Lua 的 lua-cassandra 库,您可以在 Lua 中连接和查询 Cassandra 数据库。

想法三:切换其他脚本语言

  1. JavaScript: 通过使用 Nginx 的 ngx_http_js_module,您可以在 Nginx 中使用 JavaScript。这可以让您使用 JavaScript 脚本来实现一些灰度发布或其他功能。此外,JavaScript 也广泛用于前端开发,因此可以在前后端一体化的项目中更容易共享代码逻辑。

  2. LuaJIT: LuaJIT 是一个通过即时编译实现高性能的 Lua 解释器。它提供了与标准 Lua 解释器兼容的 API,但是比标准 Lua 解释器更快。使用 LuaJIT,您可以获得更高的性能,同时保持与 Lua 的兼容性。

  3. Python: 如果您已经熟悉 Python,您可以使用 Python-NGINX-Module 在 Nginx 中嵌入 Python。这样可以使用 Python 编写 Nginx 的配置文件和处理请求的逻辑。

  4. Java: 使用 nginx-jvm-clojure 或 nginx-jwt 等模块,您可以在 Nginx 中嵌入 Java 或 Clojure。这些模块提供了在 Nginx 上运行 Java 或 Clojure 代码的功能,可以与其他 Java 或 Clojure 库和框架进行集成。

想法四:切换其他web服务器或反向代理服务器

  1. Apache HTTP Server: Apache 是一个广泛使用的开源 Web 服务器和反向代理服务器,它支持多种模块和扩展,提供了丰富的功能和配置选项。

  2. Microsoft IIS: Internet Information Services (IIS) 是由 Microsoft 开发的 Web 服务器,专为 Windows 操作系统设计。它是 Windows Server 默认的 Web 服务器,提供了广泛的功能和集成。

  3. Caddy: Caddy 是一个用 Go 编写的现代化的 Web 服务器和反向代理服务器。它具有简单配置、自动 HTTPS、HTTP/2 支持等特性。

  4. HAProxy: HAProxy 是一个高性能的负载均衡器和反向代理服务器,适用于高流量的 Web 应用程序。它具有丰富的负载均衡和代理功能。

  5. Envoy: Envoy 是一个轻量级的开源代理服务器和通信总线,适用于云原生和微服务架构。它具有动态配置、负载平衡、流量管理等功能。

大家可以根据自己的想法或者兴趣进行研究,本文不做过多介绍

作者:京东健康 马仁喜

来源:京东云开发者社区 转载请注明来源

原文链接:https://www.cnblogs.com/Jcloud/p/17910370.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号