1. 域名解析
一个域名一定会被解析为一个或多个ip,一般包含两步:
本地域名解析
浏览器会首先在本机的hosts文件中查找域名映射的IP地址,如果找到就返回IP,没找到则进行域名服务器解析,一般本地解析都会失败,因为默认这个文件是空的。
Windows下的hosts文件地址:C:/windows/system32/drivers/etc/hosts
Linux下的hosts文件所在路径: /etc/hosts
域名服务器解析
本地解析失败,才会进行域名服务器解析,域名服务器就是网络中的一台计算机,里面记录了所有注册备案的域名和IP映射关系,一般只要域名是正确的,并且备案通过,一定能找到。
2. Nginx简介
是一个WEB服务器,是一个高性能的反向代理的服务器、还是一个负载均衡服务器,同时还可以实现动静分离。
特点:在高并发和处理静态资源上相对于tomcat有更多优势.
什么是反向代理
正向代理:客户端先进行代理服务器的设置,客户端发送请求到代理服务器,代理服务器将请求转发至原始服务器。代理服务器所代理的对象是很多个客户端。
反向代理:对于客户而言反向代理就像原始服务器,客户不需要作任何设置,客户端发送请求,直接发送到代理服务器,代理服务器判断向何处转发请求,并将获得的内容返回给客户端。反向代理是对多个服务器进行代理
什么是负载均衡
可以按照调度规则实现动态、静态页面分离,可以按照轮询、ip哈希、权重等多种方式实现将请求平均分配到后端服务器上
3. docker安装
3.1 拉取镜像
docker pull nginx
3.2 启动容器
docker run -d –name mynginx1 -p 80:80 nginx bash
配置文件在/etc/nginx/nginx.conf,默认没有vi命令
拷贝nginx目录到宿主机:
docker cp mynginx1:/etc/nginx /opt/nginx
docker cp mynginx1:/usr/share/nginx/html /usr/share/nginx/html
删除容器:docker stop mynginx1–》docker rm mynginx1
启动容器并添加数据卷:
docker run -v /opt/data/nginx:/etc/nginx -di –name mynginx -p 80:80 nginx
yum安装
安装yum仓库 yum-utils
1
2可以不执行,当出现版本问题时,再进行更新
sudo yum install yum-utils -y创建/etc/yum.repos.d/nginx.repo文件,
1
vi /etc/yum.repos.d/nginx.repo
内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=truenginx-stable:稳定版的信息。一般情况下使用此版本
nginx-mainline:主力版本(或开发版本),如果想要安装此版本,可以先使用如下命令,再安装
使用stable版本,下面这句话不要执行
1
2使用stable版本,下面这句话不要执行
sudo yum-config-manager --enable nginx-mainline安装
1
sudo yum install nginx -y
启动测试
1
nginx
在windows主机上输入 http://192.168.33.10
其它命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14停止
nginx -s stop
重启
nginx -s reopen
检查是否有语法错误
nginx -t
重新加载
nginx -s reload
查看版本
nginx -V 或nginx -v
查看80端口的程序
netstat –ano | grep 80
卸载Nginx
yum remove nginx
关闭防火墙 (需要重启):chkconfig iptables off
卸载步骤:
1 | 卸载时 |
其它Linux版本的安装请参考以下文档:
http://nginx.org/en/linux_packages.html#RHEL-CentOS
配置文件位置
/etc/nginx
主配置文件 ngixn.conf
每个服务器配置的conf.d目录下
主启动页:/usr/share/nginx/html
四、nginx信号量
1. 工作模式
nginx是一个多进程/多线程高性能web服务器,在linux系统中,nginx启动后会以后台守护进程(daemon)的方式去运行,后台进程包含一个master进程和多个worker进程(可以通过在nginx.conf配置文件中配置worker_processes参数设置),可以充分利用多核架构。
nginx默认的工作模式是以多进程的方式来工作的,nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式。nginx在启动之后会有一个master进程和多个worker进程(默认是一个),多个worker子进程将监听同一个端口,并行处理请求。worker 进程数应该设置为等于 CPU 的核数,高流量并发场合也可以考虑将进程数提高至 CPU 核数 * 2。
master主进程主要用来管理worker进程,主要作用是:读取并验正配置信息,管理真正提供服务的worker进程,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。master进程不会对用户请求提供服务,而用户的请求则是worker进程来响应的。
nginx是通过信号来控制,比如关闭,重启等去控制nginx进程。nginx信号是属于nginx进程间的通信的一种机制,比如master主进程控制多个worker子进程,也是通过信号控制的,如下图。
2. 信号量
信号控制语法
kill -信号选项 nginx的主进程号
- TERM,INT:快速关闭
- QUIT :从容关闭(优雅的关闭进程,即等请求结束后再关闭)
- HUP :平滑重启,重新加载配置文件 (平滑重启,修改配置文件之后不用重启服务器。直接kill -PUT 进程号即可)
- USR1 :重新读取日志文件,在切割日志时用途较大(停止写入老日志文件,打开新日志文件,之所以这样是因为老日志文件就算修改的文件名,由于inode的原因,nginx还会一直往老的日志文件写入数据)
- USR2 :平滑升级可执行程序 ,nginx升级时候用
- WINCH :优雅的关闭旧的进程(配合上USR2来进行升级)
1 | 查找nginx.pid |
五、nginx的配置
1. main 全局配置
nginx在运行时与具体业务功能(比如http服务或者email服务代理)无关的一些参数,比如工作进程数,运行的身份等。
1 | # 指定nginx进程使用什么用户启动,默认是nobody |
2. events模块
1 | events { |
3. http服务器
1 | include是个主模块指令,实现对配置文件所包含的文件的设定,可以减少主配置文件的复杂度。 |
3.1 客户端head缓存
1 | 服务器名字的hash表大小 |
3.2 FastCGI参数
FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。
1 | 指定连接到后端FastCGI的超时时间。 |
3.3 gzip模块设置
1 | 开启gzip压缩输出 |
4. nginx 配置虚拟主机
4.1 配置虚拟主机流程
1:拷贝一段完整的server段,并放入http标签内
2:更改server_name以及对应网页的root根目录
3:创建server_name 对应网页的根目录,如果没有index首页会出现404错误。
4:对客户端server_name 的主机做host 解析或DNS配置。
5:浏览器访问,或者在Linux客户端做host解析,用wget或curl 访问。
1 | server { |
如果出现502,503错误,尝试临时关闭SELinux后再测试。
1 | 临时关闭SELinux |
如果出现403错误,用以下方式解决
- 看log,查看路径是否正确
- 如果路径正确,则确认配置文件中用户是什么,修改和当前用户匹配(如果当前用户为root,请也将用户改成root)。
4.2 location模块语法规则
location的语法规则有两种:前缀字符串(路径名)和正则表达式
- 前缀字符串
1 | 匹配以/some/path/开头的路径,如:/some/path/domt.html |
正则表达式
正则表达式前加上“
”表示区分大小写,加上”*”表示不区分大小写※当使用插入符时“^~”则表示只匹配前缀字符串,不匹配正则表达式
location [=|||^~] /uri/ { … }*
- = 精确匹配,如果找到匹配=号的内容,立即停止搜索,并立即处理请求(优先级最高)
- ~ 区分大小写
- ~* 不区分大小写
- ^~ 只匹配字符串,不匹配正则表达式
- / 通用匹配,任何请求都会匹配到
1 | #匹配跟目录 |
六、nginx动静分离
1. 什么是动静分离
在Web开发中,通常来说,动态资源其实就是指那些后台资源,而静态资源就是指HTML、JavaScript、CSS、img等文件。
动静分离就是将动态资源和静态资源分开,将静态资源部署在Nginx上。当一个请求来的时候,如果是静态资源的请求,就直接到nginx配置的静态资源目录下面获取资源,如果是动态资源的请求,nginx利用反向代理的原理,把请求转发给后台应用去处理,从而实现动静分离。
优点:
- 可以很大程度的提升静态资源的访问速度。
- 前后端可以并行开发、有效地提高开发效率。
2. nginx结合tomcat实现动静分离
项目准备
编写一个带图片的index.html,放置在/opt/project/emp目录中。
图片fruit01.jpg放入/opt/project/static/img目录中
1 |
|
nginx配置
思路:动、静态的文件,请求时匹配不同的目录
当访问gif,jpeg时 直接访问/opt/project/static/目录下内容,正则自行配置
1 | user root; |
测试
图片能够正常加载
通过以下语句测试图片的正常加载
1 | curl -I http://localhost/static/img/fruit01.jpg |
七、nginx反向代理、负载均衡
1. 什么是反向代理
- 代理:通过客户机的配置,实现让一台服务器代理客户机,客户的所有请求都交给代理服务器处理
- 反向代理:用一台服务器,代理真实服务器,用户访问时,不是访问真实的服务器,而是访问代理服务器。
Nginx可以当作反向代理服务来使用时,我们需要提前在Nginx中配置好反向代理的规则,不同的请求,交给不同的真实服务器处理。当请求到达nginx,nginx会根据已经定义的规则进行请求的转发,从而实现路由功能。
安装在主机上
安装在虚拟机上
2. Nginx反向代理Tocat
拷贝配置文件
将/etc/nginx/conf.d目录下的default.conf拷贝一份,并命名成my.conf
1 | 进入配置server的目录 |
my.conf的修改
使用proxy_pass来设置反向代理的服务器
1 |
|
修改nginx.conf
/etc/nginx/nginx.conf中的http节点中修改以下内容
1 | 修改内容 |
3. 负载均衡
upstream模块
nginx 的负载均衡功能依赖于 ngx_http_upstream_module模块,所支持的代理方式有 proxy_pass(一般用于反向代理).fastcgi_pass(一般用于和动态程序交互),memcached_pass,proxy_next_upstream,fastcig_next_pass 以及memcached_next_pass 。
upstream 模块应该放于http{}标签内。
1 | upstream dynamic { |
my.conf
1 | proxy_pass http://tc; |
负载均衡策略
轮询(rr):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器故障,故障系统自动清除,使用户访问不受影响。适用于多个服务器的性能相当的情况下,适用此策略。
轮询权值(weight),weight值越大,分配到的访问几率越高,主要用于后端每个服务器性能不均的情况。
ip_hash,每个请求按访问IP的hash结果分配(IP地址的前三段),这样来自同一个IP的固定访问一个后端服务器,主要解决动态网站session共享的问题。 192.168.40.xxx
url_hash,按照访问的URL的hash结果来分配请求,是每个URL定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率,nginx本身不支持,如果想使用需要安装nginx的hash软件包。
server模块的写法
server IP 调度状态
server指令指定后端服务器IP地址和端口,同时还可以设定每个后端服务器在负载均衡调度中的状态。
- down 表示当前的server暂时不参与负载均衡。
- backup 预留的备份服务器,当其他所有的非backup服务器出现故障或者忙的时候,才会请求backup机器,因为这台集群的压力最小。
- max_fails 允许请求失败的次数,默认是1,当超过最大次数时,返回proxy_next_upstream模块定义的错误。0表示禁止失败尝试,企业场景:2-3.京东1次,蓝汛10次,根据业务需求去配置。
- fail_timeout,在经历了max_fails次失败后,暂停服务的时间。京东是3s,蓝汛是3s,根据业务需求配置。常规业务2-3秒合理。
vue项目的发布
开发或者测试环境的确认
执行打包命令 npm run build:prod
把dist文件夹放入centos 的 /opt/dist目录
放入vagrant共享目录, vagrant reload读取文件,通过cp命令copy到opt目录下
修改nginx的配置(server段)
1 | #nginx.conf |
八、session共享
1.ip_hash
缺点:
- 分配不均匀。
- 如果后端还作了其他负载均衡,就不能共享session
2.tomcat会话复制
会话数据会存储在每个服务器上的堆内存中
2.1 实现步骤
在每一个tomcat中添加集群缓存配置
在tomcat的conf中找到server.xml,在
这一行下面添加下面内容: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto" port="4000" autoBind="100" selectorTimeout="5000" maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/" watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>在每个项目的web.xml中添加下面标签
1
<distributable/>
2.2 缺点
- 因为每个服务器都存储一份session,所以数据冗余
- 如果某个服务器内存很小,可能无法存储。
3.会话共享
推荐使用Spring Session方案,主流, 会话存储在远程的redis缓存中.
3.1 实现原理
客户端第一次发请求时,没有携带sessionID,nginx将请求分发给服务器1 ,然后服务器1 产生session0,spring 对sesion0封装成sesion1,并根据session0计算并更新session1的id,然后 放入redis中,并把session0的原始ID回写到浏览器,这样服务器1 和redis中都会有一个相同的session1
当客户端发送第二次请求的时候,nginx将请求分发给服务器2 (无session),因为请求中携带了一个sessionID,那么服务器2 就根据sessionID得出session1的id,用这个id去redis中获取session。
3.2 实现步骤
建两个springboot项目,内容如下,除了端口号不同
两个项目的pom依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
</dependencies>templates目录添加login.html
1
2
3
4<form action="/login" method="post">
<input name="username"><br>
<input type="submit">
</form>templates目录添加success.html
1
2
3<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<h1>this is session1</h1>
<span th:text="${session.username}"></span>yml内容如下,注意:另一项目端口为8080
1
2
3
4
5
6
7
8
9server:
port: 80
spring:
redis:
host: 127.0.0.1
port: 6379
jedis:
pool:
max-idle: 8config包下添加类
1
2
3
4
5
6
7@Configuration
public class MyConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/showSuc").setViewName("success");
registry.addViewController("/showLogin").setViewName("login");
}
}controller包中添加类
@Controller public class UserCtl { @RequestMapping("/login") public String hello(HttpSession session, String username){ session.setAttribute("username",username); //注意:这里的session已不是传统session,被重构成新的session,存储在redis中 System.out.println("name:"+username+",sessionID:"+session.getId()); return "success"; } }
主类添加注解
//使用该注解,会重构session,参数为session存活时间 @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 10000*30) @SpringBootApplication public class SessionApp { public static void main(String[] args) { SpringApplication.run(SessionApp.class,args); } }
nginx中
修改配置
1
2
3
4
5
6
7
8
9location / {
root /opt/project/emp;
index index.html index.htm;
proxy_pass http://tc;
}
upstream tc{
server 192.168.1.144:80;
server 192.168.1.144:8080;
}重启nginx
/usr/local/nginx/sbin/nginx -s reload
启动redis: redis-server redis.conf
启动80和8080两个端口的项目
测试