高併發技術

時間靜止不是簡史發表於2019-10-21

第一章 預備知識

一 理解大資料

我國是人口大國同時也是資料大國, 由資料的量(數以億計)變產生了質變 , 我們步入了大資料時代.
而大資料也帶來的高併發的問題. 解決高併發問題是大資料時代的永恆主題.

我們假設已經解決高併發的問題, 我們可以通過對數以億計的資料做日誌分析 ,
從中分析使用者行為 ,分析在哪個渠道的使用者最具購買力 , 哪個渠道最容易接納我們的產品.
進而對使用者行為進行建模 ,分析使用者喜好 ,根據這些喜好可以推薦給使用者一些個性化服務.
即: 高併發>日誌>分析行為>畫像>推薦>服務
這便是大資料時代下企業發展之路 ,因此 ,解決高併發問題便是關鍵.

通過相應技術, 解決高併發問題 ,為企業節省更多資金 ,有益企業良性發展.
這便是大資料技術發展的不竭動力之源.

二 網工基礎知識

OSI七層參考模型

OSI是Open System Interconnection的縮寫,意為開放式系統互聯。國際標準化組織(ISO)制定了OSI模型,該模型定義了不同計算機互聯的標準,是設計和描述計算機網路通訊的基本框架。OSI七層模型如下:

所在層 所在層名稱
第七層 應用層 ( nginx 軟體 )
第六層 表示層
第五層 會話層
第四層 傳輸層 /運輸層( lvs 核心 )
第三層 網路層
第二層 鏈路層 / 資料鏈路層
第一層 物理層

應用層

網路應用層是通訊使用者之間的視窗,為使用者提供網路管理、檔案傳輸、事務處理等服務
這一層設計的主要問題是分佈資料庫、分佈計算技術、網路作業系統和分佈作業系統、
遠端檔案傳輸、電子郵件、終端電話及遠端作業登入與控制等。
應用層為作業系統或網路應用程式提供訪問網路服務的介面

應用層協議的代表包括
Telnet(遠端登入協議)、
FTP(檔案傳輸協議)、
HTTP(超文字傳輸協議)、
SNMP(簡單網路管理協議)、
DNS(域名解析協議)等。

表示層

表示層向上對應用層提供服務,向下接收來自會話層的服務。
表示層要完成某些特定的功能,主要有不同資料編碼格式的轉換,提供資料壓縮、解壓縮服務,
對資料進行加密、解密。例如影象格式的顯示,就是由位於表示層的協議來支援。
表示層為應用層提供服務包括語法選擇、語法轉換等。語法選擇是提供一種初始語法和以後修改這種選擇的手段。
語法轉換涉及程式碼轉換和字符集的轉換、資料格式的修改以及對資料結構操作的適配。

會話層

提供包括 訪問驗證 和 會話管理 在內的 建立和維護 應用之間通訊的 機制(如伺服器驗證使用者登入)。
會話層提供的服務可使應用建立和維持會話,並能使會話獲得同步。
會話層使用校驗點可使通訊會話在通訊失效時從校驗點繼續恢復通訊。
會話層同樣要擔負應用程式服務要求,而運輸層不能完成的那部分工作,給運輸層功能差距以彌補。
主要的功能是對話管理,資料流同步和重新同步。

傳輸層

傳輸層建立在網路層和會話層之間,實質上它是網路體系結構中高低層之間銜接的一個介面層。
用一個定址機制來標識一個特定的應用程式(埠號)。
傳輸層不僅是一個單獨的結構層,它還是整個分層體系協議的核心,沒有傳輸層整個分層協議就沒有意義。
傳輸層的資料單元是由資料組織成的資料段(segment)這個層負責獲取全部資訊,
傳輸層最重要的兩個協議:TCP , UDP協議

傳輸層主要負責的行為
三次握手>>(傳輸資料)>>四次分手

小技巧
利用 netstat -natp可檢視虛擬機器建立的tcp連線

在這裡插入圖片描述

網路層

網路層也稱通訊子網層,是高層協議之間的介面層,用於控制通訊子網的操作,是通訊子網與資源子網的介面。
如果你在談論一個IP地址,那麼你是在處理第3層的問題,這是“資料包”問題,而不是第2層的“幀”。
IP是第3層問題的一部分,此外還有一些路由協議和地址解析協議(ARP)。
有關路由的一切事情都在第3層處理。地址解析和路由是3層的重要目的 ,是路由器所屬層
網路層還可以實現擁塞控制、網際互連、資訊包順序控制及網路記賬等功能。

網路層協議的代表包括
IP(網際協議:目前應用最廣的網路互聯協議, 消除物理網路差異性 ,使網路互連成為可能)
OSPF(開放式最短路徑優先, 屬於內部閘道器協議)等。

小技巧
通過 route -n 檢視虛擬機器核心的IP路由表資訊
在這裡插入圖片描述

鏈路層

在物理層提供位元流服務的基礎上,將位元資訊封裝成資料幀Frame,
起到在物理層上建立、撤銷、標識邏輯連結和鏈路複用以及差錯校驗等功能。
資料鏈路層在不可靠的物理介質上提供可靠的傳輸 ,是交換機所在的層
該層的作用包括:實體地址定址、資料的成幀、流量控制、資料的檢錯、重發等。
在這一層,資料的單位稱為幀(frame)。

資料鏈路層協議的代表包括:
ARP協議(地址解析協議:根據IP地址獲取實體地址的一個TCP/IP協議)、
SDLC、HDLC、PPP、STP、幀中繼等。

小技巧
通過arp -a 查詢虛擬機器ARP快取中IP地址和MAC地址的對應關係
在這裡插入圖片描述

物理層

物理層是OSI分層結構體系中最重要、最基礎的一層,
建立在傳輸媒介基礎上,起建立、維護和取消物理連線作用,實現裝置之間的物理介面。
物理層只接收和傳送一串位元(bit)流,不考慮資訊的意義和資訊結構。

功能分層

層與層依賴

  1. 能夠申請到埠號
  2. 路由表有下一跳條目
  3. ARP能請求到下一跳MAC
  4. 三次握手
  5. 傳輸資料
  6. 四次分手

在這裡插入圖片描述

總結

整個網際網路建立在下一跳的模式下
IP是邏輯上的兩個端點
MAC是物理上連線的兩個節點

端點間TCP傳輸過程中
確認機制
狀態機制
不可分割

解析資料包需要成本
交換機:二層,只關心MAC地址 學習機制
路由器:三層,只關心IP和路由表
LVS伺服器:四層,只關心PORT,狀態
nginx:七層,關心socket對應關係

第二章 LVS技術

一 LVS介紹

LVS是Linux Virtual Server的簡寫,即Linux虛擬伺服器,是一個虛擬的伺服器叢集系統

相關概念

  1. ipvs : 嵌入到linux的核心
  2. ipvsadm:管理應用程式
  3. VIP: 虛擬伺服器地址
  4. DIP: 轉發的網路地址
    和RIP通訊:ARP協議,獲取Real Server的RIP:MAC地址
    轉發Client的資料包到RIP上(隱藏的VIP)
  5. RIP: 後端真實主機(後端伺服器)
  6. CIP: 客戶端IP地址

在這裡插入圖片描述

工作模式

1. LVS -D_NAT 地址轉換

NAT(Network Address Translation,網路地址轉換):
當在專用網內部的一些主機本來已經分配到了本地IP地址(即僅在本專用網內使用的專用地址),
但現在又想和因特網上的主機通訊時,可使用NAT方法

這種方法需要在專用網連線到因特網的路由器上安裝NAT軟體。
裝有NAT軟體的路由器叫做NAT路由器,它至少有一個有效的外部全球IP地址
所有使用本地地址的主機在和外界通訊時,都要在NAT路由器上將本地地址轉換成全球IP地址,才能連線網路。
私有ip不能出現再公網上,所以需要net轉換,
nat交換機將源id埠轉換為net交換機分配到的公網ip,並記錄下對於的內網主機地址,
收到請求後根據目標地址轉換為內網地址

在這裡插入圖片描述

2. LVS -DR MAC欺騙 直接路由

這種方式不會修改源ip地址和目標ip地址,會在第二層資料鏈路層時修改目標MAC地址,
將其修改為server到的MAC地址。成為MAC欺騙。
又因為MAC基於下一跳的機制,所以server和負載均衡器必須位於同一個區域網。
server端使用隱藏的vip傳送socket,這樣源ip對應請求的目標ip,同時降低負載均衡器的IO.

在這裡插入圖片描述

3. LVS -TUN 隧道

使用ip隧道技術,將請求封裝成ipTUN,server收到ipTUN後解包並處理請求。
響應機制使用隱藏的VIP

在這裡插入圖片描述

二 LVS排程演算法

靜態排程演算法

簡稱 全稱
rr 輪詢排程(Round-Robin Scheduling)
wrr 加權輪詢排程(Weighted Round-Robin Scheduling)
dh 目標地址雜湊排程(Destination Hashing Scheduling)
sh 源地址雜湊排程(Source Hashing Scheduling)

動態排程演算法

簡稱 全稱
lc 最小連線排程(Least-Connection Scheduling)
wlc 加權最小連線排程(Weighted Least-Connection Scheduling)
sed 最短的期望的延遲排程(Shortest Expected Delay’)
nq 最少佇列排程(Never Queue )
lblc 基於區域性性的最少連結(Locality-Based Least Connections Scheduling)
lblcr 帶複製的基於區域性性最少連結(Locality-Based Least Connections with Replication Scheduling)

預設方法:wlc
點選瞭解LVS三種工作模式與10種排程演算法詳細

LVS命令

監控多個埠號

# ipvs核心模組
yum install ipvsadm -y

# 管理叢集服務
#新增:
-A -t|u|f service-address [-s scheduler]
	-t: TCP協議的叢集 
	-u: UDP協議的叢集
	service-address:     IP:PORT
	-f: FWM: 防火牆標記 
	service-address: Mark Number
#修改:-E
#刪除:
-D -t|u|f service-address

eg: 
ipvsadm -A -t 192.168.9.100:80 -s rr

管理服務叢集中的Real Serever(RS)

#新增:
-a -t|u|f service-address -r server-address [-g|i|m] [-w weight]
	-t|u|f service-address:事先定義好的某叢集服務
	-r server-address: 某RS的地址,在NAT模型中,可使用IP:PORT實現埠對映;
		[-g|i|m]: LVS型別	
		-g: DR
		-i: TUN
		-m: NAT
		[-w weight]: 定義伺服器權重
#修改:-e
#刪除:
-d -t|u|f service-address -r server-address
#eg:
 ipvsadm -a -t 172.16.100.1:80 -r 192.168.10.8 –g
 ipvsadm -a -t 172.16.100.1:80 -r 192.168.10.9 -g

#檢視
-L|l
-n: 數字格式顯示主機地址和埠
	--stats:統計資料
	--rate: 速率
	--timeout: 顯示tcp、tcpfin和udp的會話超時時長
-:c 顯示當前的ipvs連線狀況

#刪除所有叢集服務
-C:清空ipvs規則
-S: 儲存規則
-R : 載入此前的規則
#eg:
 ipvsadm -S > /path/to/somefile
 ipvsadm -R < /path/form/somefile

三. LVS-DR實現

LVS-DR實驗拓撲圖

在這裡插入圖片描述

實現步驟

vip :虛擬ip
RS:real伺服器

  1. 準備3臺虛擬機器
    node1作為lvs伺服器
    node2,node3作為Real Server

  2. 先配置3臺虛擬機器的網路
    eth0,配置在一個網段
    DIP,RIP在一個網段

  3. 配置lvs的VIP(node1主機)

    # 臨時配置 ,重啟後配置消失
    # 設定vip 需要根據自己所在網段配置, 例如我的網段 192.168.179.0,因此我隨便設定了一個192.168.179.100
    ifconfig eth0:2 192.168.179.100/24
    
    # 設定轉發級別, 	/proc不允許使用vim進行修改 ,因為使用vi命令會在目錄下建立交換檔案(臨時配置)
    echo "1" > /proc/sys/net/ipv4/ip_forward
    
  4. 調整RS的響應。通告級別(每一臺RS都配, node2, node3)

    # node2
    echo 1  > /proc/sys/net/ipv4/conf/eth0/arp_ignore
    echo 2  > /proc/sys/net/ipv4/conf/eth0/arp_announce
    # node3
    echo 1  > /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 2  > /proc/sys/net/ipv4/conf/all/arp_announce
    
  5. 配置RS的VIP(每一臺RS都配, node2, node3)

    ifconfig lo:8 192.168.179.100 netmask 255.255.255.255
    

    在這裡插入圖片描述

  6. 啟動RS上的httpd(node2, node3)

    # 下載httpd服務
    yum install -y httpd 
    
    # 進入相關目錄
    cd /var/www/html
    
    # 新增主頁內容
    vi index.html  
    ------------------index.html------------
    from ooxxip(各自ip)
    ------------------index.html------------
    
    # 啟動服務
    service httpd start
    
    # 關閉防火牆(node1,node2,node3主機)
    service iptables stop
    

    客戶端驗證:
    VIP:80不能顯示(node1)
    訪問的是node的vip: 192.168.179.100 ,而不是真實 ip:192.168.179.140

    RIP:80 能顯示(node2,node3)
    在這裡插入圖片描述
    在這裡插入圖片描述

  7. LVS——ipvsadm(node1)

    # 下載對lvs命令的支援
    yum install -y ipvsadm 
    
    # 設定監控的包
    ipvsadm -A -t 192.168.179.100:80 -s rr
    # 新增real server(noed2, node3),-g直接路由,
    ipvsadm -a -t 192.168.179.100:80 -r 192.168.179.141 -g 
    ipvsadm -a -t 192.168.179.100:80 -r 192.168.179.142 -g
    # 檢視配置是否成功(圖1)
    ipvsadm -ln
    
    # 瀏覽器重新整理: 訪問vip(node1),然後F5重新整理,測試配置的輪詢演算法是否生效,並多次重複重新整理
    訪問的是node的vip: 192.168.179.100
    而不是真實 ip:192.168.179.140
    
    # 檢視tcp協議連線的有哪些程式
    netstat -natp
    # 驗證lVS偷窺/負載記錄(圖2)
    ipvsadm -lnc
    

    圖1
    在這裡插入圖片描述
    圖2
    在這裡插入圖片描述

LVS簡單總結
負載均衡
四層(傳輸層)
不會握手——高速轉發
豐富的排程演算法

缺點:
後端:映象伺服器 ,沒有健康檢查機制
自身:單點故障(如果lvs出現故障,會導致服務不可用; 如果RS出現故障會出現資料傾斜)

沒有解決的問題:
後端伺服器如果臃腫,由計算和io瓶頸,lvs是無能為力的
這裡就引出下面了Keepalived技術

第三章 Keepalived

keepalived是叢集管理中保證叢集高可用的服務軟體

一 高可用 High Available

  1. 需要心跳機制探測後端RS是否提供服務。
    a) 探測down,需要從lvs中刪除該RS
    b) 探測傳送從down到up,需要從lvs中再次新增RS。
  2. Lvs DR,需要主備(HA)
    Keepalived 原理:
    VRRP協議(虛擬路由冗餘協議) - Virtual Router Redundancy Protocol
    IP漂移

Keepalived下的lvs架構圖

新增了用於備用的lvs伺服器 , keepalived通過心跳檢測的形式檢測lvs和rs ,
如果主lvs出現問題則 ,立即為備份主機分配vip ,並令其生效
在這裡插入圖片描述

二 模擬實驗配置

node1 主lvs
node4 備lvs
node2,node3 real server(RS)
每個節點node對應一臺物理主機
進行實驗時,防火牆必須關閉

# 1.清除上個實驗lvs的配置(node1)
ipvsadm -C

# 2.檢視相關配置是否清除完畢
ipvsadm -in

# 3. 關閉上個實驗node1中vip的設定
ifconfig 
ifconfig eth0:2 down

# 4.開啟node4, 可以不用安裝ipvsadm -lnc ,安裝 Keepalived ,keepalived(ipvsadm,自身高可用)
# 配置RS的步驟還和上次實驗一致
yum install -y  keepalived ipvsadm 
yum install -y ipvsadm   # 這裡安裝 ipvsadm不是用來配置而是用來檢視核心相關介面情況

# 5.在node1中安裝Keepalived 
yum install -y  keepalived

# 6. 修改配置檔案(建議備份一下)
cd /etc/keepalived
# 幫助手冊
man keepalived.conf
cp keepalived.conf  keepalived.conf.bak
vim keepalived.conf    
# 修改內容在下一個程式碼塊


# 7. 遠端複製(從 node1複製到node4 ,圖1)
scp ./keepalived.conf root@192.168.179.143:`pwd`
# 修改node4的角色狀態並降低權重
vrrp_instance VI_1 {
    state BACKUP        #MASTER 主和從 
    priority 50      #優先順序 主的優先順序要高
}


# 8. 啟動Keepalived(node1,node4)
service keepalived start
# 檢視日誌
tail /var/log/messages 


# 9. 測試
# a.檢視通過keepalived配置的lvs是否生效(如圖2)
ipvsadm -ln   # 對主備都進行檢視
# 訪問 node1的vip,重新整理瀏覽器,看輪詢演算法是否生效(圖3)

# b.模擬主lvs當機 ,將node1網路卡關閉 ,使node1與外界失聯, 訪問瀏覽器,檢視輪詢演算法是否有異常(無異常:模擬使用者對異常的無感知)
ifconfig eth0 down
# 模擬運維修復主lvs異常 ,在虛擬機器中將網路卡啟動 ,檢視虛擬介面 eth0:3是否從備機自動分配到了主機
ifconfig eth0 up

# c.關閉啟動一個real server(node2/node3) ,檢視keepalived是否將宕掉的real剔除(keepalived不僅對準備做健康檢查還會對realserver做健康檢查)
service httpd stop  # 測試完畢後重啟服務
ipvsadm -ln        # 對主備都進行檢視

# d.模擬keepalived軟體異常退出(在node1中執行)
ps -ef | grep keep   # 定位keepalived的所有埠號
kill  -9 埠號   # 所有都結束
#這樣做的結果是備機node4也會擁有介面eth0:3, 而導致主備都會擁有同一個vip的情況 
#我們都知道在網際網路中ip地址必須唯一,所以這樣做是非常危險的,同時這也是keepalived的一個bug



步驟5修改的內容程式碼

# 主要是對埠號,virtual_ipaddress,persistence_timeout,lb_kind DR,心跳檢查返回的狀態的膝蓋
# 這裡沒出現的建議刪除

global_defs {
   notification_email {
     root@localhost  #傳送提醒郵件的目標地址可有多個
     goldbin@126.com
  }
   notification_email_from test@localhost              #傳送郵件的from地址,可以隨意寫,郵件地址不存在都無所謂
   smtp_server 127.0.0.1             #郵件服務的地址,一般寫本地
   smtp_connect_timeout 30
   router_id LVS_DEVEL
}


vrrp_instance VI_1 {
    state MASTER        #MASTER 主和從 
    interface eth0        #VIP需要繫結的網路卡名稱
    virtual_router_id 51
    priority 100       #優先順序 主的優先順序要高
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {  
        192.168.179.100/24 dev eth0 label eth0:3         #設定VIP
    }
}


virtual_server 192.168.179.100 80 {       #設定虛擬lvs服務,VIP PORT
    delay_loop 6
    lb_algo rr   #排程演算法wrr
    lb_kind DR  #lvs的模式
    nat_mask 255.255.255.0
   # persistence_timeout 50 同一個IP地址在50秒內lvs轉發給同一個後端伺服器
    persistence_timeout 0
    protocol TCP
  
    real_server 192.168.179.141 80 {       #設定真實伺服器的心跳機制 RID PORT
        weight 1      #權重
        HTTP_GET {      #心跳檢測的方式
            url {
              path /      #心跳檢查的地址
              status_code 200      #心跳檢查返回的狀態
            }
            connect_timeout 3       #超時時間
            nb_get_retry 3      #重複檢查3次
            delay_before_retry 3      #每隔1秒鐘再次檢查
        }
    }
    real_server 192.168.179.142 80 {      #第二個真實伺服器設定
      weight 1      #權重
        HTTP_GET {      #心跳檢測的方式
            url {
              path /      #心跳檢查的地址
              status_code 200      #心跳檢查返回的狀態
            }
            connect_timeout 2       #超時時間
            nb_get_retry 3      #重複檢查3次
            delay_before_retry 3      #每隔1秒鐘再次檢查
        }
   }

}

圖1
在這裡插入圖片描述
圖2
在這裡插入圖片描述

圖3
在這裡插入圖片描述
在這裡插入圖片描述

第四章 Nginx和 Tengine

一 介紹

Nginx

Nginx (“engine x”) 是一個高效能的 HTTP 和 反向代理伺服器,也是一個 IMAP/POP3/SMTP 代理伺服器。
其將原始碼以類BSD許可證的形式釋出,因它的穩定性、豐富的功能集、
示例配置檔案和低系統資源的消耗而聞名 .官方測試nginx能夠支撐5萬併發連結,
並且cpu、記憶體等資源消耗卻非常低,執行非常穩定. 其特點是佔有記憶體少,併發能力強,
事實上nginx的併發能力確實在同型別的網頁伺服器中表現較好,
中國大陸使用nginx網站使用者有:新浪、網易、騰訊等。

Tengine

Tengine 是nginx的加強版,封裝版 ,淘寶開源 ,官網http://tengine.taobao.org/
動態模組載入(DSO)支援。加入一個模組不再需要重新編譯整個Tengine;
支援SO_REUSEPORT選項,建連效能提升為官方nginx的三倍;
支援SPDY v3協議,自動檢測同一埠的SPDY請求和HTTP請求;
流式上傳到HTTP後端伺服器或FastCGI伺服器,大量減少機器的I/O壓力;
更加強大的負載均衡能力,包括一致性hash模組、會話保持模組,還可以對後端的伺服器進行主動健康檢查,根據伺服器狀態自動上線下線,以及動態解析upstream中出現的域名;
輸入過濾器機制支援。通過使用這種機制Web應用防火牆的編寫更為方便;
支援設定proxy、memcached、fastcgi、scgi、uwsgi在後端失敗時的重試次數
動態指令碼語言Lua支援。擴充套件功能非常高效簡單;
支援管道(pipe)和syslog(本地和遠端)形式的日誌以及日誌抽樣;
支援按指定關鍵字(域名,url等)收集Tengine執行狀態;
組合多個CSS、JavaScript檔案的訪問請求變成一個請求;
自動去除空白字元和註釋從而減小頁面的體積

常用高併發模型設計

利用lvs來管理Nginx ,每臺Nginx可支撐五萬連結 ,因此通過這樣的架構可以輕鬆實現對百萬連結支撐的請求

在這裡插入圖片描述

二 Nginx和apache(httpd)的優缺點

  1. nginx相對於apache的優點:
    輕量級,同樣起web 服務,比apache 佔用更少的記憶體及資源
    抗併發,nginx 處理請求是非同步非阻塞的,而apache 則是阻塞型的,在高併發下nginx 能保持低資源低消耗
    高效能, 高度模組化的設計,編寫模組相對簡單 社群活躍,各種高效能模組出品迅速

  2. apache 相對於nginx 的優點:
    rewrite ,比nginx 的rewrite 強大
    模組多,基本想到的都可以找到
    少bug ,nginx 的bug 相對較多

  3. Nginx 配置簡潔, Apache 複雜

  4. ,最核心的區別在於apache是同步多程式模型,一個連線對應一個程式;nginx是非同步的,多個連線(萬級別)可以對應一個程式

三 安裝Tengine並製作Nginx指令碼

Tengine整合了nginx ,所以我們只需要安裝Tengine即可

# 1、安裝依賴 gcc openssl-devel pcre-devel zlib-devel
yum install gcc openssl-devel pcre-devel zlib-devel -y

# 2.上傳Tengine,解壓,複製
# 要注意我們所複製後的目錄以及複製後的檔名
tar tengine-2.1.0.tar.gz -rf
cp tengine-2.1.0 /usr/local/ -rf

# 3. 在複製後的tengine-2.1.0目錄下執行
./configure \
  --prefix=/usr/local/tengine-2.1.0


# 4 .編譯安裝
make && make install

# 5. 上傳指令碼使nginx可以像服務一樣啟動 ,內容在下一個程式碼塊
cd /etc/init.d/
chmod +x nginx 

# 6. 執行nginx服務
service nginx  start

# ps:如果出現沒有相關檔案的錯誤, 請使用touch目錄建立
# 在瀏覽器輸入配置Tengine的ip即可訪問,如下圖

指令碼內容

注意這裡配置的路徑要與我們make install所在的目錄一致
nginx="/usr/local/tengine-2.1.0/sbin/nginx"
NGINX_CONF_FILE="/usr/local/tengine-2.1.0/conf/nginx.conf"

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig:   - 85 15 
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /etc/nginx/nginx.conf
# config:      /etc/sysconfig/nginx
# pidfile:     /var/run/nginx.pid
 
# Source function library.
. /etc/rc.d/init.d/functions
 
# Source networking configuration.
. /etc/sysconfig/network
 
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
 
nginx="/usr/local/tengine-2.1.0/sbin/nginx"
prog=$(basename $nginx)
 
NGINX_CONF_FILE="/usr/local/tengine-2.1.0/conf/nginx.conf"
 
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
 
lockfile=/var/lock/subsys/nginx
 
make_dirs() {
   # make required directories
   user=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
   options=`$nginx -V 2>&1 | grep 'configure arguments:'`
   for opt in $options; do
       if [ `echo $opt | grep '.*-temp-path'` ]; then
           value=`echo $opt | cut -d "=" -f 2`
           if [ ! -d "$value" ]; then
               # echo "creating" $value
               mkdir -p $value && chown -R $user $value
           fi
       fi
   done
}
 
start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    make_dirs
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
 
stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
 
restart() {
    configtest || return $?
    stop
    sleep 1
    start
}
 
reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}
 
force_reload() {
    restart
}
 
configtest() {
  $nginx -t -c $NGINX_CONF_FILE
}
 
rh_status() {
    status $prog
}
 
rh_status_q() {
    rh_status >/dev/null 2>&1
}
 
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac

Tengine配置成功圖
在這裡插入圖片描述

四 配置檔案nginx.conf

位於Nginx編譯安裝後指定的目錄
cd /usr/local/tengine-2.1.0/conf/nginx.conf

配置檔案解讀

#1.定義Nginx執行的使用者和使用者組
user root root;

#nginx程式數,建議設定為等於CPU總核心數。
worker_processes 1;

#全域性錯誤日誌定義型別,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log info;

#程式檔案
pid /var/run/nginx.pid;

#一個nginx程式開啟的最多檔案描述符數目,理論值應該是最多開啟檔案數(系統的值ulimit -n)與nginx程式數相除,但是nginx分配請求並不均勻,所以建議與ulimit -n的值保持一致。
worker_rlimit_nofile 65535;
#工作模式與連線數上限
events {
    #參考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本核心中的高效能網路I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
    use epoll;
    #單個程式最大連線數(總的最大連線數=連線數*程式數)
    worker_connections 1024;
}


#2. event下的一些配置及其意義
 #單個後臺worker process程式的最大併發連結數    
    #worker_connections  1024;
    # 併發總數是 worker_processes 和 worker_connections 的乘積
    # 即 max_clients = worker_processes * worker_connections
    # 在設定了反向代理的情況下,max_clients = worker_processes * worker_connections / 4  為什麼
    # 為什麼上面反向代理要除以4,應該說是一個經驗值
    # 根據以上條件,正常情況下的Nginx Server可以應付的最大連線數為:4 * 8000 = 32000
    # worker_connections 值的設定跟實體記憶體大小有關
    # 因為併發受IO約束,max_clients的值須小於系統可以開啟的最大檔案數
	# 而系統可以開啟的最大檔案數和記憶體大小成正比,一般1GB記憶體的機器上可以開啟的檔案數大約是10萬左右
    # 我們來看看360M記憶體的VPS可以開啟的檔案控制程式碼數是多少:
    # $ cat /proc/sys/fs/file-max
    # 輸出 34336
    # 32000 < 34336,即併發連線總數小於系統可以開啟的檔案控制程式碼總數,這樣就在作業系統可以承受的範圍之內
    # 所以,worker_connections 的值需根據 worker_processes 程式數目和系統可以開啟的最大檔案總數進行適當地進行設定
    # 使得併發總數小於作業系統可以開啟的最大檔案數目
    # 其實質也就是根據主機的物理CPU和記憶體進行配置
    # 當然,理論上的併發總數可能會和實際有所偏差,因為主機還有其他的工作程式需要消耗系統資源。
    # ulimit -SHn 65535

#3. 設定http伺服器
http {
    include mime.types; #副檔名與檔案型別對映表
    default_type application/octet-stream; #預設檔案型別
    #charset utf-8; #預設編碼
    server_names_hash_bucket_size 128; #伺服器名字的hash表大小
    client_header_buffer_size 32k; #上傳檔案大小限制
    large_client_header_buffers 4 64k; #設定請求緩
    client_max_body_size 8m; #設定請求緩
    sendfile on; #開啟高效檔案傳輸模式,sendfile指令指定nginx是否呼叫sendfile函式來輸出檔案,對於普通應用設為 on,如果用來進行下載等應用磁碟IO重負載應用,可設定為off,以平衡磁碟與網路I/O處理速度,降低系統的負載。注意:如果圖片顯示不正常把這個改成off。
    autoindex on; #開啟目錄列表訪問,合適下載伺服器,預設關閉。
    tcp_nopush on; #防止網路阻塞
    tcp_nodelay on; #防止網路阻塞
    keepalive_timeout 120; #長連線超時時間,單位是秒
    
    #5. gzip模組設定
    gzip on; #開啟gzip壓縮輸出
    gzip_min_length 1k; #最小壓縮檔案大小
    gzip_buffers 4 16k; #壓縮緩衝區
    gzip_http_version 1.0; #壓縮版本(預設1.1,前端如果是squid2.5請使用1.0)
    gzip_comp_level 2; #壓縮等級
    gzip_types text/plain application/x-javascript text/css application/xml;
    #壓縮型別,預設就已經包含text/html,所以下面就不用再寫了,寫上去也不會有問題,但是會有一個warn。
    gzip_vary on;
    #limit_zone crawler $binary_remote_addr 10m; #開啟限制IP連線數的時候需要使用
    
    #6. 虛擬主機的配置
    #nginx支援三種型別的虛擬主機配置,
    #1、基於ip的虛擬主機, (一塊主機繫結多個ip地址)
    #2、基於域名的虛擬主機(servername)
    #3、基於埠的虛擬主機(listen如果不寫ip埠模式)
    server {
        #監聽埠
        listen 80;
        #域名可以有多個,用空格隔開
        server_name www.ha97.com ha97.com;

    #7. location 對映(ngx_http_core_module)
    	#location [ = | ~ | ~* | ^~ ] uri { ... }
    	#location URI {}:
    	#	對當前路徑及子路徑下的所有物件都生效;
    	#location = URI {}: 注意URL最好為具體路徑。
        #   精確匹配指定的路徑,不包括子路徑,因此,只對當前資源生效;
    	#location ~ URI {}:
    	#location ~* URI {}:
    	#	模式匹配URI,此處的URI可使用正規表示式,~區分字元大小寫,~*不區分字元大小寫;
    	#location ^~ URI {}:
    	#	不使用正規表示式
    	#優先順序:= > ^~ > ~|~* >  /|/dir/
        #=字首的指令嚴格匹配這個查詢。如果找到,停止搜尋。
        # 特別注意: 所有剩下的常規字串,最長的匹配。如果這個匹配使用^〜字首,搜尋停止。 
        #正規表示式,在配置檔案中定義的順序。
        #如果第3條規則產生匹配的話,結果被使用。否則,如同從第2條規則被使用
        #先普通
            #順序無關
            #最大字首
            #匹配規則簡單
            #打斷:
                #^~
                #完全匹配
        #再正則
            #不完全匹配
            #正則特殊性:一條URI可以和多條location匹配上
            #有順序的
            #先匹配,先應用,即時退出匹配
        #IP訪問控制
        #location  {
        	  # deny  IP /IP段   禁止訪問
        	   #deny  192.168.1.109;
        	   #allow 192.168.1.0/24;192.168.0.0/16;192.0.0.0/8   允許訪問
        	#}
        #規則:按照順序依次檢測,直到匹配到第一條規則
       # 使用者認證訪問
        #模組ngx_http_auth_basic_module 允許使用“HTTP基本認證”協議驗證使用者名稱和密碼來限制對資源的訪問。
        #	location / {
        #		auth_basic           "closed site";
        #		auth_basic_user_file /var/users;
        #    }
        #Apache發行包中的htpasswd命令來建立user_file 檔案
        
        #要通過yum –y install httpd
        #htpasswd -c -m /var/users username
        #注:需要安裝httpd才可以使用上面命令
        

        location ~ .*\.(php|php5)?$
            index index.html index.htm index.jsp;
            root /data/www/ha97;
        {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.jsp;
        include fastcgi.conf;
    }
}    

ps :
通過淘寶Tengine 檢視Tengine技術以及Nginx中文文件
Nginx中文地址

技術延伸

通過對Tengine中Nginx的配置檔案修改達到下面的效果

利用Nginx配置虛擬Server

# 1.修改配置檔案
# 修改配置檔案中的server, 修改了server_name
# 建立了一個server,配置server_name ,listen 以及location

 	server {
        listen 80;
        server_name www.chy.com;
        location / {
            root   /mnt;
            autoindex on;    #這裡配置了自動索引
        }

         }
    server {
        listen       80;
        server_name  www.timepause.com;


        #charset koi8-r;

        #access_log  logs/host.access.log  main;

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



# 2. 重新載入nginx ( 需要將Nginx封裝成一個服務,本章第三節支援 )
service nginx reload

# 3. 在本地hosts檔案中配置地址對映,將上面配置的兩個域名對映到有nginx的虛擬機器中
# hosts 檔案位於 C:\Windows\System32\drivers\etc下
192.168.179.140  www.chy.com www.timepause.com

# 4.測試訪問
www.timepause.com   如圖1
www.chy.com              如圖2

# 5. 如果虛擬機器新增了光碟檔案.可以掛載,以列表的形式進行顯示
mount /dev/cdrom /mnt/
# 再次訪問  www.chy.com (這樣可以做yum的本地安裝庫, 如圖3)
#思路 :找一臺物理機+nginx可以作為公司的本地安裝源

圖1
在這裡插入圖片描述
圖2
在這裡插入圖片描述
如3
在這裡插入圖片描述

利用Nginx對伺服器做反向代理

在配置檔案中的server配置中的location中新增如下配置

location / {
           root   html;
            index  index.html index.htm;
        }
         location /chy.doc {
             proxy_pass http://192.168.179.141/;
         }
        location ~* \.go$  {
            proxy_pass http://192.168.179.142;
        }

通過上面配置並過載服務, 即可實現對指定uri的靜態訪問攔截 ,與動態攔截(圖1)
靜態攔截如圖2,圖3. 可以攔截server_name後面為 /chy.doc的請求,
但會在url中將 chy.doc 去掉, 因此我們實際訪問的都是Index.html頁面

如訪問 server_name/chy.doc/index.html 通過Nginx處理後實際訪問的是 192.168.179.141/index.html
訪問 server_bane/chy.doc 通過Nginx處理後實際訪問的是 192.168.179.141/ ,這裡預設的也是訪問index.html

正規表示式動態攔截, 可以攔截 .go 結尾的uri, 並且以 ip/uri 的路徑將其轉發(不會去掉該uri ,圖4),
如訪問 server_name/index.go 通過Nginx處理後實際訪問的是 192.168.179.142/index.go
但是要求我們在 192.168.179.192這臺主機需要有 index.go頁面處理

圖1
在這裡插入圖片描述

圖2
在這裡插入圖片描述

圖3
在這裡插入圖片描述
圖4
在這裡插入圖片描述

利用Nginx做反向代理負載均衡

修改Tengine 中的nginx中的配置檔案nginx.config

# 1. 修改超時時間,如果不為0 ,會等到超時時間結束才會被負載到另一個伺服器, 
keepalive_timeout  0;

# 2. 建立 upstream配置, 名稱任意 ,配置用於負載的伺服器, 一般位於server配置的上方
upstream testbalance {
        server 192.168.179.141;
        server 192.168.179.142;
    }

# 3. 配置反向代理
# 過載服務後, 我們只需要訪問 server_name+用於反向代理的localtion.即http://www.timepause.com/test
#就會被隨機負載到 .141和 .142的兩臺伺服器上了( 圖1,圖2 )
  location /test {                    							  # location後的攔截路徑名任意,但是需要有"/"
             proxy_pass http://testbalance/;            # 這裡最後也要有 "/;"
         }
         
----------------------------------------------------------
    server {
        listen       80;
        server_name  www.timepause.com;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
           root   html;
            index  index.html index.htm;
        }
         location /test {
             proxy_pass http://testbalance/;
         }
}
----------------------------------------------------------

圖1
在這裡插入圖片描述
圖2
在這裡插入圖片描述

利用Nginx 對指定域名(百度)進行代理

在 nginx.conf中的server配置中新增如下程式碼 ,修改後需要過載nginx服務

location /baidu {
             proxy_pass https://www.baidu.com/;
         }
# 過載nginx服務,訪問 (圖1)
service nginx reload 

注意 :

  1. 如果遇到圖3問題需要配置預設閘道器route add default gw 閘道器地址要根據自己所在網段進行配置

  2. 我們需要注意的是避免域名直接的跳轉 ,如果我們將反向代理寫成了這個 http://www.baidu.com/ ,
    由於現在的網址使用的協議大多都是https(安全性考慮) ,通過Nginx代理後的目錄就是( 圖2 ),
    導致Nginx不能對當前域名進行管理, 因此在今後的專案程式碼中儘量不要出現客戶端的跳轉
    以後在企業開發時一定多多注意類似問題

圖1
在這裡插入圖片描述
圖2
在這裡插入圖片描述

圖3
在這裡插入圖片描述

小技巧 :利用 !命令的前幾個字元匹配命令並執行

舉例 ,其他命令也同本例

# 利用 ifconfig 命令檢視網路資訊,圖1
ifconfig 

# 利用 !if 可快速執行上一個,命令,圖2
!if

#這個命令的原理是會呼叫 history 命令來檢視我們的歷史命令,
#通過對我們在!後書寫的字元進行匹配 ,如果匹配到就進行執行該命令

圖1
在這裡插入圖片描述

圖2
在這裡插入圖片描述

nginx如何識別我們的域名

我們傳送這樣的域名請求時 ,雖然域名被本地hosts檔案對映到了對應的虛擬機器ip地址,因此我們實際訪問的其實是對應的IP地址
但我們仍可以根據域名訪問到對應的地址 , 這是因為在我們傳送域名請求時, 域名資訊也會被封裝到請求頭的Host中傳送(圖1)
Nginx掃描請求頭中的資訊(域名/ip/埠) ,然後與Nginx的配置檔案的server配置(圖2)進行比對 ,如果符合就跳轉到對應的頁面

在這裡插入圖片描述
圖2
在這裡插入圖片描述

利用Nginx的access.log監聽使用者的瀏覽資訊

該日誌檔案位於Nginx目錄下的: logs/access.log
利用 tail -f access.log 可以通過Nginx持續監聽使用者在被Nginx代理的網站的瀏覽記錄
例如下圖中我訪問了chy.com 的 /EFI 目錄 ,而日誌中就會顯示我的訪問資訊
個人感覺這個功能可能在資料收集中可能會有意想不到的作用

在這裡插入圖片描述

五 session一致性問題的解決

情景模擬

三臺虛擬機器node1,node2,node3
node2,3安裝jdk與tomcat(目的是執行tomcat)
node1 安裝Nginx, memcached

# 1. 修改主頁,便於識別,檢視session,訪問頁面,如圖1,圖2
# node2中的tomcat的index頁面, 清除所有內容,編寫如下程式碼 ,用於分辨主機以及對應的session資訊(  位於/webapps/ROOT/index.jsp )
-----------------------------------
from 192.168.179.141<br>
<%=session.getId()%>

# node3中的tomcat的index頁面,清除所有內容,編寫如下程式碼(  /webapps/ROOT/index.jsp )
-----------------------------------
from 192.168.179.142<br>
<%=session.getId()%>

# 2 利用Nginx代理上面兩個伺服器(給我們的感覺是代理了兩個tomcat主頁 ) ,修改nginx.conf (配置負載均衡upstream 以及location  )
----------------------------配置的內容-----------------
 upstream test.tomcat.session {
        server 192.168.179.141:8080;
        server 192.168.179.142:8080;
        }

   server {
        listen       80;
        server_name  www.timepause.com;
        
        location /tomcat {
          proxy_pass http://test.tomcat.session/;
        }

}

# 3. 過載nginx 服務,訪問 瀏覽器 ,可以看到一直重新整理可以分別訪問到這兩個tomcat主頁(圖3,圖4 )
http://www.timepause.com/tomcat

# 4.觀察session變化我們可以看到,每次重新整理session都會改變,這裡就說明出現了session不一致的情況,下面我們將解決這個問題

圖1
在這裡插入圖片描述
圖2
在這裡插入圖片描述

圖3
在這裡插入圖片描述
圖4
在這裡插入圖片描述

解決方案——安裝memcached

安裝memcached可以為我們解決seession的問題

# 1、安裝memcached(node1)
  yum -y install memcached
  
# 2、啟動memcached(node1)
	memcached -d -m 128m -p 11211 -l 192.168.179.140 -u root -P /tmp/
	-d:後臺啟動服務
	-m:快取大小
	-p:埠
	-l:IP
	-P:伺服器啟動後的系統程式ID,儲存的檔案
	-u:伺服器啟動是以哪個使用者名稱作為管理使用者

	
# 3. 修改node2,node3中tomcat中conf  ( context.xml ), 注意memcachedNodes的配置
------------------------------------------------------------------------
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" 
	memcachedNodes="n1:192.168.179.140:11211" 
    sticky="false" 
    lockingMode="auto"
    sessionBackupAsync="false"
	requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
    sessionBackupTimeout="1000" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />



# 4、拷貝jar到tomcat的lib下 ,分享在部落格末尾
[asm-3.2.jar]
[kryo-1.04.jar]
[kryo-serializers-0.11.jar]
[memcached-session-manager-1.7.0.jar]
[memcached-session-manager-tc7-1.8.1.jar]
[minlog-1.2.jar]
[msm-kryo-serializer-1.7.0.jar]
[reflectasm-1.01.jar]
[spymemcached-2.7.3.jar]


5. 重啟tomcat ,訪問測試
由圖1,圖2可以看到執行memcached 就消除了一致性問題 ,而且他們的時間也被一致化了

注意: 時間一致性
不僅是Nginx代理的tomcat需要時間一致, 叢集中時間也必須一致 ,
檢視虛擬機器當前時間命令 date , 通過date -s 設定時間 .
可以通過xshell的全部會話功能( 圖3 )來同步時間

[root@node4 ~]# date -s "2011-11-11 11:11:11"
Fri Nov 11 11:11:11 CST 2011

圖1

在這裡插入圖片描述
圖2
在這裡插入圖片描述
圖3
在這裡插入圖片描述

連結:https://pan.baidu.com/s/11KOnUQcDOEfSkmYcZdU9jw
提取碼:nc38
複製這段內容後開啟百度網盤手機App,操作更方便哦

相關文章