流程图
“
技术栈:docker + nginx + jdk + tomcat
背景
一般来说,一个公司不可能只部署一个服务,如果是这个服务某些原因挂了,导致引起客诉。
也很少只部署一台机器上,假如这台机器宕机…,也会引起客诉。
所以当服务并发请求量较大时,一台服务器处理不过来,所以就需要加多台服务器,所以就有了集群。
但是对于这么多发服务器,我们怎么知道用户请求到了哪台机器,如果是请求到了这台机器,下一次打到别的机器,有需要重新验证吗?
所以这个时候就有了nginx负载均衡功能,负载均衡的方式有几种,这是是设置weight权重模式。可以配置服务器权重;配置低的服务器就设置低权重。
所以这里简单实现一个负载均衡,通过docker拉去2个jdk镜像+1个nginx镜像。用脚本形式启动。相当于实现了反向代理的功能。
目标:两台tomcat放在2个jdk镜像里面,1个nginx镜像
目的:通过浏览器成功访问80,nginx负载均衡访问两台tomcat服务器。
具体步骤:
docker
登录harbor
仓库,docker
拉取jdk
,nginx
镜像- 编写3个脚本挂起3个镜像。一个
nginx
镜像脚本,两个jdk镜像脚本(2个tomcat
放里面)。通过脚本启动服务。 - 配置
nginx
和tomcat
的端口
先看效果:通过访问80端口,代理8080和8090端口,实现nginx负载均衡
访问nginx端口 |
---|
8080端口 |
8090端口 |
“
之前通过阿里云服务器linux系统上,通过原生配置nginx+3台tomcat可以实现负载均衡。
现在通过虚拟机上docker 拉取镜像,配置负载均衡。
一、环境准备
1.1 安装环境(docker)
yum update
yum-config-manager
--add-repo
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce-19.03.11
systemctl start docker
systemctl enable docker
mkdir -p /etc/docker
cd /etc/docker/
cat >> /etc/docker/daemon.json <<EOF
{
"insecure-registries":["10.249.0.137:80","10.252.0.209:80","10.252.0.29:5000","10.245.0.253:5000"],
"log-driver": "json-file",
"log-opts": {
"max-size": "1024m",
"max-file": "1"
}
}
EOF
systemctl daemon-reload && systemctl restart docker
1.2 登录harbor镜像仓库,拉取镜像
[root@localhost ~]# docker login 10.249.0.137:80
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
[root@localhost ~]# docker pull 10.249.0.137/base/jdk-1.8:20210202
[root@localhost ~]# docker pull 10.249.0.137/base/nginx:1.13.8
1.3 通过编写脚本启动镜像
通过编写脚本启动镜。这么做的目的是方便知道,当你容器内做了修改,然后你宿主机也会发生改变。
新建jdk,jdk2脚本,并且进入容器里面。docker exec -it 容器名
1.4 编写jdk1脚本
在/opt/script/setup/jdk
目录下,进行设置jdk1脚本
[root@localhost jdk]# pwd
/opt/script/setup/jdk
[root@localhost jdk]# vim install.sh
# !/bin/bash
# 编写作者: 千羽的编程时光
# 程序说明:自动创建容器、并分配固定IP及开放端口
# ---------------------------------------------------------------------------
#
#设置容器相关变量
cname="test-jdk"
name="jdk1.8"
logs="/opt/data/"${cname}"/"
#创建目录
mkdir -p ${logs}
port1="8080"
#启动容器
echo -e "Start "${cname}" Container"
docker run -d -it -p ${port1}:${port1} --privileged=true --restart=always --name ${cname} --hostname ${name} -v ${logs}:/opt/data 10.249.0.137:80/base/jdk-1.8:20210202
保存退出 esc
,:wq!
使脚本生效,启动脚本
[root@localhost jdk]# chmod +x install.sh
[root@localhost jdk]# ls
install.sh
[root@localhost jdk]# ./install.sh
Start test-jdk Container
6add9e8b81d6cbd6ee7ddc6da9e50b4629c2ce58f2383c7a912c4b7403610c19
[root@localhost jdk]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6add9e8b81d6 10.249.0.137:80/base/jdk-1.8:20210202 "/usr/sbin/sshd -D" 6 seconds ago Up 5 seconds 22/tcp, 0.0.0.0:8080->8080/tcp test-jdk
1.5 配置tomcat1
这里的通过把二进制包tomcat包上传到挂载目录(即存放到镜像里面),然后进入到镜像里面进行配置tomcat
当你把二进制包tomcat1丢进去挂载目录,相当于镜像里面也上传了一份tomcat1
[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root 220 7月 22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月 22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]#
修改tomcat的配置文件,改端口
[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root 220 7月 22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月 22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]# cd apache-tomcat-8.5.41
[root@localhost conf]# vim server.xml
<Connector port="8000" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8" />
启动tomcat
1.6 编写jdk2脚本
[root@localhost setup]# pwd
/opt/script/setup
[root@localhost setup]# ll
总用量 0
drwxr-xr-x. 2 root root 24 7月 22 14:14 jdk
drwxr-xr-x. 2 root root 24 7月 22 16:01 jdk2
drwxr-xr-x. 3 root root 77 7月 22 17:49 nginx
[root@localhost setup]#
进入java目录下:
cd /opt/script/setup/jdk
通过脚本启动容器
[root@localhost jdk]# vim install.sh
# !/bin/bash
# 编写作者: 千羽的编程时光
# 程序说明:自动创建容器、并分配固定IP及开放端口
# ---------------------------------------------------------------------------
# 设置容器相关变量
cname="test-jdk2"
name="jdk1.8"
logs="/opt/data/"${cname}"/"
#创建目录
mkdir -p ${logs}
port1="8090"
#启动容器
echo -e "Start "${cname}" Container"
docker run -d -it -p ${port1}:${port1} --privileged=true --restart=always --name ${cname} --hostname ${name} -v ${logs}:/opt/data 10.249.0.137:80/base/jdk-1.8:20210202
启动脚本
[root@localhost jdk2]# vim install.sh
[root@localhost jdk2]# pwd
/opt/script/setup/jdk2
[root@localhost jdk2]# ll
总用量 4
-rwxr-xr-x. 1 root root 868 7月 22 15:59 install.sh
[root@localhost jdk2]# ./install.sh
1.7 配置tomcat2
[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root 220 7月 22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月 22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]#
修改tomcat的配置文件,改端口
[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root 220 7月 22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月 22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]# cd apache-tomcat-8.5.41
[root@localhost conf]# vim server.xml
<Connector port="8090" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8" />
启动tomcat
二、编写nginx 脚本,启动nginx镜像
[root@localhost nginx]# pwd
/opt/script/setup/nginx
[root@localhost nginx]# vim install.sh
nginx脚本install.sh
#!/bin/bash
# 编写作者:千羽的编程时光
# 程序说明:虚拟主机启动时自动执行脚本,实现ovs初始化、增加IP路由、固定容器IP、端口开放等。
# ---------------------------------------------------------------------------
cname="test-nginx"
port1="80"
log="/opt/data/"${cname}
mkdir -p ${log}/conf
mkdir -p ${log}/data
cp -r nginx.conf ${log}/conf
cp -r html ${log}
docker run -it -d -v ${log}/conf/nginx.conf:/etc/nginx/nginx.conf -v ${log}/html:/usr/share/nginx/html -v ${log}/data:/opt/data --name ${cname} --hostname ${cname} -p ${port1}:${port1} --restart=always --privileged 10.249.0.137:80/base/nginx:1.13.8
修改nginx.conf 配置文件
[root@localhost conf]# pwd
/opt/data/test-nginx/conf
[root@localhost conf]# vim nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
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 /etc/nginx/conf.d/*.conf;
upstream backserver {
# ip_hash;
server 10.8.46.197:8080;
server 10.8.46.197:8090;
}
server{
listen 80;
server_name 10.8.46.197;
index index.html index.htm index.php;
location /{
proxy_pass http://backserver;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
fastcgi_buffer_size 512k;
fastcgi_buffers 6 512k;
fastcgi_busy_buffers_size 512k;
fastcgi_temp_file_write_size 512k;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
}
}
启动脚本
[root@localhost nginx]# ll
总用量 8
drwxr-xr-x. 2 root root 6 7月 22 13:48 html
-rwxr-xr-x. 1 root root 975 7月 22 17:40 install.sh
-rw-r--r--. 1 root root 1527 7月 26 09:13 nginx.conf
[root@localhost nginx]# ./install.sh
[root@localhost nginx]# docker stop test-nginx
test-nginx
[root@localhost nginx]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9451c839f840 10.249.0.137:80/base/jdk-1.8:20210202 "/usr/sbin/sshd -D" 16 hours ago Up 16 hours tomcat
c761e01333ba 10.249.0.137:80/base/jdk-1.8:20210202 "/usr/sbin/sshd -D" 3 days ago Up 16 hours 22/tcp, 0.0.0.0:8090->8090/tcp, :::8090->8090/tcp test-jdk2
6add9e8b81d6 10.249.0.137:80/base/jdk-1.8:20210202 "/usr/sbin/sshd -D" 3 days ago Up 16 hours 22/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp test-jdk
[root@localhost nginx]# docker rm test-nginx
查看主机端口映射
netstat -a
# 服务器端口 容器端口
iptables -t nat -D DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8081
-D 删除
-A 覆盖
iptables -t nat -A DOCKER -p tcp --dport 8082 -j DNAT --to-destination 172.17.0.4:8082
查看容器端口
[root@jdk1 conf]# ss -ntl
验证
访问nginx端口80 | 8080端口 | 8090端口 |
---|---|---|
- 先访问:8080
- 再访问:8090
- 最后通过访问80,看看效果。
八股文相关:
1.负载均衡,先知道什么是正向代理和反向代理
- 正向代理,代理的是用户(翻墙)
- 反向代理,代理的是服务器
2.nginx实现负载均衡的几种方式
轮询 | 默认方式 |
---|---|
weight | 权重方式 |
ip_hash | 依据ip分配方式 |
least_conn | 最少连接方式 |
fair(第三方) | 响应时间方式 |
url_hash(第三方) | 依据URL分配方式 |
- 轮询(默认)
- 缺省配置就是轮询策略。
- 此策略适合服务器配置相当,无状态且短平快的服务使用。
- 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
- 场景:在轮询中,如果服务器down掉了,会自动剔除该服务器。
upstream backserver {
# ip_hash;
server 10.8.46.197:8080;
server 10.8.46.197:8090;
}
- weight权重指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
upstream backserver {
权重越高,在被访问的概率越大,如上例,分别是30%,70%。
server 10.8.46.197:8080 weight=3;
server 10.8.46.197:8090 weight=7;
}- 权重越高分配到需要处理的请求越多。
- weight权重可以与least_conn和ip_hash结合使用。
- 比较适合服务器的硬件配置差别比较大的情况。
- 场景:
- 负载均衡系统中,如果用户在某台服务器A登录了,用户第二次请求时会请求到服务器b,这样导致用户登录信息将会丢失,可以采用ip_hash指令解决这个问题,如果客户访问服务器A,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。场景:
upstream backserver {
ip_hash;
server 10.8.46.197:8080 weight=3;
server 10.8.46.197:8090 weight=7;
}- ip_hash不能与backup同时使用。
- 适合有状态服务,比如session。
- 当有服务器需要剔除,必须手动down掉。
- least_conn
- 把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
upstream backserver {
注意:此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。
least_conn; #把请求转发给连接数较少的后端服务器
server localhost:8080 weight=2; #tomcat 7.0
server localhost:8081; #tomcat 8.0
server localhost:8082 backup; #tomcat 8.5
server localhost:8083 max_fails=3 fail_timeout=20s; #tomcat 9.0
}
- 把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
- fair(第三方) 按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backserver {
server 10.8.46.197:8080;
server 10.8.46.197:80907;
fair;
} - url_hash(第三方) 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
upstream backserver {
每个设备的状态设置为:
server 10.8.46.197:8080;
server 10.8.46.197:80907;
hash $request_uri;
hash_method crc32;
}- down 表示单前的server暂时不参与负载
- weight 默认为1.weight越大,负载的权重就越大。
max_fails
:允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream
模块定义的错误fail_timeout:max_fails
次失败后,暂停的时间。- backup:其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。
3.nginx有哪些限流的方式
- Nginx的限流主要是两种方式:限制访问频率和限制并发连接数。
#速率限流配置
limit_req_zone $binary_remote_addr zone=ipRateLimit:10m rate=2r/s;
#并发量限流-单个IP控制
limit_conn_zone $binary_remote_addr zone=perip:10m;
#并发量限流-整个服务控制
limit_conn_zone $server_name zone=perserver:10m;
server {
listen 80;
server_name localhost;
location ~ .*.(woff|ico|css|js|gif|jpg|jpeg|png)$ {
root /usr/local/openrestyDir/pages/;
}
location /msitems/ {
#限流配置
#limit_req zone=ipRateLimit burst=5 nodelay;
#并发量限流
limit_conn perip 20;
limit_conn perserver 100;
root /usr/local/openrestyDir/pages/;
}
}
参考文献:
- 实现负载均衡的几种方式:http://aijishu.com/a/1060000000008890
- Nginx服务器之6种负载均衡策略:https://blog.csdn.net/xiaren_1988/article/details/123007245
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/213291.html