天天看點

Nginx+Sping Cloud+Tomcat 實作負載均衡

一、什麼是Nginx?

     Nginx是一款輕量級高性能的反向代理伺服器,支援Web站點和郵件代理。其特點是記憶體少,并發能力強,結構簡單,支援長時間的動作,它通過代理模式将使用者的請求轉發給不同的伺服器,減輕伺服器的壓力。

二、Nginx負載均衡政策

      Nginx支援6種均衡政策,分别為輪詢,權重,IP hash(ip 配置設定),least_conn(最少連接配接),fair(響應時間),url_hash(url配置設定)。通過這幾種政策來達到不同的業務需求。下面分别介紹下各自的特點:

1、輪詢

     輪詢是政策中最基礎的方式,通過upstream子產品實作,是預設的均衡政策  在nginx.conf檔案裡

    upstream weburl{

        server 127.0.0.1:8080;

        server 127.0.0.1:8081 backup;//IP + 端口 +參數配置

    }

    通過upstram子產品 指定後端的伺服器清單,每個請求會按時間順序通路後端的伺服器。其中提供一些參數設定:

    fail_timeout :時間超出。

    max_timeout  : 最大逾時時間,如超過次數會被認為該伺服器為停機狀态。

    fail_time:請求逾時的時間 預設為10s。

    backup:标記為該服務為務用伺服器,當其中的主機當機後,請求會被備用機接收。

    down:表示永遠停機。

 2、權重政策Weight

    權重政策是增加請求次數的幾率,可以設定對哪台伺服器進行多次的通路:

   upstream weburl{

        server 127.0.0.1:8080 weight=2;

        server 127.0.0.1:8081 weight=1;

        server 127.0.0.1:8082 backup;

    }

 上面的例子中使用weight參數=2來表示應該伺服器的請求次數,會比權重1的要通路的次數高一些,權重配置設定的越高處理請求次數越多,此政策用于伺服器之間配置較大時進行使用,可以和least_conn,ip_hash配合使用。

3、IP_Hash政策

  ip_hash政策指定負載均衡按照基于用戶端IP的配置設定方式,将相同的用戶端請求發送到同一個伺服器進行處理

  upstream weburl{

        ip_hash;

        server 127.0.0.1:8080 weight=2;

        server 127.0.0.1:8081 weight=1;

        server 127.0.0.1:8082 ;

   }

  其中ip_hash不能和backup進行同時使用,該政策适合狀态服務(session)。

4、least_conn政策

least_conn政策是将請求交給後端連接配接數較少的伺服器,輪詢政策中是将請求平均的配置設定給後端伺服器,這會增加占用請求的時間,least_conn比輪詢效果會好一些。

  upstream weburl{

        least_conn;

        server 127.0.0.1:8080 weight=2;

        server 127.0.0.1:8081 weight=1;

        server 127.0.0.1:8082 ;

   }

5、第三方政策fair

      要實作這種政策需要安裝第三方插件。

     upstream weburl{

        server 127.0.0.1:8080 weight=2;

        server 127.0.0.1:8081 weight=1;

        server 127.0.0.1:8082;

        fair;

    }

  fair是按照伺服器響應時間來進行配置設定請求,響應時間短的優先配置設定。

6、url_hash政策

 url_hash也是需要第三方插件,url_hash是根據url的hash結果值來配置設定後端伺服器,當多個請求都通路同一個資源,使用url_hash政策可以将同一台伺服器之前通路過的資源進行再次配置設定,從緩存中取出。

    upstream weburl{

        hash $request_url;

        server 127.0.0.1:8080 weight=2;

        server 127.0.0.1:8081 weight=1;

        server 127.0.0.1:8082;

    }

以上幾種政策要根據不同的應用場景進行使用。

三、Nginx如何處理請求

      Nginx在啟動會解析配置檔案,得到需要的端口和IP位址,然後在nginx的主程序裡,發先初始化這個監控對象socket綁定到指定的IP位址端口再進行監聽listen,然後再通過fork建立一個新的線程worker,多個線程程序之間會互相竟争accept的連接配接,此時,用戶端可以向nginx發起連接配接,與nginx三次握手(http協定),找到一适合的線程進行連接配接同時會獲得accept的對象(socket),然後建立nginx封裝ngx_connection結構體,之後處理之間的讀寫請求操作進行資料交換,完成之後再進行釋放連接配接。

      對于逾時的請求nginx會根據設定的逾時時間來進行設定,長時間沒有得到處理會傳回一個狀态碼(404  501)來标明這個請求出現了錯誤,nginx提供proxy_next_upstream_tries來進行重試機制,出現了逾時的主機,不會再次發送到該主機上,由下一個竟争的節點來進行處理。其中在nginx之前還有一層代理SLB最大的逾時時間為一分鐘,如果設定多了,會出現多次重複請求的問題。

四、搭建Nginx代理伺服器

       本文以windows做一個簡單的示例,Linux的請檢視其它文章。

    1、首先從官網下載下傳最新的tar包(http://nginx.org/en/download.html)。

    2、下載下傳完後解壓到一個盤符下打開conf 下的nginx.conf檔案如圖:

#user  nobody;
worker_processes  2;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
	multi_accept on;
	accept_mutex on;
	
}


http {
    include       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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

	upstream weburl{
	
		server 127.0.0.1:8080 weight=2;
		server 127.0.0.1:8081 weight=1;
		server 127.0.0.1:8082;
		
	}
	
	error_page 400 http://www.baidu.com;
	
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
			proxy_pass http://weburl;
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       8888 ssl;
    #    server_name  localhost;
	
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}
           

檢視檔案的子產品結構:

**************************************

全局變量

events{   //nginx與網絡連接配接配置參數

}

http{    //http子產品

     //局部參數

    server{  //伺服器子產品

        location{  //服務位址參數配置

       }  

 }

}

*****************************

這以上為主要的幾個子產品。後面再來進行相關配置。

五、打包SpringCloud

   基于之前的文章使用到的 Spring-cloud-mybatis-jsp 工程 在index.jsp增加一個h1标簽來進行辨別哪個站點。在工程中複制一份工程。複制工程之後需要修改幾個地方

1、pom.xml 

<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.2.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>spring-cloud-mybatis-jsp2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>spring-cloud-mybatis-jsp2</name>
	<description>Demo project for Spring Boot</description>
           

修改其中的artifactId  和 name值  内容為新的項目名稱

2、在工程空間下修改.settings檔案下org.eclipse.wst.common.component 檔案将其中的deploy-name,context-root,java-output-path都修改成新的工程名稱

<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
    <wb-module deploy-name="spring-cloud-mybatis-jsp2-0.0.1-SNAPSHOT">
        <wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
        <wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
        <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
        <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
        <property name="context-root" value="spring-cloud-mybatis-jsp2"/>
        <property name="java-output-path" value="/spring-cloud-mybatis-jsp2/target/classes"/>
    </wb-module>
</project-modules>
           

3、打包成war檔案  首先pom.xml裡的<packaging>war</packaging>需要指定的是war值,然後檔案中的tomcat需要設定<scope>provided</scope>值

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
           

 最後主程式需要繼承SpringBootServletInitializer類重寫configure方法 如下:

@SpringBootApplication
public class SpringCloudMybatisJspApplication extends SpringBootServletInitializer {

	public static void main(String[] args) {
		SpringApplication.run(SpringCloudMybatisJspApplication.class, args);
	}
	
	@Override//為了打包springboot項目
    protected SpringApplicationBuilder configure(
            SpringApplicationBuilder builder) {
        return builder.sources(this.getClass());
    }

}
           

滿足這幾個條件就可以進行war打包, 點選工程  右鍵選擇Run As->Maven install 之後console會顯示打包war後的路徑 eg:

E:\apache-maven-3.5.3\maven\repository\com\example\spring-cloud-mybatis-jsp2\0.0.1-SNAPSHOT\spring-cloud-mybatis-jsp2-0.0.1-SNAPSHOT.war

之後将檔案重命為相同的名稱放在tomcat webapp目錄。另一個工程同樣的方法進行打包。

注意:test檔案下的内容不能進行打包,删除就可以了。

4、設定兩個Tomcat

      從安裝好的Tomcat複制一份,修改tomcat的配置檔案 主要修改三個地方(配置不同的端口):

<Server port="8006" shutdown="SHUTDOWN">

<Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
           

然後修改bin目錄下的兩個檔案:startup.bat 和catalina.bat 将其中的CATALINA_HOME全替換為新的名稱CATALINA_HOME_8080  另一個tomcat就取CATALINA_HOME_8081。

最後運作兩個tomcat,tomcat會自動的将war進行解壓運作   如圖 :

Nginx+Sping Cloud+Tomcat 實作負載均衡
Nginx+Sping Cloud+Tomcat 實作負載均衡

通過兩個tomcat 通路各自的項目。

6、配置Nginx

       上面的顯示例代碼也已經出給了,下在進行說明一下,在server 子產品的上方通過upstream 服務群名稱來指定不同的伺服器:

       upstream weburl{

        server 127.0.0.1:8080 weight=2;

        server 127.0.0.1:8081 weight=1;

    }

 其中server可以指定本機和其它的IP位址,端口就是tomcat的端口号,後面參數可以設定均衡政策。其中在localtion子產品中需要将剛剛配置的叢集名字放到服務地上子產品中進行指定。如下:

        location / {

            proxy_pass http://weburl;  //這裡叢集名稱一緻。

            root   html;

            index  index.html index.htm;

        }

以上就配置好了,本例隻是個簡單的例子,還有其它的配置比如逾時,檔案緩存政策、重試等。

之後進入目錄(cd /) 啟動Nginx 使用指令start nginx啟動(nginx -s stop 停止),如果出現錯誤就檢視log檔案下的error.log檔案,裡面指明錯誤的資訊,如果沒有錯誤說明配置沒有出現錯誤,然後檢視程序裡是否有nginx程序。

最後運作Url: http://localhost/spring-cloud-mybatis-jsp/getusers  連續重新整理檢視  通過nginx代理可以通路不同的工程,不需要指定端口号,就可以在兩個工程之間進行通路。

總結:

   以上就是本文通過Nginx+Spring Cloud+Tomcat實作一個簡單的負載均衡,Nginx還有很多的配置但都是基于nginx.conf裡的參數來進行設定,具體參數需要根據工程需求來進行設定,包括連接配接的優化,以及響應時間等等要根據實際情況而定。

繼續閱讀