如何实现服务器之间的协同功能呢?

通过 Nginx 提供的反向代理和负载均衡功能,可以合理的完成业务的分配,提高网站的处理能力;同时利用缓存功能,还可以将不需要实时更新的动态页面输出结果,转化为静态网页形成缓存,从而提高网站的响应速度。

代理和反向代理

代理(正向代理,目标服务器不知道谁在访问)

位于客户端和目标服务器之间,起到一个中转的作用。其实就是客户端想访问目标服务器,但是因为某些原因不能够直接访问,则把请求和目标服务器发给代理服务器,代理服务器再去请求目标服务器,把返回的响应结果返回给客户端。

反向代理(用户实际并不知道最终服务器,只是访问一个反向代理服务器而已)

客户端会把反向代理服务器当成目标服务器,向反向代理服务器发送请求后,反向代理服务器再请求内部的后端服务器,把得到的响应结果返回给客户端。

特性:

  • 安全性。反向代理具有安全性。能隐藏真实的内部服务器。

  • 功能性。正向代理主要用途是为防火墙内的局域网用户提供访问外网的途径。反向代理主要用途是将防火墙内的服务器提供给外边的用户访问,同时也可以为多个后端服务器提供负载均衡功能、缓存功能等。

反向代理服务配置

在 Nginx 配置文件中的 location 块中,这是 proxy_pass ` 指令。

server{listen 80;
 server_name test.test;
 #将本机接收到的test.test的请求全部转发到另外一台服务器192.168.78.128
 location /{
   proxy_pass http://192.168.78.128;
   #下面是其他辅助指令
   proxy_set_header Host $host; #更改来自客户端的请求头信息
   proxy_set_header X-Real_IP $remote_addr;    #用户真实访问ip
   proxy_connect_timeout 2; #配置nginx与后端服务器建立连接的超时时间
   proxy_read_timeout 2; #配置nginx向后端发出read请求的等待响应超时时间
   proxy_send_timeout 2; #配置nginx向后端服务器发出write请求的等待响应超时时间
   proxy_redirect http://www.baidu.com; #用于修改后端服务器返回的响应头中的Location和Refresh
 }}

负载均衡

负载均衡(load balance):就是将负载分摊到多个操作单元上执行,从而提高服务的可用性和响应速度。

  1. 一个没有负载均衡的 web 架构如下图:

用户直接连接服务器,这个时候如果这台服务器挂了,那么就整个网站挂了。

  1. 有负载均衡的 web 架构

用户不直接访问后端服务器,而是访问负载均衡服务器,由负载均衡服务器再次转发到后端服务器。如果这个时候有一台后端服务器挂掉了,那么负载均衡服务器会剔除掉它,将后续请求都转发到好的那台,这样就不影响网站的正常运行。这个时候我们也需要考虑负载均衡服务器会不会挂掉,那就引入第二个负载均衡服务器来缓解一下。

负载均衡的配置

通过配置负载均衡服务器的 Nginx 中的 upstream 指令可以实现。

不同负载均衡配置的特点如下图所示:

配置方式 说明
轮询方式(默认) 每个请求按照时间顺序逐一分配到不同的后端服务器,如果有服务器宕机,会自动剔除。
权重方式(weight) 利用 weight 制定轮询的权重比率,与访问率成正比,用于后端服务器性能不均的情况,性能好的服务器 weight 高一点。
ip_hash 使每个访客固定访问一个后端服务器,这样可以解决 session 共享的问题。
第三方模块(fair、url_hash)nginx 默认不包含第三方模块,使用时需要安装 第三方模块采用 fair,按照每台服务器的响应时间来分配,响应时间短的优先分配。如果第三方模块采用的是 url_hash,则安装 url 的 hash 值来分配。

一般轮询配置

server{
   listen 80;
 server_name test.test;
 location / {
   proxy_pass http://web_server; #反向代理
 }}#配置负载均衡服务器组upstream web_server {
   server 192.168.78.128;
 server 192.168.78.129;}

加权轮询配置

#配置负载均衡服务器组upstream web_server {
   server 192.168.78.128 weight=1;
 server 192.168.78.129 weight=3;}

这里面的权值总和为一个循环,这里以 4 次为一个循环,那么就是每四次请求中,三次会被分派到 129 这个服务器,一次分配到 128,但是具体三次并不会顺序执行,而是按照算法分散执行。
我们也可以设置每台 web 服务器在负载均衡调度中的状态。

upstream web_server{
   server 192.168.78.128 weight=1 max_fails=1 fail_timeout=2; #允许请求失败次数,在请求max_fail次数失败后,暂停服务的时间
 server 192.168.78.200 backup; #预留的备份服务器
 server 192.168.78.33 down; #当前服务器不参与负载均衡}

ip_hash 配置

upstream web_server{
   ip_hash;
 server 192.168.78.120;
 server 192.168.78.123;
 server 192.168.78.33 down; #如果这台服务器宕机,则用down表示当前服务器暂不参与负载均衡}

使用 ip_hash 的时候,不能使用 weight 和 backup。

第三方模块(fair)

  1. 备份已安装的 Nginx

由于使用第三方模块,需要重新编译 Nginx,所以需要关闭已经开启的 Nginx 进程,对已经安装好的 Nginx 进行备份,便于恢复。

cp -r /usr/local/nginx /usr/local/nginx_old
  1. 重新编译安装 Nginx

先从 github 获取 fair 模块,下载到 zip 到 root 目录下,解压。

unzip nginx-upstream-fair-master.zip #解压mv nginx-upstream-fair-master nginx-upstream-fair #重命名

如果没有 unzip 命令,则需要用 yum install unzip 安装。

cd  nginx-1.10.1#配置./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--add-module=/root/nginx-upstream-fair#编译安装make && make install
  1. 配置 fair 的负载均衡

打开新安装的 Nginx 配置文件,在 http 块下实现 fair 的负载均衡。

server{
   listen 80;
 server_name test.test;
 location / {
   proxy_pass http://web_server  }}upstream web_server{
   server 192.168.78.128;
 server 192.168.78.132;
 fair;     #使用fair}

缓存配置

对于一些含有大量内容的网站来说,随着访问量的增多,对于经常被访问的内容,如果每一次都从服务器中获取,则给服务器很大的压力。所以我们可以利用反向代理服务器对访问频率较多的内容进行缓存,有利于节省后端服务器的资源。

原理

web 缓存服务器位于内容源 web 服务器和客户端之间,当客户端访问一个 url 时,缓存服务器请求内容源服务器,并将响应结果缓存到内存或硬盘,当下一次请求同一个 url 时,缓存服务器直接将已缓存的内容输出给客户端,这样就减少了再次向内容源服务器请求的次数。

永久缓存配置(proxy_store)

Nginx 提供了 proxy_store 指令用于缓存内容服务器响应到本地,若不手动删除,则一直存在。

server{
   listen 80;
 server_name test.test;
 location / {
   root cache; #制定个缓存文件的保存目录
   proxy_store on; #开启本地缓存
   proxy_store_access user:rw group:rw all:r; #设置缓存的读写规则
   proxy_temp_path cache_tmp; #设置反向代理时接收的数据临时存储文件的目录,该目录会自动创建    #利用正则匹配缓存文件、目录或符号链接是否存在,如果不存在再执行块语句
   if(!-e $request_filename){
       proxy_pass http://192.168.78.128;
   }
 }}

临时缓存(proxy_cache)

Nginx 服务器提供了 proxy_cache 指令设置临时缓存。采用 md5 算法将请求链接进行 hash 后,根据具体配置生成缓存文件目录,保存响应数据。

在缓存服务器上配置 nginx.conf 中的 **http** 块。

#代理临时目录proxy_temp_path /usr/local/nginx/proxy_temp_dir; #设置缓存服务器接收内容服务器响应内容使用的临时目录#web缓存目录和参数设置proxy_cache_path /usr/local/nginx/proxy_cache_dir levels=1:2 keys_zone=cache_one:50minactive=1m max_size=500m; #自定义保存目录,

配置 server 块:

server {
   listen 80;
 server_name test.test;
 #增加两个响应头,用于获取访问的服务器地址与缓存是否成功
 add_header X-Via $server_addr;
 add_header X-Cache $upstream_cache_status;
 location /{
   proxy_cache cache_one; #设置缓存区域名称
   proxy_cache_key $host$uri$is_args$args; #以域名、uri、参数组合成web缓存的key,nginx根据key值哈希
   proxy_cache_valid 200 10m;  #对200状态码设置缓存时间
   proxy_cache_valid 304 1m;
   proxy_cache_valid any 1m;   #其他未设置的缓存1分钟
   proxy_pass http://192.168.78.128;
 }}

缓存清理配置

因为 Nginx 不支持清理制定 url 的缓存,需要借助第三方模块来实现。例如 ngx_cache_purge

  1. 备份已安装的 Nginx

在添加 ngx_cache_purge 模块之前,关闭 Nginx 服务,备份已有的 Nginx 服务。

cp -r /usr/local/nginx /usr/local/nginx_old2
  1. 重新编译安装 Nginx

在 github 获取 ngx_cache_purge zip 包,并解压安装。

unzip ngx_cache_purge-master.zipmv ngx_cache_purge-master /usr/local/ngx_cache_purge#进入ngxin文件的解压目录配置一下cd nginx-1.10.1
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--add-module=/usr/local/ngx_cache_purge#编译和安装make && make install
  1. 配置缓存清理功能

    使用 proxy_cache_purge 指令实现缓存清理。

注意:

  • 指定的缓存区名称和 proxy_cache_purge 指令中出现的缓存区名称一致。

  • key 值设置规则要一致。

  • 清理缓存的 location 的编写位置在所有 location 之前,防止其他正则 location 提前匹配。

location ~/purge(/.*){
   allow 192.168.78.1;
 deny all;
 proxy_cache_purge cache_one $host$uri$is_args$args;}

如果有什么错误的地方,希望大家能指出,一起学习进步。

动动小手点点关注吧!

Java架构师学习公众号!

一个专注分享架构干货的微信公众号

觉得本文有用就把文章分享给更多的人看到吧!

Java进阶——带你入门分布式中的Nginx的更多相关文章

  1. 【转】Java进阶之路

    1.   引言 搞Java的弟兄们肯定都想要达到更高的境界,用更少的代码解决更多的问题,用更清晰的结构为可能的传承和维护做准备.想想当初自己摸着石头过河,也看过不少人介绍的学习路线,十多年走过来多少还 ...

  2. 分布式锁的理解,java自带的锁为什么会失效

    前段时间在发送短信的代码块上通过网上找的工具类基于Redis实现了分布式锁的功能 对应的链接https://www.cnblogs.com/c-h-y/p/9391602.html 周末想细细看一下. ...

  3. 【Java进阶面试系列之一】哥们,你们的系统架构中为什么要引入消息中间件?

    转: [Java进阶面试系列之一]哥们,你们的系统架构中为什么要引入消息中间件? **这篇文章开始,我们把消息中间件这块高频的面试题给大家说一下,也会涵盖一些MQ中间件常见的技术问题. 这里大家可以关 ...

  4. java.sql.date与java.util.date区别以及数据库中插入带时分秒的时间

    java.sql.Date,java.sql.Time和java.sql.Timestamp三个都是java.util.Date的子类(包装类). java.sql.Date是java.util.Da ...

  5. Java中的大小写字母相互转换(不利用Java自带的方法)

    Java中的大小写字母相互转换(不利用Java自带的方法) 1.设计源码 /** * * @title:UpperAndLower.java * @Package:com.you.utils * @D ...

  6. Java进阶(四十二)Java中多线程使用匿名内部类的方式进行创建3种方式

    Java中多线程使用匿名内部类的方式进行创建3种方式 package cn.edu.ujn.demo; // 匿名内部类的格式: public class ThreadDemo { public st ...

  7. Java自带RPC实现,RMI框架入门

    Java自带RPC实现,RMI框架入门 首先RMI(Remote Method Invocation)是Java特有的一种RPC实现,它能够使部署在不同主机上的Java对象进行通信与方法调用,它是一种 ...

  8. Java进阶4表达式中的陷阱

    Java进阶4表达式中的陷阱 20131103 表达式是Java中最基本的组成单元,各种表达式是Java程序员最司空见惯的内容,Java中的表达式并不是十分的复杂,但是也有一些陷阱.例如当程序中使用算 ...

  9. Java中使用new Date()和System.currentTimeMillis()获取当前时间戳的区别(转)(Java进阶-性能提升)

    在开发过程中,通常很多人都习惯使用new Date()来获取当前时间,使用起来也比较方便,同时还可以获取与当前时间有关的各方面信息,例如获取小时,分钟等等,而且还可以格式化输出,包含的信息是比较丰富的 ...

随机推荐

  1. 微信域名检测的C#实现

     背景:最近公司的公众号域名被封了,原因是公司网站被黑后上传了一个不符合微信规范的网页.所以...就进入了微信域名解封的流程. 百度微信域名解封发现很多微信域名检测的网站,还有Api:但是本人做微信公 ...

  2. [转]7行Python代码的人脸识别

    https://blog.csdn.net/wireless_com/article/details/64120516 随着去年alphago 的震撼表现,AI 再次成为科技公司的宠儿.AI涉及的领域 ...

  3. Solr的配置和在java中的使用

    Solr是一个全局站内搜索引擎,可以快速的搜索出结果. Solr依赖于tomcat,把Solr的war包放到tomcat中即可运行. 使用solr,需要在solr的schema.xml中配置solr与 ...

  4. Codeforces 1144F Graph Without Long Directed Paths (DFS染色+构造)

    <题目链接> 题目大意:给定一个无向图,该无向图不含自环,且无重边.现在要你将这个无向图定向,使得不存在任何一条路径长度大于等于2.然后根输入边的顺序,输出构造的有向图.如果构造的边与输入 ...

  5. VS Code做项目的笔记

    需要自己研究的东西:http://www.bootcss.com/ 画页面时的布局插件:http://blog.chinaunix.net/uid-22414998-id-2878529.html v ...

  6. OO Unit 1 表达式求导

    OO Unit 1 表达式求导 面向对象学习小结 前言 本博主要内容目录: 基于度量来分析⾃己的程序结构 缺点反思 重构想法 关于BUG 自己程序出现过的BUG 分析⾃己发现别人程序bug所采⽤的策略 ...

  7. JAVA递归生成树形菜单

    递归生成一个如图的菜单,编写两个类数据模型Menu.和创建树形的MenuTree.通过以下过程实现: 1.首先从菜单数据中获取所有根节点. 2.为根节点建立次级子树并拼接上. 3.递归为子节点建立次级 ...

  8. Spark内部执行机制

    Spark内部执行机制 1.1 内部执行流程 如下图1为分布式集群上spark应用程序的一般执行框架.主要由sparkcontext(spark上下文).cluster manager(资源管理器)和 ...

  9. node07

    ---恢复内容开始--- 1.SQL基本查询语句 2.子句 1)WHERE 子句 WHERE key=val WHERE key>val WHERE key1>val1 AND key2& ...

  10. $.each()和$().each(),以及forEach()的用法

    1.forEach() 是JS遍历数组的方法 var arr=[1,2,3]; arr.forEach(function(val,index,arr){ // var 为数组中当前的值 // inde ...