近期嘗試使用tomcat和Nginx進行配合作負載均衡和靜態與動態資源分配的Demo,期間遇到不少有意思的地方和知識短板,特此記錄
一:什麼是Nginx?
Nginx也是一款服務器,咱們經常使用它作如:反向代理、負載均衡、動態與靜態資源的分離的工做
反向代理:相對應的是正向代理,若是你使用過代理服務器的話就明白,咱們訪問某一個網站並不是直接訪問目標網站,而是告訴代理服務器我須要訪問什麼目標網站,由代理服務器發出請求給目標網站,將目標網站訪問結果再轉發給你,此時,你是請求代理方。而反向代理是此時代理服務器作服務器的代理,咱們的訪問請求並不是直接訪問到目標服務器上,而是訪問代理服務器,由代理服務器決定什麼樣的請求以什麼樣的方式訪問正式服務器
負載均衡:目前大多數的網站都會採用負載均衡手段來針對目前用戶的指數級增加來減小對單點服務器的負載壓力,好比目前咱們擁有3臺真實服務器,咱們須要根據相應策略決定什麼樣的用戶請求分配到哪一個真實服務器,好比按照輪詢的方式,用戶請求挨個到達代理服務器,此時代理服務器按照第一個請求轉發至第一臺真實服務器,第二個請求轉發到第二個服務器上,依次類推,這樣能夠防止大量的用戶請求所有訪問到同一臺物理機上,單點物理機的性能始終有限的,固然這可能對服務器數據訪問時候形成事務性的失效,在Web方面可能形成Session訪問的問題,這不在本文討論方面內
動態靜態資源分離:最方便列舉就是Java的JSP和靜態資源如:.js/.css/.html/.png方面的資源分離,以前開發web方面的程序時候咱們習慣將html、css等資源文件也放置於Tomcat之中,用戶訪問後tomcat須要將請求的這些靜態資源文件一併返回給用戶,再者若是有多臺同業務邏輯的tomcat服務器的話,一樣的資源還須要在每一個服務器上放一份,同時也增長了tomcat服務器的網絡IO,十分不合算的,若是咱們只講JSP之類的請求交給tomcat,而代理服務器上存放靜態資源,當用戶的請求非動態資源的時候,咱們徹底能夠將代理服務器的靜態資源直接返回給用戶,而不去增大Tomcat的壓力,tomcat只須要負責邏輯處理和動態資源的加載就能夠了
基於上述的Nginx優點,決定搭建一下Nginx+Tomcat的組合來進行測試,包括參數傳遞,post、get傳遞參數是否有影響,還有Nginx的工做模式master和worker的工做方式進行一些淺薄的總結
1、Nginx的安裝
安裝部分這裏就不在細說了,網上的教程不少,咱們直接從配置文件開始吧
2、配置文件
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
#user nobody;
#這裏是核心worker數,通常設置爲與cpu核心數相同的數目,避免進程切換形成的上下文切換耗費資源,cpu信息能夠從/proc/cpuinfo中查看
worker_processes
1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
#use epoll model使用epoll模型,採用異步非阻塞模型加快處理速度
use epoll;
worker_connections
1024;
}
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;
#設定經過nginx上傳文件的大小
client_max_body_size
300m;
#使用sendfile函數在兩個文件描述符之間直接傳遞數據(徹底在內核中操做,傳送),從而避免了內核緩衝區數據和用戶緩衝區數據之間的拷貝,操做效率很高,被稱之爲零拷貝。
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
#鏈接活躍時間
keepalive_timeout
65;
#使用壓縮數據減小IO量,可是在不支持數據解壓瀏覽器可能產生亂碼
#gzip on;
#靜態服務器組
#設定靜態資源服務器訪問接口
upstream
static.zh-jieli.com {
server localhost:
808 weight=
1;
}
#動態服務器組
upstream zh-jieli.com {
#設置Hash輪詢規則
#ip_hash;
#weight: server ip:port weight=10
#默認 輪詢
#fair:按照後端服務器的響應時間來分配
#url_hash:按照url規則進行分配,使得固定的請求分配到固定的服務器上
server localhost:
8080;
server localhost:
8081;
}
server{
listen
808;
server_name
static;
location / {
}
location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
#全部靜態文件直接讀取硬盤內容:讀取的靜態資源存放位置
root /apache-tomcat-
8.5.24/webapps/ROOT ;
#資源是否進行緩存與緩存時間
expires
30d;
#緩存30天
}
}
server {
listen
80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index1.html
index.htm;
}
location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
#proxy_cache cache_one;
proxy_cache_valid
200 304 302 5d;
proxy_cache_valid any
5d;
proxy_cache_key
'$host:$server_port$request_uri';
add_header X-Cache
'$upstream_cache_status from $host';
proxy_pass http:
# 全部靜態文件直接讀取硬盤
root /apache-tomcat-
8.5.24/webapps/ROOT;
expires
30d;
#緩存30天
}
#其餘頁面反向代理到tomcat容器
location ^~ /tomcat {
index index;
# proxy_pass http://localhost:8080/;
#設定代理服務器組
proxy_pass http:
}
error_page
500 502 503 504 /
50x.html;
location = /
50x.html {
root html;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
整個nginx工做時當http請求到來時,由nginx針對nginx.conf配置好的規則,對location進行正則匹配,匹配到相應的正則,進行location內部的處理
關於Nginx的location配置附上一篇博客,很nice
http://seanlook.com/2015/05/17/nginx-location-rewrite/
裏面很詳細列出了各類要求的location匹配規則,值得注意的一點是:
location匹配遵循最長原則,即知足了以前的匹配規則後,除了碰見^會終止向下繼續匹配,其餘狀況會依次向下搜索,知道找到合適的location匹配規則而後進行處理
Nginx在模塊功能上分三個模塊:
Handlers(處理器模塊)。此類模塊直接處理請求,並進行輸出內容和修改headers信息等操做。Handlers處理器模塊通常只能有一個。
Filters (過濾器模塊)。此類模塊主要對其餘處理器模塊輸出的內容進行修改操做,最後由Nginx輸出。
Proxies (代理類模塊)。此類模塊是Nginx的HTTP Upstream之類的模塊,這些模塊主要與後端一些服務好比FastCGI等進行交互,實現服務代理和負載均衡等功能。
由於是測試,因此個人兩個tomcat都安裝到了同一臺本地機器上
生產環境中根據須要進行配置相應的IP就行了
本地寫好相應的測試代碼+log4j將信息日誌打到相應的位置用來觀察參數是否傳遞過來
TestOne.javacss
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
package
com.nginx.controllers
import
com.nginx.utils.Log4jUtils
import org
.springframework.stereotype.Controller
import org
.springframework.web.bind.annotation.RequestMapping
import org
.springframework.web.bind.annotation.RequestParam
@Controller
@RequestMapping(
"/test")
public class TestOne {
@RequestMapping(
"/getname")
public void test(@RequestParam(value =
"name") String name) {
//用來記錄獲取的參數name,能夠經過查看日誌進行確認
Log4jUtils
.getLogger()
.info(
"my name is" + name)
}
}
Log4jUtils.javahtml
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
package com.nginx.utils;
import org.apache.log4j.Logger;
public class Log4jUtils {
private static final Logger logger = Logger.getLogger(Logger.class);
public static Logger
getLogger() {
return logger;
}
}
這裏簡單作了兩個的demo程序,作相應的測試,將項目打成war包後上傳至Linux服務器,移動到tomcat/webapps中,tomcat進行熱部署
先測試當前的tomcat是否能正常運行,因爲沒有作區別頁面,就直接看日誌來判斷了
![這裏寫圖片描述](http://static.javashuo.com/static/loading.gif)
如圖:以輪詢方式進行訪問8080和8081監聽的tomcat
上述方式是get請求進行的測試,咱們來試試post
<!DOCTYPE html>
<html>
<body>
<form action="http://123.207.85.242/tomcat/nginx/test/getname" method="post">
<input type="text" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
測試結果依舊能夠正常接收參數,這裏就不貼圖了
2、靜態動態資源分離
如今試試直接訪問
http:
咱們會直接跳轉到tomcat的主頁面,若是檢索tomcat.png的話
http://ip/tomcat/tomcat
.png
能夠直接檢索到tomcat.png,它是來自tomcat服務器的資源,若是須要檢索nginx的靜態資源,可使用
http://ip/tomcat
.png
這樣咱們的資源就來自於nginx.conf文件中配置的關於靜態資源的訪問路徑了,爲了證實此事資源來自於nginx,我嘗試將8080端口的tomcat/webapps/ROOT/tomcat.png改名爲tomcat1.png,而後嘗試訪問http://ip/tomcat1.png訪問成功,這時候若是刷新http://ip/tomcat/訪問tomcat主頁的時候會發現圖標會在出現和不出現之間輪轉,緣由就是這裏請求了tomcat服務器自己去拿資源,tomcat:8080的圖片名被更改,若是代理訪問的服務器正好是tomcat:8080的話,它是找不到tomcat.png的,固然輪轉到tomcat:8081時候,圖片仍是會出現滴
3、Nginx工做模式
![這裏寫圖片描述](http://static.javashuo.com/static/loading.gif)
如圖nginx啓動後會有兩個進程
若是你將nginx.conf的
worker_processes 1;更改成worker_processes 2;
那麼出現的就是
![這裏寫圖片描述](http://static.javashuo.com/static/loading.gif)
那咱們來講說master和worker進程分別的是幹什麼的,從pid來看,matser的父進程是init進程,而worker的父進程都是master,這裏就頗有意思了,那nginx這兩個進程都究竟是幹嗎的嘞???
感謝baidu與google的強大,對於疑問的解釋很清楚
原地址:http://blog.csdn.net/hguisu/article/details/8930668
感興趣的同窗能夠看一看,這裏只簡單總結一下
master進程
主要用來管理worker進程,包含:接收來自外界的信號,向各worker進程發送信號,監控worker進程的運行狀態,當worker進程退出後(異常狀況下),會自動從新啓動新的worker進程。
master的平滑重啓頗有意思,master只負責接收外界信號,那麼當咱們更改了nginx.conf文件須要從新啓動nginx時候怎麼辦????只須要經過kill向master進程發送信號就好了。好比kill -HUP pid,這時候master並不會幹掉本身全部的worker而後自殺,而是從新加載nginx.conf後,從新啓動一批worker,在這以後的請求所有由新的worker進行處理,而老的worker也並非當即終止,而是在運行完當前的請求後,被終止掉,接下來的請求就所有交給新的worker了,固然這個方式後來被改爲了
nginx
-s reload
這個命令從新加載配置和上面的略有不同,其會新啓動一個nginx而後向Master發送信號,固然接下來就和上面的過程一致了
worker進程
而基本的網絡事件,則是放在worker進程中來處理了。多個worker進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的。一個請求,只可能在一個worker進程中處理,一個worker進程,不可能處理其它進程的請求。worker進程的個數是能夠設置的,通常咱們會設置與機器cpu核數一致,這裏面的緣由與nginx的進程模型以及事件處理模型是分不開的。
那麼worker是怎麼作的呢,worker從master fork出來後,由master進行監聽端口,當有相應的鏈接來以後,由worker爭搶accept_mutex互斥鎖,同一時刻此請求只能由一個worker爭搶成功,並進行鏈接的讀取、解析、處理而後斷開鏈接
着總體是Nginx的工做的大體原理,Nginx依舊有不少細節和設計值得去深究學習,本篇博客先總結到此,後續有了更深刻的瞭解,也會分享出來,謝謝