Linux——(8)Nginx

1、高併發基礎架構php

 

簡要流程:css

  1.客戶端發請求。html

  2.又LVS等四層負載均衡系統將請求轉發給不一樣的Nginx服務器。java

  3.Nginx與客戶端創建TCP鏈接,拿到請求後分析URI,而後將其轉發給對應的功能模塊服務(Tomcat容器)。linux

  4.等待後端功能模塊服務的響應。nginx

  5.功能模塊進行計算,並從後端存儲中獲取數據,並返回。web

  6.Nginx收到響應後返回給客戶端。正則表達式

 

2、Nginx和Tengineshell

    Nginx(engin x)是一個高性能的HTTP和反向代理服務器,也是一個IMAP/POP3/SMTP代理服務器。數據庫

    主要以穩定性、豐富的功能集、低系統資源消耗而聞名。

    官方測試nginx可以支撐5萬併發鏈接,而且CPU、內存等資源消耗很是低,運行穩定。

 

什麼是反向代理(通俗理解)?

  正向代理:是代用戶訪問遠程資源。 例如咱們要訪問國外的網站,咱們能夠經過位於香港等地的代理服務器來幫咱們從國外獲取資源,但咱們請求的目的仍是真正的國外服務器地址。國外服務器看到的請求方是代理服務器。

  反向代理:就是幫後端資源進行代理,也就是咱們看到的目標服務器就是該反向代理服務器,而看不到真正提供資源的服務器。咱們看到的資源地址是反向代理服務器。

 

Nginx相對apache的優勢:

1.nginx是輕量級,一樣web服務,比apache佔用更少的內存及資源。

2.抗併發,nginx是異步非阻塞的,而apache是阻塞型的,在高併發下nginx保持低資源消耗,高性能

3.高度模塊化的設計,編寫模塊相對簡單

4.社區活躍,各類高性能模塊出品迅速

5.配置簡潔

apache的優勢:

1.rewrite強大

2.模塊超多

3.bug少

 

最核心的不一樣:

    apache是同步多進程模型(select),一個連接對應一個進程;nginx是異步(epoll),多個連接(萬級別)對應一個進程。

    nginx不會浪費時間在進程的切換上,因此效率很高。

 

3、安裝Nginx(Tengine)

1.安裝依賴

yum install gcc pcre-devel openssl-devel -y

 

2.下載tengine包,並解壓

cd ~
wget http://tengine.taobao.org/download/tengine-2.3.0.tar.gz
tar zxf tengine-2.3.0.tar.gz

 

3.安裝tengine

cd tengine-2.3.0
./configure --prefix=/opt/nginx

**企業標準安裝:

./configure 
--prefix=/usr
--sbin-path=/usr/sbin/nginx
--conf-path=/etc/nginx/nginx.conf
--error-log-path=/var/log/nginx/error.log 
--http-log-path=/var/log/nginx/access.log 
--pid-path=/var/run/nginx/nginx.pid
--lock-path=/var/lock/nginx.lock
--user=nginx
--group=nginx
--with-http_ssl_module
--with-http_flv_module
--with-http_stub_status_module
--with-http_gzip_static_module
--http-client-body-temp-path=/var/tmp/nginx/client/ 
--http-proxy-temp-path=/var/tmp/nginx/proxy/ 
--http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ 
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi
--http-scgi-temp-path=/var/tmp/nginx/scgi
--with-pcre
make && make install

 

4.設置nginx爲系統服務

添加nginx.service文件:

vi /usr/lib/systemd/system/nginx.service

[Unit]
Description=The nginx HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/opt/nginx/logs/nginx.pid
ExecStartPre=/opt/nginx/sbin/nginx -t
ExecStart=/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

注意,全部path的部分都要修改成實際安裝nginx的目錄。

 

使用systemctl啓動nginx:

systemctl start nginx.service

使用瀏覽器訪問(默認監聽80端口,能夠在nginx.conf中修改):

其餘服務操做:

# 設置開機啓動
systemctl enable nginx.service
# 中止服務
systemctl stop nginx.service
# 重啓服務
systemctl restart nginx.service
# 取消開機啓動
systemctl disable nginx.service
# 查看服務運行狀態
systemctl status nginx.service

查看全部已啓動服務:

systemctl list-units --type=service

查看開機啓動服務列表:

[root@real-server-1 conf]# systemctl list-unit-files
UNIT FILE STATE proc
-sys-fs-binfmt_misc.automount static dev-hugepages.mount static dev-mqueue.mount static proc-sys-fs-binfmt_misc.mount static sys-fs-fuse-connections.mount static sys-kernel-config.mount static sys-kernel-debug.mount static tmp.mount disabled brandbot.path enabled systemd-ask-password-console.path static systemd-ask-password-plymouth.path static systemd-ask-password-wall.path static session-1.scope static arp-ethers.service disabled auditd.service enabled autovt@.service enabled blk-availability.service disabled brandbot.service static chrony-dnssrv@.service static chrony-wait.service disabled chronyd.service enabled console-getty.service disabled console-shell.service disabled container-getty@.service static cpupower.service disabled crond.service enabled dbus-org.freedesktop.hostname1.service static dbus-org.freedesktop.import1.service static dbus-org.freedesktop.locale1.service static dbus-org.freedesktop.login1.service static dbus-org.freedesktop.machine1.service static dbus-org.freedesktop.timedate1.service static dbus.service static debug-shell.service disabled dm-event.service static dnsmasq.service disabled

 

4、配置Nginx(Tengine)

1.修改nginx配置文件:

[root@real-server-1 conf]# vi /opt/nginx/conf/nginx.conf

      1 
      # 雖然user nobody是註釋掉的,但仍然在使用,固然也能夠修改成任意用戶。子進程worker是nobody用戶全部。父進程是root用戶的。
      2 #user  nobody;
      # worker_processes 是真正作事的進程的數量,通常爲物理核心的1-2倍
      3 worker_processes  1;
      4 
      # 配置日誌
      5 #error_log  logs/error.log;
      6 #error_log  logs/error.log  notice;
      7 #error_log  logs/error.log  info;
      8 #error_log  "pipe:rollback logs/error_log interval=1d baknum=7 maxsize=2G";
      9 
     10 #pid        logs/nginx.pid;
     11 
     12
     # worker_connection很重要,除了修改此處的數字,還須要修改操做系統內核容許進程所能操做文件描述符的數量。
     # 使用ulimit -a能夠查看當前內核容許的進程操做文件描述符的數量(open files)。
     # 操做系統所能操做文件描述符的總數通常和內存成正比(例如1GB對應10W個文件描述符)。
     # 咱們在考慮worker_connnection時,除了考慮客戶端鏈接數,還要考慮nginx從後端請求數據時的socket,因此須要配置得更大一些。
     # 使用ulimit -SHn 65535能夠修改內核限制,而且這裏也修改成對應的數量。
     13 events {
     14     #worker_connections  1024;
              worker_connections  65535;
     15 }
     16 
     17 # load modules compiled as Dynamic Shared Object (DSO)
     18 #
     19 #dso {
     20 #    load ngx_http_fastcgi_module.so;
     21 #    load ngx_http_rewrite_module.so;
     22 #}
     23 
     24 http {
     25     include       mime.types;
     26     default_type  application/octet-stream;
     27 
     # 日誌記錄的格式化,控制日誌怎麼記錄,作日誌分析的時候能夠參照這裏的規範(重要)
     # 有些公司使用nginx作小數據的採集,就能夠直接使用日誌來記錄,例如傳感器數據,直接訪問nginx,將小數據傳遞過來,寫進日誌。
     28     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
     29     #                  '$status $body_bytes_sent "$http_referer" '
     30     #                  '"$http_user_agent" "$http_x_forwarded_for"';
     31 
     32     #access_log  logs/access.log  main;
     33     #access_log  "pipe:rollback logs/access_log interval=1d baknum=7 maxsize=2G"  main;
     34 
     # (重要)零拷貝,例如nginx讀取文件內容,而後返回給客戶端的過程。首先調內核,讓內核讀取文件,讀到的內容放在內核的緩衝區。
     # 而後將內核緩衝區的內容拷貝到用戶態buffer中。當要從socket發送給客戶端時,又要從用戶態buffer將內容拷貝到socket在內核的緩衝區。
     # 這樣就要進行兩次內核態和用戶態之間的數據拷貝。
     # 零拷貝的意思就是,nginx調內核讀取文件的時候,直接告訴內核文件和socker(也就是輸入和輸出),而後內核讀取數據後,直接將數據用socket發送給客戶端。
     # 這就減小了2次拷貝的時間,效率大大提升。
     35     sendfile        on;
     # 就是socket buffer是否寫滿才發送,相似於執行不執行flush。
     36     #tcp_nopush     on;
     37 
     # http1.1擴充了一個字段交keepalive,就是tcp連接保持長鏈接多久才斷開。作實驗咱們爲了看效果,設置爲0。正式環境應該配一個合適的值。
     38     keepalive_timeout  0;
     39     #keepalive_timeout  65;
     40 
     # 返回時是否壓縮數據,減小IO和帶寬消耗。能夠提供更多的請求響應。
     41     #gzip  on;
     42 
     # 其中一個虛擬服務器(nginx能夠支持多個虛擬服務器,他能夠用請求頭中的Host域名來區分,經過瀏覽器F12查看)
     # 也就是說若是DNS上有兩個域名指向同一個IP地址,nginx能夠經過兩個域名來提供2個虛擬服務,都使用80端口
     43     server {
     # 監聽的端口是80
     44         listen       80;
     # 虛擬服務器名,就是域名。例如DNS中有兩個域名,www.123.com,www.234.com,這裏填寫其中一個。
     45         server_name  localhost;  # www.123.com
     46 
     47         #charset koi8-r;
     48 
     49         #access_log  logs/host.access.log  main;
     50         #access_log  "pipe:rollback logs/host.access_log interval=1d baknum=7 maxsize=2G"  main;
     51 
     # 訪問的根,也就是http://www.123.com/
     52         location / {
     # root是相對路徑,html就是咱們安裝nginx的地方/opt/nginx/html目錄
     53             root   html;
     # index用來定義默認根頁面
     54             index  index.html index.htm;
     55         }
     56 
     57         #error_page  404              /404.html;
     58 
     59         # redirect server error pages to the static page /50x.html
     60         #
     61         error_page   500 502 503 504  /50x.html;
     62         location = /50x.html {
     63             root   html;
     64         }
     65 
     66         # proxy the PHP scripts to Apache listening on 127.0.0.1:80
     67         #
     68         #location ~ \.php$ {
     69         #    proxy_pass   http://127.0.0.1;
     70         #}
     71 
     72         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
     73         #
     74         #location ~ \.php$ {
     75         #    root           html;
     76         #    fastcgi_pass   127.0.0.1:9000;
     77         #    fastcgi_index  index.php;
     78         #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
     79         #    include        fastcgi_params;
     80         #}
     81 
     82         # deny access to .htaccess files, if Apache's document root
     83         # concurs with nginx's one
     84         #
     85         #location ~ /\.ht {
     86         #    deny  all;
     87         #}
     88     }

其中Location是很是重要的,咱們能夠參看官方文檔中Location的語法:

http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_core_module.html#location

 

能夠看到如下內容:

讓咱們用一個例子解釋上面的說法:

location = / {
    [ configuration A ]
}

location / {
    [ configuration B ]
}

location /documents/ {
    [ configuration C ]
}

location ^~ /images/ {
    [ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ { 
    [ configuration E ] 
} 
請求「/」匹配配置A, 請求「/index.html」匹配配置B, 請求「/documents/document.html」匹配配置C, 請求「/images/1.gif」匹配配置D, 請求「/documents/1.jpg」匹配配置E。

 

符號解釋:

  "=":精確匹配

  "/dir/":當前路徑及子路徑都匹配,最大前綴匹配,但注意,是用這個字段去和用戶請求的URI匹配,而不是反過來。

  "~":後面用正則表達式。區分大小寫

  "~*":後面用正則表達式。不區分大小寫

  "^~":阻斷,匹配到這裏就再也不進行正則匹配,例如上面的/images/1.gif,匹配到/images/,就再也不匹配後面的".gif結尾"。

匹配規則:

  他們有優先級關係: "="  >  "^~"   >  "~ | ~*"  >  "/ | /dir/"

  普通location之間是無匹配順序的。而正則location之間是有順序的,只要匹配到第一個就不匹配後面的。

  若是匹配到^~項,後面的正則也不進行匹配。

  普通location和正則location之間,先匹配普通的,再考慮是否匹配正則:

    這裏的考慮就是指「可能」,當普通location前使用了^~,則不匹配後面的正則。或者當普通location恰好匹配好(非最大前綴匹配),則也不匹配後面的正則。

以下圖所示:

 

2.添加一個虛擬服務器(yum本地源)

# 這裏添加一個虛擬服務器www.repo.com,將/mnt做爲repo源,經過nginx發佈
server {
    listen  80;
    server_name www.repo.com;
    location / {
        root /mnt;
        # autoindex就是將/mnt的文件列表展現出去
        autoindex on;
    }
}

這裏的域名爲www.repo.com,而訪問index.html的域名爲www.123.com,因此能夠區分咱們要訪問哪一個服務器。

 

配置完nginx.conf後,咱們要重置nginx:

systemctl reload nginx.service

將光盤掛載在/mnt:

mount /dev/cdrom /mnt

在瀏覽器操做系統的hosts中添加響應的DNS映射:

#在windows的hosts中添加如下內容
192.168.1.201    real-server-1    www.123.com    www.repo.com

此時咱們訪問http://www.repo.com:80:

在訪問http://www.123.com:80:

 

 咱們在瀏覽器的F12中查看一下兩個域名訪問時的host字段:

 

 

 咱們能夠看到,兩次請求的請求頭中的Request URL分別是兩個域名,Nginx就能夠經過域名與配置文件的server_name匹配來區分咱們要訪問的服務,匹配到某個服務名後,再將域名後的URI(也就是"/"、"/search/"等)用location字段去匹配。

 

3.反向代理

在location中配置反向代理,將上面第一個server配置加上一個location作反向代理:

server {
        listen       8000;
        server_name  www.123.com;

        location / {
            root   html;
            index  index.html index.htm;
        }
        # 反向代理,訪問192.168.1.202:80
        location /ooxx {
            proxy_pass http://192.168.1.202:80/;
        }
}

此時,咱們訪問www.123.com:80,就不是返回tengine的默認頁面,而是會幫咱們請求192.168.1.202:80的頁面;

 

從結果能夠看出,咱們經過www.123.com:80/ooxx(也就是real-server-1 192.168.1.201)訪問了real-server-2(192.168.1.202的服務),並返回給客戶端。

 

示例:反向代理www.baidu.com:

server {
        listen       8000;
        server_name  www.123.com;

        location / {
            root   html;
            index  index.html index.htm;
        }
        # 反向代理,訪問192.168.1.202:80
        location /ooxx {
            proxy_pass http://192.168.1.202:80/;
        }
        # 代理baidu首頁
        location /baidu {
            proxy_pass https://www.baidu.com/;
        }
}    

使用瀏覽器訪問http://www.123.com/baidu:

 

注意,這裏的proxy_pass配置的是https://www.baidu.com。若是配置成http://www.baidu.com,則百度可能先返回頁面跳轉給瀏覽器,瀏覽器會直接用https://www.baidu.com去訪問百度。因此這裏必定要寫成https協議。

 

咱們使用代理後的百度進行搜索:

 

報錯信息:找不到URL,主要關注後面的URI(s?wd=*****):

咱們再添加一跳location:

server {
        listen       8000;
        server_name  www.123.com;

        location / {
            root   html;
            index  index.html index.htm;
        }
        # 反向代理,訪問192.168.1.202:80
        location /ooxx {
            proxy_pass http://192.168.1.202:80/;
        }
        # 代理baidu首頁
        location /baidu {
            proxy_pass https://www.baidu.com/;
        }
        # 匹配以/s開頭的URI
        location ~* ^/s {
            proxy_pass https://www.baidu.com;
        }  
}    

注意:location /baidu和location ~* ^/s的proxy_pass最後一個帶"/",一個不帶"/",區別很大

若是帶"/"或"/xxx",則會直接使用其進行訪問,例如www.baidu.com/xxx。

若是什麼都不帶,則會使用location的匹配到的URI來串接在後面進行訪問,例如www.baidu.com/s?xxxxxxx(location ~* ^/s)。

 

此時使用代理baidu搜索"香港":

 

 

4.負載均衡

在nginx配置文件中配置負載均衡:

# 在server前面定義一個upstream池
upstream leeoo {
        server 192.168.1.121:80;
        server 192.168.1.202;
}

# 而後在對應的location中,將目標服務器的域名或IP替換爲leeoo
location /ooxx {
        proxy_pass http://leeoo/;
}

此時,當咱們訪問http://www.123.com:80/ooxx時,nginx會自動進行負載均衡,將輪詢訪問leeoo中的兩臺real server。

 

5.Session一致性問題

若是咱們的後端服務器使用的是tomcat等容器,須要爲用戶保存Session。當Nginx將一個用戶連接負載到不一樣的後端服務器時,咱們須要保證他們可以使用同一個Session對用戶進行驗證,不然會出現讓用戶重複登陸的問題;

1)首先,要保證集羣中的服務器時間一致性。

2)使用專門管理Session的軟件,或者使用memcache、Redis等內存數據庫等來幫助Tomcat共享Session。

 

在192.168.1.199上安裝memcached:

yum install memcached -y

使用如下命令啓動:

memcached -d -m 128m -p 11211 -l 192.168.1.199 -u root -P /tmp/

  -m是使用128M內存空間

  -p是使用11211端口進行通訊

  -l是服務器地址

  -u用戶名

使用netstat查看memcached監聽狀況:

[root@lvs-server-1 etc]# netstat -natp | grep 11211
tcp        0      0 192.168.1.199:11211     0.0.0.0:*               LISTEN      1540/memcached      

 

在192.168.1.202和192.168.1.121上安裝JDK和Tomcat:

下載JDK和Tomcat:

apache-tomcat-7.0.96.tar.gz  
jdk-7u80-linux-x64.rpm

安裝JDK:

rpm -i jdk-7u80-linux-x64.rpm

配置環境變量:

vi /etc/profile

# 在最後添加
export JAVA_HOME=/usr/java/jdk1.7.0_80
export PATH=$PATH:$JAVA_HOME/bin

# 使其生效
source /etc/profile

運行jps命令,檢查是否安裝成功:

[root@real-server-2 etc]# jps
1793 Jps

解壓Tomcat:

tar xf apache-tomcat-7.0.96.tar.gz

 

建立一個頁面,讓其打印Session:

cd ~/apache-tomcat-7.0.96/webapps/ROOT
cp index.jsp index.jsp.bak
vi index.jsp

from 192.168.1.202<br>Session: <%= session.getId()%>

啓動Tomcat:

cd ~/apache-tomcat-7.0.96/bin
./startup.sh
[root@real-server-2 bin]# ./startup.sh 
Using CATALINA_BASE:   /root/apache-tomcat-7.0.96
Using CATALINA_HOME:   /root/apache-tomcat-7.0.96
Using CATALINA_TMPDIR: /root/apache-tomcat-7.0.96/temp
Using JRE_HOME:        /usr/java/jdk1.7.0_80
Using CLASSPATH:       /root/apache-tomcat-7.0.96/bin/bootstrap.jar:/root/apache-tomcat-7.0.96/bin/tomcat-juli.jar
Tomcat started.

訪問192.168.1.202:8080:

 

重複刷新,Session是不會變化的,由於咱們訪問的是同一個Tomcat服務器。

 

在192.168.1.202和192.168.1.121上都安裝好Tomcat以後,咱們使用nginx來作負載均衡(192.168.1.201上):

在/opt/nginx/conf/nginx.conf中作以下配置:

upstream tom {
        server 192.168.1.121:8080;
        server 192.168.1.202:8080;
}

server {
        listen       80;
        server_name  www.123.com;

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

        location /cat/ {
            proxy_pass http://tom/;
        }
}

從新載入:

systemctl reload nginx

而後此時訪問www.123.com:80:

 

 

咱們能夠看到,重複訪問的時候,負載均衡是起效的,可是他們的Session不一致的。

 

停掉兩臺機器的Tomcat:

cd ~/apache-tomcat-7.0.96/bin
./shutdown.sh

配置Tomcat使用memcached:

cd /root/apache-tomcat-7.0.96/conf
vi context.xml 

在最後添加以下內容:

<Manager className="de.javakaffee.web.msm.MencachedBackupSessionManager"
        memcachedNodes="n1:192.168.1.199:11211"
    sticky="false"
    lockingMode="auto"
    sessionBackupAsync="false"
        requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
    sessionBackupTimeout="1000" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>

再爲Tomcat的lib中補充須要的一些jar包:

[root@real-server-2 tomcat_jar]# ll
total 804
-rw-r--r-- 1 root root  43398 Feb 26  2019 asm-3.2.jar
-rw-r--r-- 1 root root  94830 Feb 26  2019 kryo-1.04.jar
-rw-r--r-- 1 root root  62112 Feb 26  2019 kryo-serializers-0.11.jar
-rw-r--r-- 1 root root 142281 Feb 26  2019 memcached-session-manager-1.7.0.jar
-rw-r--r-- 1 root root  11283 Feb 26  2019 memcached-session-manager-tc7-1.8.1.jar
-rw-r--r-- 1 root root   4879 Feb 26  2019 minlog-1.2.jar
-rw-r--r-- 1 root root  26511 Feb 26  2019 msm-kryo-serializer-1.7.0.jar
-rw-r--r-- 1 root root  11615 Feb 26  2019 reflectasm-1.01.jar
-rw-r--r-- 1 root root 407912 Feb 26  2019 spymemcached-2.7.3.jar

將這些jar包拷貝到Tomcat的lib目錄中:

cp ~/tomcat_jar/* ~/apache-tomcat-7.0.96/lib

從新啓動tomcat,後再次嘗試訪問http://www.123.com/cat,發現負載均衡正常,Session也不會發生變化。

相關文章
相關標籤/搜索