引言
一个项目搭建
问题1:客户端到底要将请求发送给哪台服务器?
问题2:如果所有客户端都将请求发送给了服务器1,怎么办?
问题3:客户端可能会请求动态资源 或者 静态资源,如果只请求静态资源,那么还让服务器处理是否占用资源了?
服务器搭建集群后
为什么要学习Nginx?它有效的解决了上面3个问题。
问题1:Nginx会接受用户的请求,再做转发,所以客户端只需要向Nginx发起请求。
问题2:Nginx通过算法指定将请求发送到哪个服务器上,比如:轮循算法 就是按顺序1 2 1 2。
问题3:Nginx可以实现动静分离,动态资源请求交给服务器,静态资源自身就可以处理。
服务器搭建集群,并用Nginx做反向代理
Nginx介绍
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
特点:
- 能够支持 50,000 个并发连接数的响应。(tomcat默认支持150个并发量)
- 稳定性极强,可以 24小时不间断的工作。
- 占用内存小
- Nginx提供了非常丰富的配置实例,学习成本低。
二、Nginx的安装
# 创建维护 nginx服务的目录 [root@zxh opt]# mkdir docker_nginx [root@zxh opt]# cd docker_nginx/ [root@zxh docker_nginx]# vim docker-compose.yml # 编写 docker-compose.yml 编排文件 version: "3" services: nginx: restart: always image: daocloud.io/library/nginx:latest container_name: nginx ports: - 80:80 [root@zxh docker_nginx]# docker-compose up -d # 访问测试
cat /etc/nginx/conf.d
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; # 以上统称为全局块 # worker_processes 的数值越大,Nginx的并发能力就越强,需要根据服务器的性能进行配置,默认即可 # error_log 代表Nginx的错误日志存在的位置 # pid 保存着nginx的进程id # events块,需要根据服务器的性能进行配置,默认即可 # worker_connections 的数值越大,Nginx并发能力越强 events { worker_connections 1024; } # http块 http { # include代表引入一个外部的文件 -> mime.types中放着大量的媒体类型 include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; # include代表引入一个外部的文件 -> *.conf 是配置文件,之后的配置主要是对给目录下的文件进行修改 include /etc/nginx/conf.d/*.conf; }
include /etc/nginx/conf.d/*.conf 引入的配置文件
root@c7206ced66dc:/etc/nginx/conf.d# ls default.conf root@c7206ced66dc:/etc/nginx/conf.d# cat default.conf server { listen 80; # Nginx监听的端口 listen [::]:80; server_name localhost; # Nginx接收请求的ip,只要访问到该地址就会被nginx处理 # location块 location / { root /usr/share/nginx/html; # 接收到请求后,去该目录下查找静态资源 index index.html index.htm; # 默认去上述的路径中找 index.html 或 index.html } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
修改docker-compose文件
之后需要修改的就是这个文件,所以做好挂载
# 先停掉服务 docker-compose down # 修改配置文件为 [root@zxh docker_nginx]# vim docker-compose.yml version: "3" services: nginx: restart: always image: daocloud.io/library/nginx:latest container_name: nginx ports: - 80:80 volumes: - /opt/docker_nginx/conf.d:/etc/nginx/conf.d # 重新构建 [root@zxh conf.d]# docker-compose build # 再次启动 [root@zxh conf.d]# docker-compose up -d # 进入挂载目录,编写配置文件 [root@zxh conf.d]# pwd /opt/docker_nginx/conf.d [root@zxh conf.d]# vim default.conf ################## server{ listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } } ################## # 这样就挂在好了配置文件,方便之后修改
正向代理和反向代理的介绍
正向代理
正向代理服务器是由客户端设立的
客户端要了解代理服务器和目标服务器都是谁
帮助我们实现突破访问权限,提高访问的速度,对目标服务器隐藏客户端的 IP 地址
反向代理
反向代理服务器是配置服务端的。
客户端不知道访问的到底是那一台服务器。
可以实现负载均衡,能够隐藏服务器真正的 IP 地址。
举例:通过Nginx访问tomcat
1)创建目标服务器,我们就创建一个tomcat容器
[root@zxh opt]# mkdir docker_mysql_tomcat [root@zxh opt]# cd docker_mysql_tomcat/ [root@zxh docker_mysql_tomcat]# vim docker-compose.yml [root@zxh docker_mysql_tomcat]# cat docker-compose.yml version: '3' services: mysql: # 服务的名称 restart: always # 代表只要docker启动,那么这个容器就跟着一起启动 image: daocloud.io/library/mysql:5.7.4 # 指定镜像路径 container_name: mysql # 指定容器的名称 ports: - 3306:3306 # 指定端口号的映射 environment: MYSQL_ROOT_PASSWORD: 123456 # 指定MySQL的ROOT用户登录密码 TZ: Asia/Shanghai # 指定时区 volumes: - /opt/docker_mysql_tomcat/mysql_data:/var/lib/mysql # 映射数据卷 tomcat: restart: always image: daocloud.io/library/tomcat:8.5.15-jre8 container_name: tomcat ports: - 8080:8080 environment: TZ: Asia/Shanghai volumes: - /opt/docker_mysql_tomcat/tomcat_webapps:/usr/local/tomcat/webapps - /opt/docker_mysql_tomcat/tomcat_logs:/usr/local/tomcat/logs # 后台运行 [root@zxh docker_mysql_tomcat]# docker-compose up -d # 编写首页 [root@zxh docker_mysql_tomcat]# cd tomcat_webapps/ [root@zxh tomcat_webapps]# mkdir ROOT [root@zxh tomcat_webapps]# cd ROOT/ [root@zxh ROOT]# vim index.html [root@zxh ROOT]# cat index.html <h1>hello,lanmu!!<h1>
2)配置Nginx的反向代理
# 配置Nginx的反向代理,监听localhost:80,当接收到请求后,将其转发到 http://47.95.37.172:8080 [root@zxh docker_nginx]# cd conf.d/ [root@zxh conf.d]# vim default.conf [root@zxh conf.d]# cat default.conf server{ listen 80; server_name localhost; location / { proxy_pass http://47.69.37.172:8080; # 配置请求转发 } #location / { # root /usr/share/nginx/html; # index index.html index.htm; #} } # 重启 nginx 容器 [root@zxh conf.d]# cd .. [root@zxh docker_nginx]# docker-compose restart Restarting nginx ... done
关于Nginx的location路径映射
# 1. 等号'='匹配 location = / { # 精准匹配,主机名后面不能带任何的字符串 } # 举例:访问www.baidu.com时,nginx可以匹配,因为它是根目录 /,而访问www.baidu.com/hello时,则不能匹配,因为它的路径为 /hello,所有的匹配方式都是如此。 # 2. 通用匹配 location /xxx { # 匹配所有以/xxx开头的路径 } # 3. 正则匹配 location ~ /xxx { # 匹配所有以/xxx开头的路径 } # 4. 匹配开头的路径 location ^~ /images { # 匹配所有以/images开头的路径 } # 5. 匹配结尾的路径 location ~* \.(gif|jpg|png)$ { # 匹配以gif、jpg、png结尾的路径 } # 6. 匹配所有路径,也就是所有路径都会拦截 location / { }
优先级从大到小(location / 是匹配所有的路径,但会继续往优先级高的去匹配):
推荐按照优先级书写
实例
1)我们将之前在docker中写过的SpringBoot+redis实现访问自增的项目也启动,方便做多条路径映射
2)启动后有两个页面,一个是首页,一个自增的功能
3)现在我们用Nginx做路径映射,修改default.conf
配置文件
server{ listen 80; server_name localhost; location = /msg/send/index { proxy_pass http://47.95.37.172:8081/look; } location /msg/send { proxy_pass http://47.95.37.172:8081/; # 这里URL的结尾需要有 /,否则会404 } location ^~ /msg { proxy_pass http://47.95.37.172:8080/; # 这里URL的结尾需要有 /,否则会404 } location / { root /usr/share/nginx/html; index index.html index.htm; } }
4)重启容器
[root@zxh docker_nginx]# docker-compose restart Restarting nginx ... done
Nginx为我们提供了三种负载均衡的策略:
轮询(默认的方式)
将客户端发起请求,平均的分配给每一台服务器,也就是每台服务器处理一次请求,但是也不是0101非常有规律的,这不用去纠结。
权重(用于服务器性能不一致)
会将客户端的请求,根据服务器的权重值不同,分配不同的数量。
ip_hash
基于发起请求的客户端的IP地址不同,他始终会将请求发送到指定的服务器上。
轮询
- 这里使用 8080 和 8081 端口进行模拟多台服务器的情况。
# 1、修改nginx配置文件 [root@zxh docker_nginx]# vim conf.d/default.conf # 2、配置完成重新启动容器 [root@zxh docker_nginx]# docker-compose restart Restarting nginx ... done [root@zxh docker_nginx]# cat conf.d/default.conf upstream my-server { server 47.95.37.172:8080; server 47.95.37.172:8081; } server{ listen 80; server_name localhost; location / { proxy_pass http://my-server/; } } # 格式: =================default.conf ========================= # 自定义名称不要出现下划线 # upstream 自定义名称 { # server ip:port; # server ip:port: # ... # } upstream my-server { server 47.95.37.172:8080; server 47.95.37.172:8081; ... } server { listen 80; server_name localhost; # 格式:proxy_pass http://服务的名称/; location / { proxy_pass http://my-server/; # 注意路径最后的 /,端口号之后需要加上/ } } ================default.conf ==========================
权重
[root@zxh docker_nginx]# vim conf.d/default.conf [root@zxh docker_nginx]# docker-compose restart Restarting nginx ... done [root@zxh docker_nginx]# cat conf.d/default.conf # 只需要添加 weight=权重比例 即可,权重比例只能使用数字 upstream my-server { server 47.95.37.172:8080 weight=10; server 47.95.37.172:8081 weight=90; } server{ listen 80; server_name localhost; location / { proxy_pass http://my-server/; } }
[root@zxh docker_nginx]# vim conf.d/default.conf [root@zxh docker_nginx]# docker-compose restart Restarting nginx ... done [root@zxh docker_nginx]# cat conf.d/default.conf upstream my-server { ip_hash; # 只需要添加 ip_hash; 即可 server 47.95.37.172:8080; server 47.95.37.172:8081; } server{ listen 80; server_name localhost; location / { proxy_pass http://my-server/; } }
Nginx 的并发能力公式
- worker_processes * worker_connections / (4 | 2) = Nginx最终的并发能力
worker_processes 和 worker_connections 这两个属性在 nginx 的配置文件里看到了
为什么要除以 4或者2 呢?
如下图所示:
- 客户端请求动态资源要向服务器获取资源,那么就需要4个连接数。
- 客户端请求Nginx服务里的静态资源,只需要从自身获取资源,那么就需要2个连接数。
Nginx通过动静分离,来提升Nginx的并发能力,更快的给用户响应。
动态资源代理
# 配置如下 location / { proxy_pass 路径; }
# 配置如下 location / { root 静态资源所在的父目录路径; index 默认访问root路径下的什么资源; autoindex on; # 以列表的形式展示root目录下的所有资源 }
- 因为静态资源代理,指的是Nginx服务自带的静态资源。
- 所以需要在 Nginx服务 中创建静态资源,然后进行代理配置即可。
1、创建静态资源
# 1、修改docker配置文件,挂在Nginx容器的数据卷 [root@zxh docker_nginx]# ls conf.d docker-compose.yml [root@zxh docker_nginx]# vim docker-compose.yml [root@zxh docker_nginx]# cat docker-compose.yml version: "3" services: nginx: restart: always image: daocloud.io/library/nginx:latest container_name: nginx ports: - 80:80 volumes: - /opt/docker_nginx/conf.d/:/etc/nginx/conf.d - /opt/docker_nginx/img/:/data/img # 指定根目录下的 /data/img 目录 - /opt/docker_nginx/html/:/data/html # 指定根目录下的 /data/html 目录 # 2、先停止容器 [root@zxh docker_nginx]# docker-compose down Stopping nginx ... done Removing nginx ... done Removing network docker_nginx_default # 再重新启动,这样可以自动创建数据卷对应的目录 [root@zxh docker_nginx]# docker-compose up -d Creating network "docker_nginx_default" with the default driver Creating nginx ... done # 3、任意图片当作静态资源 [root@zxh docker_nginx]# ls conf.d docker-compose.yml html img [root@zxh docker_nginx]# mv /home/zxh/file/123\ 005.GIF img/123.GIF [root@zxh docker_nginx]# ls img 123.GIF [root@zxh docker_nginx]# vim html/index.html [root@zxh docker_nginx]# ls html index.html [root@zxh docker_nginx]# cat html/index.html <h1>hello,lanmu!</h1>
配置Nginx静态资源代理
server{ listen 80; server_name localhost; # 代理html静态资源,当请求 /html/xx 时,自动去 Nginx 容器中的 /data/html 目录中获取资源,获取不到404 location /html { root /data; # 会自动拼接为/data/html index index.html; # 请求为 /html,则默认访问 /html/index.html } # 代理到img静态资源,当请求 /img/xx 时,自动去 Nginx 容器中的 /data/img 目录中获取资源 location /img { root /data; # 会自动拼接为/data/img autoindex on; # 以目录的形式展示所有的资源 } }
引言
为什么要搭建集群呢?
一个应用有多个模块,也成为多个服务,这些服务分别搭建在不同的服务器上,这样可以保证某个服务宕掉了,其他的服务可以照常使用。
而 Nginx 集群亦是如此,如果只有一台Nginx服务,那么Nginx服务宕掉了,那么所有服务就都访问不到了,所以才需要搭建集群。
也就是解决单点故障问题。
1、怎么知道 Nginx 可用?
准备 keepalived,监听nginx的健康情况。
2、多个 Nginx服务,到底要访问哪个?
准备haproxy,提供一个虚拟的路径,统一去接收用户的请求。
搭建Nginx集群
注意ps:所有的配置文件最好是通过 vim 命令创建出来。
其中的 favicon.ico 是网页的图标,随便上传一张ico图片即可。
创建镜像文件 Dockerfile
FROM nginx: 1.13.5-alpine # 指定nginx镜像版本 RUN apk update && apk upgrade # apk 类似 yaml,该镜像版本不是centos,所以用的是apk命,更新仓库 RUN apk add --no-cache bash curl ipvsadm iproute2 openrc keepalived # 下载软件,可以看到包含了 keepalived COPY entrypoint.sh /entrypoint.sh # 复制当前目录下的一个脚本文件 RUN chmod +x /entrypoint.sh # 给脚本文件添加执行权限 CMD ["/entrypoint.sh"] # 执行脚本
entrypoint.sh
#!/bin/sh #/usr/sbin/keepalived -n -l -D -f /etc/keepalived/keepalived.conf --dont-fork --log-console & /usr/sbin/ keepalived -D -f /etc/keepalived/keepalived.conf nginx -g "daemon off;"
version: "3" services: # 主服务 nginx_master: build: context: ./ # 指定当前目录下的dockerfile dockerfile: ./Dockerfile ports: - 8081:80 # 端口映射 volumes: # 关联首页 - ./index-master.html:/usr/share/nginx/html/index.html # 关联页面图标 - ./favicon.ico:/usr/share/ngin/html/favicon.ico # 关联keepalived配置文件 - ./keepalived-master.conf:/etc/keepalived/keepalived.conf networks: static-network: # 将ip写死,保证keepalived可以正确识别 ipv4_address: 172.20.128.2 cap_add: - NET_ADMIN # 从服务 nginx_slave: build: context: ./ # 指定当前目录下的dockerfile dockerfile: ./Dockerfile ports: - 8082:80 # 端口映射 volumes: # 关联首页 - ./index-slave.html:/usr/share/nginx/html/index.html # 关联页面图标 - ./favicon.ico:/usr/share/ngin/html/favicon.ico # 关联keepalived配置文件 - ./keepalived-slave.conf:/etc/keepalived/keepalived.conf networks: static-network: ipv4_address: 172.20.128.3 cap_add: - NET_ADMIN # haproxy proxy: image: haproxy:1.7-alpine ports: # 80端口映射到haproxy的端口 - 80:6301 volumes: - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg networks: - static-network networks: static-networks: ipam: config: - subnet: 172.20.0.0/16
index-master.html
<h1>Master!!</h1>
index-slave.html
<h1>Slave!!</h1>
keepalived 主从配置
keepalived-master.conf
# 指定多久检测一次nginx的健康状态 vrrp_script cnk_nginx { script "pidof nginx" interval 2 } vrrp_instance VI_1 { state MASTER # master负责接收用户的请求,当master宕掉后才会有slave接收 interface eth0 # 容器内部的网卡名称 virtual_router_id 33 # 虚拟路由id priority 200 # 优先级 advert_int 1 authentication { auth_type PASS auth_pass letmein } virtual_ipaddress { 172.20.128.50 # 指定maste主服务的虚拟ip地址 } track_script { chk_nginx } }
keepalived-slave.conf
# 指定多久检测一次nginx的健康状态 vrrp_script cnk_nginx { script "pidof nginx" interval 2 } vrrp_instance VI_1 { state BACKUP # master负责接收用户的请求,当master宕掉后才会有slave接收 interface eth0 # 容器内部的网卡名称 virtual_router_id 33 # 虚拟路由id priority 100 # 优先级比master低 advert_int 1 authentication { auth_type PASS auth_pass letmein } virtual_ipaddress { 172.20.128.50 # 指定maste主服务的虚拟ip地址 } track_script { chk_nginx } }
haproxy.conf
g1oba1 log 127.0.0.1 local0 maxconn 4096 daemon nbproc 4 defaults log 127.0.0.1 local3 mode http option dontlognull option redispatch retries 2 maxconn 2000 balance roundrobin timeout connect 5000ms timeout client 5000ms timeout server 5000ms frontend main bind *:6301 default_backend webserver # 172.20.128.50:80 对应 keepalived-master/slave.conf 配置的虚拟路径 # 当用户访问 80端口 时,会映射到haproxy,haproxy通过下面的虚拟路径将请求交给keepalived,有keepalived 决定选择 主/从nginx。 backend webserver server ngxin_master 172.20.128.50:80 check inter 2000 rise 2 fall 5
测试
# 1、构建镜像 [root@zxh docker_nginx_cluster]# docker-compose build # 2、后台启动容器 [root@zxh docker_nginx_cluster]# docker-compose up -d Creating docker_nginx_cluster_nginx_slave_1 ... done Creating docker_nginx_cluster_proxy_1 ... done Creating docker_nginx_cluster_nginx_master_1 ... done
[root@zxh docker_nginx_cluster]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES da30c781d9b8 docker_nginx_cluster_nginx_slave "/entrypoint.sh" About a minute ago Up About a minute 0.0.0.0:8082->80/tcp docker_nginx_cluster_nginx_slave_1 c2a931441c08 haproxy:1.7-alpine "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:80->6301/tcp docker_nginx_cluster_proxy_1 adc693524c73 docker_nginx_cluster_nginx_master "/entrypoint.sh" About a minute ago Up About a minute 0.0.0.0:8081->80/tcp docker_nginx_cluster_nginx_master_1 # 停掉master节点的nginx容器 [root@zxh docker_nginx_cluster]# docker stop adc693524c73 adc69352473
再次访问 80端口,发现切换到了slave从节点。
# 重新启动容器,再次访问80端口,可以看到又切换回了 master节点 [root@zxh docker_nginx_cluster]# docker start adc693524c73 adc69352473
原文链接:https://www.cnblogs.com/zxhbk/p/14298957.html