ToB企服应用市场:ToB评测及商务社交产业平台

标题: 百万架构师第四十四课:Nginx:Nginx 的扩展-OpenRestry|JavaGuide [打印本页]

作者: 冬雨财经    时间: 4 天前
标题: 百万架构师第四十四课:Nginx:Nginx 的扩展-OpenRestry|JavaGuide
Nginx 的扩展-OpenRestry

课程目的

Nginx 进程模型简介

多进程

​        当它启动以后,会产生一个主进程和多个工作进程。多个工作进程是通过 Master 进程去管理的。它是基于 Master 进程 Fork 出来的。当我们的 Nginx 收到一个请求的时候,它会向我们的 work 发送一个信号。然后通过 worker 进程去管理。雷同于中央进程的意思。
​        当有一个请求过来的时候,只会有一个 worker 进程去处理惩罚。
root   /nginx747310 20:09?00:00:00 nginx:master   process .nobody747474730 20:09?00:00:00 nginx:worker process
  1. [root@Darian1 nginx]# ps -ef|grep nginx
  2. root      47432      1  0 00:14 ?        00:00:00 nginx: master process ./sbin/nginx
  3. nobody    47433  47432  0 00:14 ?        00:00:00 nginx: worker process
  4. root      47438  47405  0 00:14 pts/1    00:00:00 grep --color=auto nginx
  5. [root@Darian1 nginx]#
复制代码

​        Master 进程会去管理每一个 worker 进程。当客户端发起一个请求的时候,它会由 worker 进程去处理惩罚,而不是由 Master 进程去处理惩罚。如果有多个 worker 进程的时候,一个请求过来,多个 worker 会有竞争。每一个进程会去争抢得到这样的一个许可。
​        相当于多个 worker 进程 构成一个集群去实现,每一个 worker 进程后边是多路复用。
Nginx 配置几个进程

末了支持的就是 CPU 数 * 进程数
  1. # 用户组,这个用户组是当前 Linux 的用户组。和用户账号
  2. #user  nobody;         
  3. # Nginx 工作进程数, 建议设置成我们的 CPU 总核心数。
  4. worker_processes  1;   
  5. #error_log  logs/error.log;
  6. #error_log  logs/error.log  notice;
  7. #error_log  logs/error.log  info;
  8. #pid        logs/nginx.pid;
  9. events {
  10.     # io 模型
  11.     use epoll ;  
  12.     # 理论上  processes* connections
  13.     worker_connections  1024;  
  14. }
复制代码
  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.     # 媒体类型,
  12.     include       mime.types;
  13.     # 默认的配置是二进制字节流
  14.     default_type  application/octet-stream;
  15.     # 日志格式,命名,把日志放到某一个文件里边,然后用 Kafka 收集起来,最后做分析
  16.     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
  17.         '$status $body_bytes_sent "$http_referer" '
  18.         '"$http_user_agent" "$http_x_forwarded_for"';
  19.     # 访问日志,每一个请求都会记录一个日志
  20.     #access_log  logs/access.log  main;
  21.     # 是否开启 0 拷贝模式,我们传输文件 0 拷贝效率高
  22.     sendfile        on;
  23.     # tcp 超时时间
  24.     #tcp_nopush     on;
  25.     #keepalive_timeout  0;
  26.     keepalive_timeout  65;
  27.     # 扫描这个目录下的配置文件
  28.     include    extra/*.conf;
  29.     # 是否打开 gzip
  30.     gzip on;
  31.     # 超过多长长度再进行压缩
  32.     gzip_min_length 5K;
  33.     # 压缩的等级越高,压缩后的文件越小,占用的 CPU 越高
  34.     gzip_comp_level 3;
  35.     # 对哪些文件去做压缩
  36.     gzip_types application/javascript image/jpeg;
  37.     # 设置缓冲区,按照我们我们指定大小的倍数去申请内存,
  38.     # 按照我们原始文件的大小,以 32K 为单位的四倍去申请内存。
  39.     gzip_buffers 4 32k;
  40.     # 是否传输 “vary: Accept-Encoding” 的文件头标志
  41.     # 根据客户端的头去判断我们是不是要去做压缩。
  42.     gzip_vary on;
  43. }
复制代码
Nginx 的高可用方案


​        这模型的整个吞吐量是有限的。一旦大了以后,就会崩溃
​        Nginx 作为反向代理服务器,所有的流量都会经过 Nginx,所以 Nginx 自己的可靠性是我们起首要思量的问题。

​        问题: HTTP Server 之间的同步,出现问题的切换,DNS 是没有办法解决的。
​        通过 Nginx 去代理后端应用的服务器。Nginx 对外是一个 IP 地址,七层负载,做一个转发,通过应用层的 URI 做一些转发。 我可以做 IP_Hash 、轮询、权重 ... ... 各种方式去做转发。
​        Nginx 性能比 Tomcat 高得多得多。高性能的反向代理服务器。(DNS 是对域名做解析的。)通过 Nginx 做一个集群。

​        我们为了制止单点故障,就需要解决 Nginx 的单点问题!!!

​        我一个请求过来,会根据它的一个 IP + 端口号 做一个转发,转发以后,后续请求,不是通过 F5 去做一个返回。而是直接返回,只是通过 F5 做一个解析而已。 F5 的性能 Nginx 更高。

流量问题,不能纯靠技术问题去解决。
www.baidu.com 它是可以分发到不同的站点的,叫做 地域服务器
在北京访问北京的机房。其他的地方,访问其他地方的机房。
流量是无限的。我们需要通过 多机房,地域来解析。
把你的请求转发到离你最近的服务器上。
keepalived

keeppalived 可以生成 虚拟IP  ( vip )。
​         Keepalived 是 Linux 下一个轻量级别的高可用解决方案,Keepalived 软件起初是专为 LVS 负载均衡软件 设计的,用来管理并监控 LVS 集群体系中各个服务节点的状态,厥后又加入了可以实现高可用的 VRRP 功能。因此,Keepalived 除了能够管理 LVS 软件外,还可以作为其他服务(例如:Nginx、Haproxy、MySQL 等)的高可用解决方案软件。
​        Keepalived 软件主要是通过 VRRP 协议实现高可用功能的。VRRP 是 Virtual Router RedundancyProtocol (虚拟路由器冗余协议)的缩写,VRRP 出现的目的就是为相识决静态路由单点故障问题的,它能够包管当个别节点宕机时,整个网络可以不间断地运行;(简单来说,vrrp 就是把两台或多台路由器设备虚拟成一个设备, 实现主备高可用)。(它是虚拟 IP )
​        所以,Keepalived 一方面具有配置管理 LVS 的功能,同时还具有对 LVS 下面节点举行康健检查的功能,另一方面也可实现体系网络服务的高可用功能。
​        LVS 是 Linux Virtual Server 的缩写,也就是 Linux 虚拟服务器,在 linux2.4 内核以后,已经完全内置了 LVS 的各个功能模块。
​        它是工作在四层的负载均衡,雷同于 Haproxy, 主要用于实现对服务器集群的负载均衡。
​        关于四层负载,我们知道 osi 网络层次模型的 7 层模型(应用层、体现层、会话层、传输层、网络层、数据链路层、物理层);四层负载就是基于传输层,也就是 ip+端口 的负载;而七层负载就是需要基于 URL 等应用层的信息来做负载,同时另有二层负载(基于 MAC)、三层负载(IP);
常见的四层负载有:LVS、F5 ; 七层负载有 : Nginx、HAproxy ; 在软件层面,
Nginx / LVS / HAProxy  是利用得比较广泛的三种负载均衡软件
对于中小型的 Web 应用,可以利用 Nginx、大型网站大概紧张的服务并且服务比较多的时候,可以思量利用 LVS
轻量级的高可用解决方案

​        LVS 四层负载均衡软件(Linux virtual server) 监控 lvs 集群体系中的各个服务节点的状态VRRP         协议(虚拟路由冗余协议) linux2.4 以后,是内置在 linux 内核中的
lvs(四层) -> HAproxy 七层
lvs(四层) -> Nginx(七层)

实践

安装步调

版本,2.0.7  其他版本会有问题。
  1. [root@Darian1 software]# tar -zxvf keepalived-2.0.11.tar.gz
  2. [root@Darian1 software]# mkdir keepalived
  3. [root@Darian1 software]# cd keepalived-2.0.11/
  4. [root@Darian1 keepalived-2.0.11]# ./configure --prefix=/software/keepalived --sysconf=/etc
  5. configure: error:
  6. !!! OpenSSL is not properly installed on your system. !!!
  7. !!! Can not include OpenSSL headers files.            !!!
  8. [root@Darian1 keepalived-2.0.11]# yum install openssl-devel
  9. Is this ok [y/d/N]: y
  10. *** WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.
  11. [root@Darian1 keepalived-2.0.11]# yum install libnl libnl-devel
  12. [root@Darian1 keepalived-2.0.11]# yum install gcc
  13. [root@Darian1 keepalived-2.0.11]# ./configure --prefix=/software/keepalived --sysconf=/etc
  14. configure: error: libnfnetlink headers missing
  15. [root@Darian3 keepalived-2.0.7]# yum install -y libnfnetlink-devel
  16. [root@Darian1 keepalived-2.0.7]# make && make install
  17. [root@Darian3 software]# mkdir keepalived
  18. [root@Darian1 keepalived]# cd ../keepalived
  19. [root@Darian1 keepalived]# ln -s sbin/keepalived /sbin
  20. [root@Darian1 keepalived]# cp /software/keepalived-2.0.7/keepalived/etc/init.d/keepalived /etc/init.d
  21. [root@Darian1 keepalived]# chkconfig --add keepalived
  22. [root@Darian1 keepalived]# chkconfig keepalived on
  23. 注意:正在将请求转发到“systemctl enable keepalived.service”。
  24. Created symlink from /etc/systemd/system/multi-user.target.wants/keepalived.service to /usr/lib/systemd/system/keepalived.service.
  25. [root@Darian1 keepalived]# service keepalived start
  26. [root@Darian1 keepalived]# service keepalived status
复制代码

请立马配置 keepalived 的日记

keepalived 的配置
  1. [root@Darian1 keepalived]# vim /etc/keepalived/keepalived.conf
  2. ! Configuration File for keepalived
  3. # 配置一些全局的东西
  4. global_defs {
  5.    # 邮箱的配置, 当 keepalived 发生错误的时候,发送到你的邮箱里边
  6.    notification_email {
  7.      acassen@firewall.loc
  8.      failover@firewall.loc
  9.      sysadmin@firewall.loc
  10.    }
  11.    notification_email_from Alexandre.Cassen@firewall.loc
  12.    smtp_server 192.168.200.1
  13.    smtp_connect_timeout 30
  14.    router_id LVS_DEVEL
  15.    vrrp_skip_check_adv_addr
  16.    vrrp_strict
  17.    vrrp_garp_interval 0
  18.    vrrp_gna_interval 0
  19. }
  20. # 虚拟的路由的冗余协议
  21. vrrp_instance VI_1 {
  22.     state MASTER
  23.     interface eth0
  24.     virtual_router_id 51
  25.     priority 100
  26.     advert_int 1
  27.     authentication {
  28.         auth_type PASS
  29.         auth_pass 1111
  30.     }
  31.     # 配置多个虚拟 IP 地址
  32.     virtual_ipaddress {
  33.         192.168.200.16
  34.         192.168.200.17
  35.         192.168.200.18
  36.     }
  37. }
  38. # 虚拟的服务,就是我们的 LVS  了,就是我们对外的一个虚拟的 IP 地址的配置的映射,默认 443 是对 HTTPS 的一个映射,
  39. virtual_server 192.168.200.100 443 {
  40.     delay_loop 6
  41.     lb_algo rr
  42.     lb_kind NAT
  43.     persistence_timeout 50
  44.     protocol TCP
  45.     # 这里是真实服务的一个配置
  46.     real_server 192.168.201.100 443 {
  47.         weight 1
  48.         SSL_GET {
  49.             url {
  50.               path /
  51.               digest ff20ad2481f97b1754ef3e12ecd3a9cc
  52.             }
  53.             url {
  54.               path /mrtg/
  55.               digest 9b3a0c85a887a256d6939da88aabd8cd
  56.             }
  57.             connect_timeout 3
  58.             retry 3
  59.             delay_before_retry 3
  60.         }
  61.     }
  62. }
  63. virtual_server 10.10.10.2 1358 {
  64.     delay_loop 6
  65.     lb_algo rr
  66.     lb_kind NAT
  67.     persistence_timeout 50
  68.     protocol TCP
  69.     sorry_server 192.168.200.200 1358
  70.     real_server 192.168.200.2 1358 {
  71.         weight 1
  72.         HTTP_GET {
  73.             url {
  74.               path /testurl/test.jsp
  75.               digest 640205b7b0fc66c1ea91c463fac6334d
  76.             }
  77.             url {
  78.               path /testurl2/test.jsp
  79.               digest 640205b7b0fc66c1ea91c463fac6334d
  80.             }
  81.             url {
  82.               path /testurl3/test.jsp
  83.               digest 640205b7b0fc66c1ea91c463fac6334d
  84.             }
  85.             connect_timeout 3
  86.             retry 3
  87.             delay_before_retry 3
  88.         }
  89.     }
  90.     real_server 192.168.200.3 1358 {
  91.         weight 1
  92.         HTTP_GET {
  93.             url {
  94.               path /testurl/test.jsp
  95.               digest 640205b7b0fc66c1ea91c463fac6334c
  96.             }
  97.             url {
  98.               path /testurl2/test.jsp
  99.               digest 640205b7b0fc66c1ea91c463fac6334c
  100.             }
  101.             connect_timeout 3
  102.             retry 3
  103.             delay_before_retry 3
  104.         }
  105.     }
  106. }
  107. virtual_server 10.10.10.3 1358 {
  108.     delay_loop 3
  109.     lb_algo rr
  110.     lb_kind NAT
  111.     persistence_timeout 50
  112.     protocol TCP
  113.     real_server 192.168.200.4 1358 {
  114.         weight 1
  115.         HTTP_GET {
  116.             url {
  117.               path /testurl/test.jsp
  118.               digest 640205b7b0fc66c1ea91c463fac6334d
  119.             }
  120.             url {
  121.               path /testurl2/test.jsp
  122.               digest 640205b7b0fc66c1ea91c463fac6334d
  123.             }
  124.             url {
  125.               path /testurl3/test.jsp
  126.               digest 640205b7b0fc66c1ea91c463fac6334d
  127.             }
  128.             connect_timeout 3
  129.             retry 3
  130.             delay_before_retry 3
  131.         }
  132.     }
  133.     real_server 192.168.200.5 1358 {
  134.         weight 1
  135.         HTTP_GET {
  136.             url {
  137.               path /testurl/test.jsp
  138.               digest 640205b7b0fc66c1ea91c463fac6334d
  139.             }
  140.             url {
  141.               path /testurl2/test.jsp
  142.               digest 640205b7b0fc66c1ea91c463fac6334d
  143.             }
  144.             url {
  145.               path /testurl3/test.jsp
  146.               digest 640205b7b0fc66c1ea91c463fac6334d
  147.             }
  148.             connect_timeout 3
  149.             retry 3
  150.             delay_before_retry 3
  151.         }
  152.     }
复制代码
​        我们需要在 Keepalived 里边配置 Nginx 的一些东西。通过 Keepalived 实现了对 Nginx 的高可用,keepalived 是对 LVS 的一个检测。这个 虚拟 IP 会根据你的配置去举行映射。

master
  1. [root@Darian1 keepalived]# vim /etc/keepalived/keepalived.conf
  2. ! Configuration File for keepalived
  3. global_defs {
  4.     # 运行 keepalived 服务器的标识,在一个网络内应该是唯一的
  5.     router_id LVS_DEVEL   
  6. }
  7. # vrrp 实例定义部分
  8. vrrp_instance VI_1 {
  9.     # 设置 lvs 的状态,MASTER 和 BACKUP 两种,必须大写
  10.     state MASTER  
  11.     # 设置对外服务的接口,网卡的地址
  12.     interface ens33   
  13.     # 设置虚拟路由标示,这个标示是一个数字,同一个 vr rp 实例使用唯一标示
  14.     virtual_router_id 51   
  15.     # 定义优先级,数字越大优先级越高,在一个 vrrp——instance 下,master 的优先级必须大于 backup
  16.     priority 100
  17.     # 设定 master 与 backup 负载均衡器之间同步检查的时间间隔,单位是秒
  18.     advert_int 1
  19.     authentication {  
  20.         # 设置验证类型和密码
  21.         auth_type PASS
  22.         # 验证密码,同一个 vrrp_instance 下 MASTER 和 BACKUP 密码必须相同
  23.         auth_pass 1111   
  24.     }
  25.     virtual_ipaddress {
  26.         #设置虚拟 ip 地址,可以设置多个,每行一个
  27.         192.168.40.100
  28.     }
  29. }
  30. # 设置虚拟服务器,需要指定虚拟 ip 和服务端口
  31. virtual_server 192.168.40.100 80 {
  32.     # 健康检查时间间隔
  33.     delay_loop 6
  34.     # 负载均衡调度算法
  35.     lb_algo rr
  36.     # 负载均衡转发规则
  37.     lb_kind NAT   
  38.     # 设置会话保持时间protocol TCP #指定转发协议类型,有 TCP 和 UDP 两种
  39.     persistence_timeout 50
  40.     # 配置服务器节点 1,需要指定 real server 的真实 IP 地址和端口
  41.     real_server 192.168.40.128 80 {
  42.         # 设置权重,数字越大权重越高
  43.         weight 1  
  44.         # realserver 的状态监测设置部分单位秒,用来去检测它的状态
  45.         TCP_CHECK {  
  46.             # 超时时间
  47.             connect_timeout 3  
  48.             # 重试间隔
  49.             delay_before_retry 3
  50.             # 监测端口
  51.             connect_port 80  
  52.         }
  53.     }
  54. }
复制代码
backup

vim /etc/keepalived/keepalived.conf
  1. ! Configuration File for keepalived
  2. global_defs {
  3.    router_id LVS_DEVEL
  4. }
  5. vrrp_instance VI_1 {
  6.    state BACKUP
  7.    interface ens33
  8.    virtual_router_id 51
  9.    priority 50
  10.    advert_int 1
  11.    authentication {
  12.        auth_type PASS
  13.        auth_pass 1111
  14.    }
  15.    virtual_ipaddress {
  16.        192.168.40.100
  17.    }
  18. }
  19. virtual_server 192.168.40.100 80 {
  20.    delay_loop 6
  21.    lb_algo rr
  22.    lb_kind NAT
  23.    persistence_timeout 50
  24.    protocol TCP
  25.    real_server 192.168.40.129 80 {
  26.        weight 1
  27.        TCP_CHECK {
  28.            connect_timeout 3
  29.            delay_before_retry 3
  30.            connect_port 80
  31.        }
  32.    }
  33. }
复制代码
  1. [root@Darian1 software]# service keepalived restart
  2. Restarting keepalived (via systemctl):                     [  确定  ]
  3. [root@Darian1 software]# service keepalived status
  4. ● keepalived.service - LVS and VRRP High Availability Monitor
  5.    Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; vendor preset: disabled)
  6.    Active: active (running) since 日 2019-01-20 20:10:22 CST; 20s ago
  7.   Process: 83210 ExecStart=/software/keepalived/sbin/keepalived $KEEPALIVED_OPTIONS (code=exited, status=0/SUCCESS)
  8. Main PID: 83211 (keepalived)
  9.    CGroup: /system.slice/keepalived.service
  10.            ├─83211 /software/keepalived/sbin/keepalived -D
  11.            ├─83212 /software/keepalived/sbin/keepalived -D
  12.            └─83213 /software/keepalived/sbin/keepalived -D
  13. 1月 20 20:10:25 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  14. 1月 20 20:10:25 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  15. 1月 20 20:10:25 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  16. 1月 20 20:10:28 Darian1 Keepalived_healthcheckers[83212]: TCP connection to [192.168.40.128]:udp:80 success.
  17. 1月 20 20:10:30 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  18. 1月 20 20:10:30 Darian1 Keepalived_vrrp[83213]: (VI_1) Sending/queueing gratuitous ARPs on ens33 for 192.168.11.100
  19. 1月 20 20:10:30 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  20. 1月 20 20:10:30 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  21. 1月 20 20:10:30 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  22. 1月 20 20:10:30 Darian1 Keepalived_vrrp[83213]: Sending gratuitous ARP on ens33 for 192.168.11.100
  23. [root@Darian1 software]#
  24. [root@Darian3 software]# service keepalived restart
  25. Restarting keepalived (via systemctl):                     [  确定  ]
  26. [root@Darian3 software]#  service keepalived status
  27. ● keepalived.service - LVS and VRRP High Availability Monitor
  28.    Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; vendor preset: disabled)
  29.    Active: active (running) since 日 2019-01-20 20:12:31 CST; 15s ago
  30.   Process: 47254 ExecStart=/software/keepalived/sbin/keepalived $KEEPALIVED_OPTIONS (code=exited, status=0/SUCCESS)
  31. Main PID: 47255 (keepalived)
  32.    CGroup: /system.slice/keepalived.service
  33.            ├─47255 /software/keepalived/sbin/keepalived -D
  34.            ├─47256 /software/keepalived/sbin/keepalived -D
  35.            └─47257 /software/keepalived/sbin/keepalived -D
  36. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: (Line 3) Unexpected '{' - ignoring
  37. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: (Line 4) Unknown keyword 'router_id'
  38. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: (Line 5) Unknown keyword '}'
  39. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: Assigned address 192.168.40.129 for interface ens33
  40. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: Assigned address fe80::d3a1:60b3:dbb3:68c2 for interface ens33
  41. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: Registering gratuitous ARP shared channel
  42. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: (VI_1) removing VIPs.
  43. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: (VI_1) Entering BACKUP STATE (init)
  44. 1月 20 20:12:31 Darian3 Keepalived_vrrp[47257]: VRRP sockpool: [ifindex(2), proto(112), unicast(0), fd(8,9)]
  45. 1月 20 20:12:37 Darian3 Keepalived_healthcheckers[47256]: TCP connection to [192.168.40.129]:tcp:80 success.
  46. [root@Darian3 software]#
复制代码
Nginx 是每秒都可以抗十万的。
踩坑:

配置同一个网段,不是同一个网段,访问会有问题!!!
线程在进程之内是共享的。共享资源相互影响。
线程产生的本钱比进程低。
keepalived 日记文件配置

通过脚本实现动态切换

​         Keepalived 需要配置主备来实现动态的切换。Nginx 挂掉的时候,keepalived 也要制止掉。keepalived 的存在的意义是用来监听 Nginx 的请求。这个监听的过程实际上是通过 LVS 来转发的。需要脚原来触发。
利用步调:

  1. [root@Darian1 sbin]# vim /etc/keepalived/keepalived.conf
  2. global_defs {
  3.     # 运行 keepalived 服务器的标识,在一个网络内应该是唯一的
  4.     router_id LVS_DEVEL
  5.     enable_script_security
  6. }
  7. vrrp_script nginx_status_process {
  8.     # 实现当 Nginx 挂掉以后,keepalived 也挂掉
  9.     script "/software/nginx/sbin/nginx_status_check.sh"
  10.     # 用户的隔离,用户的运行权限,防止其他用户对这个脚本的执行
  11.     user root
  12.     # 检查频次
  13.     interval 3
  14. }
  15. # vrrp 实例定义部分
  16. vrrp_instance VI_1 {
  17.     # 设置 lvs 的状态,MASTER 和 BACKUP 两种,必须大写
  18.     state MASTER
  19.     # 设置对外服务的接口,网卡的地址
  20.     interface ens33
  21.     # 设置虚拟路由标示,这个标示是一个数字,同一个 vr rp 实例使用唯一标示
  22.     virtual_router_id 51
  23.     # 定义优先级,数字越大优先级越高,在一个 vrrp——instance 下,master 的优先级必须大于 backup
  24.     priority 100
  25.     # 设定 master 与 backup 负载均衡器之间同步检查的时间间隔,单位是秒
  26.     advert_int 1
  27.     authentication {
  28.         # 设置验证类型和密码
  29.         auth_type PASS
  30.         # 验证密码,同一个 vrrp_instance 下 MASTER 和 BACKUP 密码必须相同
  31.         auth_pass 1111
  32.     }
  33.     virtual_ipaddress {
  34.         #设置虚拟 ip 地址,可以设置多个,每行一个
  35.         192.168.40.100
  36.     }
  37.     track_script{
  38.         # 对应的 上边的 nginx_status_process
  39.         nginx_status_process
  40.     }
  41. }
  42. # 设置虚拟服务器,需要指定虚拟 ip 和服务端口
  43. virtual_server 192.168.40.100 80 {
  44.     # 健康检查时间间隔
  45.     delay_loop 6
  46.     # 负载均衡调度算法
  47.     lb_algo rr
  48.     # 负载均衡转发规则
  49.     lb_kind NAT
  50.     # 设置会话保持时间protocol TCP #指定转发协议类型,有 TCP 和 UDP 两种
  51.     persistence_timeout 50
  52.     # 配置服务器节点 1,需要指定 real server 的真实 IP 地址和端口
  53.     real_server 192.168.40.128 80 {
  54.         # 设置权重,数字越大权重越高
  55.         weight 1
  56.         # realserver 的状态监测设置部分单位秒,用来检测它的状态
  57.         TCP_CHECK {
  58.             # 超时时间
  59.             connect_timeout 3
  60.             # 重试间隔
  61.             delay_before_retry 3
  62.             # 监测端口
  63.             connect_port 80
  64.         }
  65.     }
  66. }
复制代码
  1. [root@Darian1 sbin]# vim nginx-ha-check.sh
  2. #!bin/sh   #! /bin/sh 是指此脚本使用/bin/sh 来执行
  3. A=`ps -C nginx --no-header |wc -l`
  4. if [ $A -eq 0 ]
  5. then
  6.      echo 'nginx server is died'
  7.      service keepalived stop
  8. fi
复制代码
  1. [root@Darian1 sbin]# sh nginx_status_check.sh
  2. nginx server is died
  3. Stopping keepalived (via systemctl):                       [  确定  ]
复制代码
  1. [root@Darian1 sbin]# chmod +x nginx_status_check.sh
  2. [root@Darian1 sbin]# service keepalived restart
  3. [root@Darian1 sbin]# ./nginx -s stop
复制代码

美团的 Camel
OpenResty

Nginx + lua
​         OpenResty 是一个通过 Lua 扩展 Nginx 实现的可伸缩的 Web 平台,内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理惩罚超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
安装

HelloWorld

开始第一个程序,HelloWorld
openresty/nginx/conf/nginx.conf  就是 nginx 的配置的东西。
  1. [root@Darian3 software]# cd openresty/nginx/
  2. [root@Darian3 nginx]# vim conf/nginx.conf
  3. location / {
  4.         default_type         text/html;
  5.         content_by_lua_block {
  6.             ngx.say("helloworld");
  7.     }
  8. }
  9. [root@Darian3 nginx]# ./sbin/nginx
复制代码
在 sbin 目次下实行.nginx 下令就可以运行,看到 helloworld

创建工作空间

创建目次

​        大概为了不影响默认的安装目次,我们可以创建一个独立的空间来训练,先在安装目次下创建 demo 目次,安装目次为 /data/program/openresty/demo
mkdir demo
​        然后在 demo 目次下创建两个子目次,一个是 logs 、一个是 conf
创建配置文件

实行:./nginx -p /data/program/openresty/demo 【-p 主要是指明 nginx 启动时的配置目次】
  1. [root@Darian1 openresty]# mkdir demo
  2. [root@Darian1 openresty]# cd demo/
  3. [root@Darian1 demo]# mkdir conf
  4. [root@Darian1 demo]# mkdir logs
  5. [root@Darian1 demo]# cd conf/
  6. [root@Darian1 conf]# vim nginx.conf
  7. worker_processes 1;
  8. error_log logs/error.log;
  9. events {
  10.    worker_connections 1024;
  11. }
  12. http {
  13.    server {
  14.        listen 8888;
  15.        location / {
  16.            default_type text/html;
  17.            content_by_lua_block {
  18.                ngx.say("Hello world")
  19.            }
  20.        }
  21.    }
  22. }
  23. [root@Darian1 conf]# cd ../../nginx/sbin/
  24. [root@Darian1 sbin]# ./nginx -p /software/openresty/demo/
复制代码


总结

​        我们刚刚通过一个 helloworld 的简单案例来演示了 nginx + lua 的功能,其中用到了 ngx.say 这个表达式,通过在 content_by_lua_block 这个片段中举行访问;这个表达式属于 ngx_lua 模块提供的 api, 用于向客户端输出一个内容。
​         我们配置了多个 模块,就会有固定的顺序。
写一个完全做认证的模块
  1. [root@Darian1 openresty]# cd demo/conf/
  2. [root@Darian1 conf]# mkdir lua
  3. [root@Darian1 conf]# cd lua
  4. [root@Darian1 lua]# vim add.lua
  5. local args = ngx.req.get_uri_args();
  6. ngx.say(args.a + args.b);
  7.                      
  8. [root@Darian1 lua]# vim params.lua
  9. local _M = {}
  10. function _M.is_number(...)
  11.     local arg = {...}
  12.     local num;
  13.     for i,v in ipairs(arg) do
  14.         num=tonumber(v);
  15.         if nil == num then
  16.             return false;
  17.         end
  18.     end
  19.         return true;
  20. end
  21.     return _M;
  22. [root@Darian1 lua]#  vim check.lua
  23. local param=require("params");
  24. local args=ngx.req.get_uri_args();
  25. if not args.a or not args.b or not param.is_number(args.a, args.b) then
  26.     ngx.exit(ngx.HTTP_BAD_REQUEST);
  27.     return;
  28. end
  29. [root@Darian1 lua]# vim ../nginx.conf
  30. worker_processes 1;
  31. error_log logs/error.log;
  32. events {
  33.     worker_connections 1024;
  34. }
  35. http {
  36.     lua_package_path '$prefix/lua/?.lua';
  37.     lua_code_cache off;
  38.     server {
  39.         listen 80;
  40.         location ~ ^/api/([-_a-zA-Z0_9]+) {
  41.             access_by_lua_file lua/check.lua;
  42.             content_by_lua_file lua/$1.lua;
  43.         }
  44.     }
  45. }
  46. [root@Darian1 lua]# cd ../../../nginx/sbin/
  47. [root@Darian1 sbin]# history   
  48. [root@Darian1 sbin]# ./nginx -p /software/openresty/demo/
  49.    
  50. nginx: [alert] lua_code_cache is off; this will hurt performance in /software/openresty/demo/conf/nginx.conf:11
  51.    
复制代码
​        在 lua 里边有模块的概念,有包的概念。我可以把公共的代码放到一个文件里边。以 API 的方式去提供。可以把他作为一个方法。
​        正常地来说,我们会有一个 lua 文件夹,按照我们的需求去写。
​        我可以利用 lua 写一些复杂的逻辑。可以写业务代码的。
注意:

lua 目次在 demo 目次下 openresty/demo/lua/sub.lua


库文件利用

​        通过上面的案例,我们基本上对 OpenResty 有了一个更深的认识,其中我们用到了自界说的 lua 模块。实际上 openresty 提供了很丰富的模块。让我们在实现某些场景的时候更加方便。可以在 /openresty/lualib 目次下看到;比如在 resty 目次下可以看到 redis.lua、mysql.lua 这样的利用 redis 和利用数据库的模块。
利用 redis 模块连接 redis
  1. worker_processes 1;
  2. error_log           
  3. logs/error.log; events {
  4.     worker_connections 1024;
  5. }
  6. http {
  7.     lua_package_path '$prefix/lualib/?.lua;;'; # 添加”;;”表示默认路径下的lualib
  8.     lua_package_cpath '$prefix/lualib/?.so;;';
  9. server {
  10.     location /demo {
  11.         content_by_lua_block {
  12.             local redisModule=require "resty.redis";
  13.             local redis=redisModule:new();   # lua 的对象实例
  14.             redis:set_timeout(1000);
  15.             ngx.say("===begin connect redis server");
  16.             local ok,err = redis:connect("127.0.0.1",6379);   #连接 redis
  17.             if not ok then
  18.                 ngx.say("==connection redis failed,error message:",err);
  19.             end
  20.                 ngx.say("==begin set key and value");
  21.                 ok,err=redis:set("hello","world");
  22.             if not ok then
  23.                 ngx.say("set value failed");
  24.                 return;
  25.             end
  26.                 ngx.say("===set value result:",ok);
  27.                 redis:close();
  28.             }
  29.         }
  30.     }
  31. }
复制代码
演示效果

到 nginx 路径下实行 ./nginx -p /data/program/openresty/redisdemo 在浏览器中输入:http://192.168.11.160/demo即可看到输出内容并且连接到 redis 服务器上以后,可以看到 redis 上的结果
redis 的所有下令利用,在 lua 中都有提供相应的利用。比如 redis:get(“key”)、
redis:set()等
网关

​        通过扩展以后,在实际过程中应该怎么去应用呢?一般的利用场景: 网关、​web 防火墙、缓存服务器(对响应内容举行缓存,淘汰到达后端的请求,来提升性能),接下来重点讲讲网关的概念以及如何通过 Openresty 实现网关开发。
网关的概念

​        从一个房间到另一个房间,必须要经过一扇门,同样,从一个网络向另一个网络发送信息,必须经过一道“关口”,这道关口就是网关。顾名思义,网关(Gateway) 就是一个网络连接到另一个网络的“关口”。
​        那什么是 API 网关呢?
​        在微服务流行起来之前,api 网关就一直存在,最主要的应用场景就是开放平台, 也就是 open api; 这种场景大家打仗的一定比较多,比如阿里的开放平台;当微服务流行起来以后,api 网关就成了上层应用集成的标配组件。
​        比如说,支付包地址会有一个网关,做一个统一的路由转发。
为什么需要网关?

对微服务组件地址举行统一抽象

​        API 网关意味着你要把 API 网关放到你的微服务的最前端,并且要让 API 网关酿成由应用所发起的每个请求的入口。这样就可以简化实现客户端和微服务应用程序之间的沟通方式。
Backends for frontends


​        当服务越来越多以后,我们需要思量一个问题,就是对某些服务举行安全校验以及用户身份校验。甚至包括对流量举行控制。 我们会对需要做流控、需要做身份认证的服务单独提供认证功能,但是服务越来越多以后,会发现很多组件的校验是重复的。这些东西很显着不是每个微服务组件需要去关心的事情。微服务组件只需要负责接收请求以及返回响应即可。可以把身份认证、流控都放在 API 网关层来举行控制。
​        针对于 app 大概 web 等分别做不同的网关。不同的客户端是不同的验证、不同的方式。
网关的作用

OpenResty 实现 API 网关限流及登录授权

OpenResty 为什么能做网关?
​        前面我们相识到了网关的作用,通过网关,可以对 api 访问的前置利用举行统一的管理,比如鉴权、限流、负载均衡、日记收集、请求分片等。所以 API 网关的核心是所有客户端对接后端服务之前,都需要统一接入网关,通过网关层将所有非业务功能举行处理惩罚。
​        OpenResty 为什么能实现网关呢? OpenResty 有一个非常紧张的因素是,对于每一个请求,Openresty 会把请求分为不同阶段,从而可以让第三方模块通过挂载行为来实现不同阶段的自界说行为。而这样的机制能够让我们非常方便地设计 api 网关。

​        Nginx 自己在处理惩罚一个用户请求时,会按照不同的阶段举行处理惩罚,总共会分为 11 个阶段。而 openresty 的实行指令,就是在这 11 个步调中挂载 lua 实行脚本实现扩展,我们分别看看每个指令的作用。
initbylua : 当 Nginx master 进程加载 nginx 配置文件时会运行这段 lua 脚本,一般用来注册全局变量大概预加载 lua 模块
initwokerby_lua: 每个 Nginx worker 进程启动时会实行的 lua 脚本,可以用来做康健检查
setbylua:设置一个变量
rewritebylua:在 rewrite 阶段实行,为每个请求实行指定的 lua 脚本
accessbylua:为每个请求在访问阶段调用 lua 脚本
contentbylua:前面演示过,通过 lua 脚本生成 content 输出给 http 响应
balancerbylua:实现动态负载均衡,如果不是走 contentbylua,则走 proxy_pass,再通过 upstream 举行转发
headerfilterby_lua: 通过 lua 来设置 headers 大概 cookie
bodyfilterby_lua:对响应数据举行过滤
logbylua : 在 log 阶段实行的脚本,一般用来做数据统计,将请求数据传输到后端举行分析
zuul 的 filter 也是雷同的实现。
灰度发布

​        在单一架构中,随着代码量和业务量不断扩大,版本迭代会逐步酿成一个很困难的事情,哪怕是一点小的修改,都必须要对整个应用重新摆设。 但是在微服务中, 各个模块是一个独立运行的组件,版本迭代会很方便,影响面很小。
​        同时,微服务化的组件节点,对于我们去实现灰度发布(金丝雀发布:将一部分流量引导到新的版本)来说,也会变得很简单;
​        还可以有白名单,比如说 QQ 的升级改造计划,针对你升级。
​        所以通过 API 网关,可以对指定调用的微服务版本,通过版原来隔离。如下图所示。

灰度发布的实现

  1.    [root@Darian1 openresty]# mkdir gray
  2.    [root@Darian1 openresty]# cd gray
  3.    [root@Darian1 gray]# mkdir lua
  4.    [root@Darian1 gray]# mkdir logs
  5.    [root@Darian1 gray]# mkdir conf
  6.    [root@Darian1 gray]# cd conf/
  7.    
  8.    worker_processes 1;
  9.    error_log      logs/error.log;
  10.    
  11.    events{
  12.        worker_connections 1024;
  13.    }
  14.    http{
  15.        lua_package_path "$prefix/lualib/?.lua;;";
  16.        lua_package_cpath "$prefix/lualib/?.so;;";
  17.        upstream prod {
  18.            server 192.168.40.128:8080;
  19.        }
  20.        upstream pre {
  21.            server 192.168.40.129:8080;
  22.        }
  23.        server {
  24.            listen  80;
  25.            server_name localhost;
  26.            location /api {
  27.                content_by_lua_file lua/gray.lua;
  28.            }
  29.            location @prod {
  30.                proxy_pass http://prod;
  31.            }
  32.            location @pre {
  33.                proxy_pass http://pre;
  34.            }
  35.        }
  36.    }
  37.       
  38.    
  39.    [root@Darian1 conf]# cd ../lua/
  40.    [root@Darian1 lua]# vim gray.lua
复制代码
  1.    local redis=require "resty.redis";
  2.    local red=redis:new();
  3.    red:set_timeout(1000);
  4.    
  5.    local ok,err=red:connect("192.168.40.128",6379);
  6.    
  7.    if not ok then
  8.        ngx.say("failed to connect redis",err);
  9.        return;
  10.    end
  11.    
  12.    local headers=ngx.req.get_headers()
  13.    local local_ip=headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or ngx.var.remote_addr
  14.    
  15.    local ip_lists=red:get("gray");
  16.    if ip_lists ~= nil and  string.find(ip_lists,local_ip) == nil then
  17.        ngx.exec("@prod");
  18.    else
  19.        ngx.exec("@pre");
  20.    end
  21.        local ok,err=red:close();
复制代码
  1. [root@Darian1 sbin]# ./nginx  -p ../../gray
  2. [root@Darian1 bin]# ./redis-server ../../redis-3.2.8/redis.conf
  3. [root@Darian1 bin]# ./redis-cli
  4. 127.0.0.1:6379> set gray 192.168.23.66
  5. OK
  6. 127.0.0.1:6379> set gray 192.168.40.1
  7. OK
复制代码

高可用踩坑:

记得网卡配置精确。

OpenResty/Demo/conf/nginx.conf 的配置文件
  1. worker_processes 1;
  2. error_log logs/error.log;
  3. events {
  4.     worker_connections 1024;
  5. }
  6. http {
  7.     server {
  8.         listen 8888;
  9.         location / {
  10.             default_type text/html;
  11.             content_by_lua_block {
  12.                 local args = ngx.req.get_uri_args();
  13.                 ngx.say("Hello world");
  14.             }
  15.         }
  16.         location /sub {
  17.             content_by_lua_block{
  18.                 local args = ngx.req.get_uri_args();
  19.                 ngx.say(args.a-args.b);
  20.             }
  21.         }
  22.     }
  23. }
复制代码
  1. worker_processes 1;
  2. error_log      logs/error.log;
  3. events{  
  4.     worker_connections 1024;
  5. }
  6. http{
  7.     # 两个分号,表示默认路径下
  8.     lua_package_path "$prefix/lualib/?.lua;;";
  9.     lua_package_cpath "$prefix/lualib/?.so;;";
  10.     upstream prod {
  11.         server 192.168.11.156:8080;
  12.     }
  13.     upstream pre {
  14.         server 192.168.11.156:8081;
  15.     }
  16.     server {
  17.         listen  80;
  18.         server_name localhost;
  19.         location /api {
  20.             content_by_lua_file lua/gray.lua;
  21.         }
  22.         location @prod {
  23.             proxy_pass http://prod;
  24.         }
  25.         location @pre {
  26.             proxy_pass http://pre;
  27.         }
  28.     }
  29.     server {
  30.         listen 8080;
  31.         location / {
  32.             content_by_lua_block {
  33.                 ngx.say("I'm prod env");
  34.             }
  35.         }
  36.     }
  37.     server {
  38.         listen 8081;
  39.         location / {
  40.             content_by_lua_block {
  41.                 ngx.say("I'm pre env");
  42.             }
  43.         }
  44.     }
  45. }
复制代码
原文链接:https://javaguide.net 微信公众号:不止极客

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4