nginx的作用?
搭建http服务器、做集群/负载均衡(减轻单台服务器的压力)、反向代理(多台服务器集群可以使用nginx做反向代理并且不暴露真实ip地址)、防盗链/黑白名单、解决跨域问题(搭建接口网关)、防ddos、虚拟服务器(可以实现在一台服务器虚拟出多个网站)、静态服务器(访问静态资源)、
nginx占内存小、轻量级服务器
分布式、微服务、高并发、高可用、消息中间件
类型nginx反向代理的服务器有lvs、F5(硬件)、Haproxy
目录结构
conf配置文件,配置信息都在这个nginx.conf里面配
html存放静态资源
启动,双击nginx即可,注意路径不要有中文。双击后查看logs error.log没有报错就说明开启了
访问 127.0.0.1:80,看到下面图片就说明开启成功了
在html目录下存放一个hello.html,里面随便写点东西
单台服务器承受不住高并发的压力会扛不住宕机或者延迟请求
高并发解决方案?
集群、负载均衡
什么是反向代理?
客户端发起请求,首先到nginx服务器,通过nginx服务器进行负载均衡转发到某个服务器上去。还有个好处是不会暴露公网ip,通过转发进行隐藏,十分安全。nginx服务器与代理服务器需要在同一个局域网
负载均衡有哪些算法?
1、权重
2、轮询机制(常用这个)
3、IP绑定
集群会产生什么问题?
session共享问题(多个JVM)、分步式job幂等性问题(就是重复问题,如并发生成订单号)、分布式生成全局id(分布式锁)
如何解决订单号幂等性问题?
提前生成好,存放在redis中,快用完马上生成一批新的id,在同一时刻只允许生成一个订单号
集群如何实现?
实现nginx实现负载均衡,反向代理是不暴露真实ip,注意区分。
集群的目的是减轻单台服务器的压力。
nginx反向代理工作流程:客户端先访问nginx的80端口,nginx转发到某个服务器项目地址
分布式的概念是将一个项目拆分成多个子项目,目的是完成同一个大体的功能,如拆分成会员、订单、支付、消息、前端系统
分布式开发:RPC远程调用技术
一开始单点应用,馒馒人多了演变成了面向服务架构开发SOA,在演化成微服务架构(区分springboot和springcloud)
说了那么多,那么开始吧
conf目录下找到nginx.conf,配置集群之前先配置反向代理,在配置负载均衡
为了方便实验,在host文件中添加两个域名a.a.com和b.b.com
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost
127.0.0.1 a.a.com
127.0.0.1 b.b.com
这时候我们可以用a.a.com:8080/index进行访问
这时我不想要8080端口,我想用80端口进行访问,但是此时80端口被nginx占用了,但我们可以用nginx帮我们去做转发
如何配置?我们可以在配置文件下边一点的位置新增一段配置,server_name改成a.a.com,并且location 为/, 表示拦截所有a.a.com:80的访问,proxy_pass为转发路径
server {
listen 80;
server_name a.a.com;
location / {
proxy_pass http://127.0.0.1:8080;
index index.html index.htm;
}
}
这时候我们直接访问http://a.a.com就是等于访问http://a.a.com:8080,原理是nginx服务器帮我们做了反向代理
负载均衡的作用?
提高网站的吞吐量
负载均衡算法?
轮询机制(比如我访问一次到你访问一次进行轮替)、权重(比例分配,比如我两次你一次进行轮替)、ip绑定(只让一个ip地址进行访问,解决session共享问题,没用)
理解2分钟,配置2秒钟
轮询机制配置,在刚刚配的server上面加个upstream backserver配置,proxy_pass 改成backserver
# 轮询机制
upstream backserver {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 80;
server_name a.a.com;
location / {
proxy_pass http://backserver;
index index.html index.htm;
}
}
我们启动两个相同的项目,端口号分别为8080和8081
用任务管理器关掉nginx.exe,再重新打开nginx.exe
重新访问http://a.a.com/index,可以看到轮询访问两个端口
权重策略,指定轮询几率,weight和访问比率成正比
upstream backserver {
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
}
ip绑定策略,每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。换句话说,就是一个客户端访问8080端口后,就一直访问8080端口,不会访问其他服务器了。
upstream backserver {
ip_hash;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
如果哪一天某个服务器挂了,那么访问将不是会有灾难性后果?就举上面的例子,8080端口挂了,8081在运行,那么用户访问将有50%的概率访问不到页面?
不会的,nginx会有宕机容错机制,一主一备或者多主多备方式。需要自己配置
如果某个web服务器挂了,会有web服务器备机
如果主nginx挂了,还有nginx备机
如果主备机全挂了,使用keepalived重启web服务器或者nginx
如果重启N次仍挂了,发送警报邮件给运维人员。
这才是高可用,不要再说手动重启了,切记切记
keepalived在linux中讲吧
这里主要是nginx配置,那么我们开始实现,集群某台服务器宕机,自动轮询到下一台服务器
之前已经配置好集群了,在这基础上稍微加一点东西即可
添加超时响应proxy_connect_timeout等即可,超过1s自动轮询
# 轮询机制
upstream backserver {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 80;
server_name a.a.com;
location / {
proxy_pass http://backserver;
index index.html index.htm;
# 添加超时配置
proxy_connect_timeout 1;
proxy_send_timeout 1;
proxy_read_timeout 1;
}
}
暂时停掉8081端口服务器,重新测试访问,将会都访问到8080端口
发布版本的时候服务器能访问吗?我们的第一感觉是不能的,但是为什么csdn、淘宝等这些大网站经常在更新网站,我们却感受不到宕机呢?
大致实现思路就是主备宕机容错机制,有多台服务器,主服务器在更新,用户会访问到备服务器。
其实眼界放大一点,可以这么来看,主集群在更新,备用集群启动进行服务,是相当大型的架构,进行统一管理
此外,还要考虑一个问题,tomcat在发布版本的时候,session会失效,因为jvm重启了,那如何解决呢?
请使用redis,或者持久化到数据库中。因此尽量不使用jvm内置缓存机制,分布式架构中难以统一管理。
解决跨域问题,之前在博客里挖了坑现在填回来,闭关修炼(二十四)浅入了解跨域问题
跨域问题简单的说在域名a.a.com下是不能访问其他域名的如b.b.com,aja访问请求的域名和浏览器访问的域名不相同。
目前主流解决方案还是使用nginx
先模拟出跨域问题,在A项目放一个静态图片,B项目静态页面去访问
A项目resources下创建static目录,里面放一张1.jpg
【假装我是1.jpg】
B项目resources下创建static目录,创建kuayu.html
<html>
<head>
<title>$跨域测试$title>
head>
<script src="http://libs.baidu.com/jquery/1.7.2/jquery.min.js">script>
<script type="text/javascript">
$(document).ready(function (){
$.ajax({
type : "GET",
async : false,
url : "http://a.a.com:8080/1.jpg",
dataType : "json",
})
})
script>
<body>
body>
html>
访问http://b.b.com:8081/kuayu.html,模拟出跨域问题,可以看到ajax请求被限制了
这时我们可以,使用nginx网关拦截请求,进行转发,来解决跨域问题,原理是将项目反向代理到同一个域名下
换句话说,举个例子:如访问c.c.com/a就是访问a.a.com,访问c.c.com/b就是访问b.b.com,c.c.com是新设的域名,那么b.b.com要访问a.a.com就通过c.c.com/a进行反向代理访问
修改nginx.conf,让nginx监听c.c.com域名,location /a和/b分别做拦截进行转发,注意proxy_pass地址最后面不要少了/
server {
listen 80;
server_name c.c.com;
location /a {
# 注意8080后面/不要少了
proxy_pass http://a.a.com:8080/;
index index.html index.htm;
}
location /b {
proxy_pass http://b.b.com:8081/;
index index.html index.htm;
}
}
启动nginx,测试c.c.com/a和c.c.com/b项目是否能正常访问,如果不能说明nginx.conf配置错了,或者host设置错了。
然后将b项目的图片url请求地址改成c域名下
<html>
<head>
<title>$跨域测试$title>
head>
<script src="http://libs.baidu.com/jquery/1.7.2/jquery.min.js">script>
<script type="text/javascript">
$(document).ready(function (){
$.ajax({
type : "GET",
async : false,
url : "http://c.c.com/a/1.jpg",
dataType : "json",
})
})
script>
<body>
body>
html>
访问测试b项目,ajax访问a项目的1.jpg,成功跨域访问
docker run -d --name nginx01 -p 80:80 nginx
创建目录用来挂载文件
mkdir -p /docker/nginx01/{conf,html,logs}
将配置文件拷贝出来
docker cp nginx01:/etc/nginx/nginx.conf /docker/nginx01/conf
cp 命令代表复制
nginx01是我们nginx容器名
/etc/nginx/nginx.conf 是容器内部nginx.conf 路径
停止容器
docker stop nginx01
移除容器
docker rm nginx01
重新创建容器,这里挂成800端口,80端口得备案…
docker run -d --name nginx01 -p 800:80 -v /docker/nginx01/conf/nginx.conf:/etc/nginx/nginx.conf -v /docker/nginx01/logs:/var/log/nginx --privileged=true nginx
执行docker exec -it nginx01 /bin/bash
进入容器内部
进入到nginx容器内部后,我们可以cd /etc/nginx
,可以看到相关的nginx配置文件都在/etc/nginx目录下
keepalived作用是宕机服务器重启脚本,发送邮件给运维,心跳检测,自动执行脚本
nginx宕机带来的错误是致命性的,并且其中部署的服务都是内网ip,端口不暴露,不允许访问外网,只有nginx暴露外网ip地址,同时部署的服务器和nginx又在同一个局域网,客户端将无法访问到服务器了。
主nginx和备nginx一般在同一个局域网内,keepalived服务器和主备nginx建立通信,形成虚拟keepalived ip地址,类似于哨兵机制。
这是一主一备的形式,还有一主多备,因此要使用keepalived监听nginx,至少得有2台nginx,那么我们就先创建两个nginx
说了那么多,那我们开始吧~
自己写Dockerfile吧,用他们压缩的docker镜像各种环境不齐我都想死了
nano Dockerfile
FROM centos:7.8.2003
ENV LANG=zh_CN.UTF-8 \
LANGUAGE=zh_CN:zh \
LC_ALL=zh_CN.UTF-8
# Install tools
RUN yum update -y && \
yum reinstall -y glibc-common && \
yum install -y telnet net-tools && \
yum clean all && \
rm -rf /tmp/* rm -rf /var/cache/yum/* && \
localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8 && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# Define default command.
CMD ["bash"]
创建自己的yore/centos7_v1镜像
docker build -t yore/centos7_v1 .
build好了查看本地镜像
docker images
启动镜像,注意要用特权模式启动
docker run -p 800:80 --privileged=true --net=host --cap-add NET_ADMIN --cap-add SYS_ADMIN -it -d --name="centos01" yore/centos7_v1:latest /usr/sbin/init
docker exec -it centos01 /bin/bash
【Master容器内】
[Master容器内]
yum install -y nano
yum -y install initscripts
安装gcc
yum install -y gcc openssl-devel popt-devel
安装keepalive
yum install keepalived
安装Nginx[Master容器内]
#使用yum安装nginx需要包括Nginx的库,安装Nginx的库
rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
# 使用下面命令安装nginx
yum install nginx
#安装网络包(需要使用ifconfig和ping命令)
yum install net-tools
[修改keepalived配置]
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
rm -rf /etc/keepalived/keepalived.conf
nano /etc/keepalived/keepalived.conf
! Configuration File for keepalived
vrrp_script chk_nginx {
script "/etc/keepalived/nginx_check.sh"
##(检测脚本执行的间隔)
interval 1
weight -20
}
vrrp_instance VI_1 {
state MASTER # 备份服务器上将 MASTER 改为 BACKUP
interface eth0 //网卡
virtual_router_id 41 # 主、备机的 virtual_router_id 必须相同
priority 100 # 主、备机取不同的优先级,主机值较大,备份机值较小
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
chk_nginx
}
virtual_ipaddress {
192.168.1.140
}
}
nano /etc/keepalived/nginx_check.sh
#检测nginx是否存活的脚本
A=`ps -ef | grep nginx | grep -v grep | wc -l`
if [ $A -eq 0 ];then
nginx
sleep 1
if [ `ps -ef | grep nginx | grep -v grep | wc -l` -eq 0 ];then
#killall keepalived
ps -ef|grep keepalived|grep -v grep|awk '{print $2}'|xargs kill -9
fi
fi
chmod 755 /etc/keepalived/nginx_check.sh
[启动keepalived]
#重新加载配置
systemctl daemon-reload
#启动keepalived服务
systemctl start keepalived.service
#查看当前状态
systemctl status keepalived.service
修改Nginx默认页面
nano /usr/share/nginx/html/index.html
keepalived测试
ip addr
查看是否绑定虚拟ip,v-ip
nginx测试
curl 172.17.0.4
ctrl+p+q退出
保存Docker Master镜像
#查看刚运行的容器ID -> a61cee4dafe6
docker ps|grep "centos01";
#提交容器镜像到本地
docker commit a61cee4dafe6 keepalived_master:v1
#查看当前镜像
docker images;
【slave容器】
创建容器
docker run -p 801:80 --privileged=true --net=host --cap-add NET_ADMIN --cap-add SYS_ADMIN -it -d --name="keepalived_slave01" keepalived_master:v1 /usr/sbin/init
#进入[Slave]这个容器
docker exec -it keepalived_slave01 bash
(按照上面的步骤安装好环境,因为是用master的镜像已经配好就不用了)
修改Slave容器的keepalived配置
nano /etc/keepalived/keepalived.conf
# 修改这两项
state BACKUP # 备份服务器上将 MASTER 改为 BACKUP
priority 99 # 主、备机取不同的优先级,主机值较大,备份机值较小
重新加载keepalived配置、重启、查看状态【Slave容器】
#重新加载配置
systemctl daemon-reload
#启动keepalived服务
systemctl start keepalived.service
#查看当前状态
systemctl status keepalived.service
修改Nginx默认页面
nano /usr/share/nginx/html/index.html
Slave测试
ip addr
测试nginx
curl 192.168.0.6
测试用例
1、
我们可以进行测试,还是需要进入到容器中,首先看一下俩台机器的ip addr 命令下 都会出现一个虚拟ip,我们可以停掉,一个机器的keepalived,然后测试,命令:service keepalived stop。结果发现当前停掉的机器已经不可用,keepalived会自动切换到另一台机器上
在master 容器输入
service keepalived stop
回到slave容器输入
ip addr
我们看到keepalived会自动切换到slave的机器上
2、
我们可以测试在nginx出现问题的情况下,实现切换,这个时候我们只需要把nginx的配置文件进行修改,让其变得不可用,然后强杀掉nginx进程即可,发现也会实现自动切换服务器节点。
ps -ef | grep nginx
ps -ef | grep keepalived
3、
service keepalived stop
强制关闭
pkill nginx
再次启动
service keepalived start
nginx自动重启
Keepalived配置重载(reload)
kill -HUP $(cat /var/run/keepalived.pid)
写在后面:
当然host主机自身也可以配keepalived,这里都用docker,容器本来就可以看作是一台虚拟机
注意一下一些问题:
在尝试部署keepalived容器之前,主机必须允许ipv4地址的非本地绑定。为此,请配置sysctl tunable net.ipv4.ip_nonlocal_bind=1。
除了启用非本地绑定之外,还必须同时使用主机网络(–net=host)和安全设置CAP_NET_ADMIN(–cap-add NET_ADMIN)来运行容器。这些使容器可以管理主机的网络配置,这对于keepalived功能至关重要。