前言
1.什么是nginx
Nginx (engine x) 是一個高性能的HTTP和反向代理web服務(wù)器,ginx是一款輕量級的Web 服務(wù)器/反向代理服務(wù)器及電子郵件(IMAP/POP3)代理服務(wù)器,在BSD-like 協(xié)議下發(fā)行。其特點是占有內(nèi)存少,并發(fā)能力強,事實上nginx的并發(fā)能力確實在同類型的網(wǎng)頁服務(wù)器中表現(xiàn)較好
2.為什么使用nginx
在傳統(tǒng)的Web項目中,并發(fā)量小,用戶使用的少。所以在低并發(fā)的情況下,用戶可以直接訪問tomcat服務(wù)器,然后tomcat服務(wù)器返回消息給用戶。
用戶訪問<-->Tomcat服務(wù)器
而在互聯(lián)網(wǎng)項目下,因單個tomcat默認并發(fā)量有限制。如果請求量過大,會產(chǎn)生如下問題:
Tomcat8 默認配置的最大請求數(shù)是 150,也就是說同時支持 150 個并發(fā),當(dāng)然了,也可以將其改大。
當(dāng)某個應(yīng)用擁有 250 個以上并發(fā)的時候,應(yīng)考慮應(yīng)用服務(wù)器的集群。
具體能承載多少并發(fā),需要看硬件的配置,CPU 越多性能越高,分配給 JVM 的內(nèi)存越多性能也就越高,但也會加重 GC 的負擔(dān)。
操作系統(tǒng)對于進程中的線程數(shù)有一定的限制:
Windows 每個進程中的線程數(shù)不允許超過 2000
Linux 每個進程中的線程數(shù)不允許超過 1000
Tomcat的最大并發(fā)數(shù)是可以配置的,實際運用中,最大并發(fā)數(shù)與硬件性能和CPU數(shù)量都有很大關(guān)系的。更好的硬件,更多的處理器都會使Tomcat支持更多的并發(fā)。
maxThreads="150" 最大并發(fā)數(shù)
minSpareThreads="10"http:///初始化時創(chuàng)建的線程數(shù)
maxSpareThreads="500"http:///一旦創(chuàng)建的線程超過這個值,Tomcat就會關(guān)閉不再需要的socket線程。
3.高并發(fā)
是互聯(lián)網(wǎng)分布式系統(tǒng)架構(gòu)設(shè)計中必須考慮的因素之一,它通常是指,通過設(shè)計保證系統(tǒng)能夠同時并行處理很多請求。
高并發(fā)相關(guān)常用的一些指標有響應(yīng)時間(Response Time),吞吐量(Throughput),每秒查詢率QPS(Query Per Second),并發(fā)用戶數(shù)等。
響應(yīng)時間: 系統(tǒng)對請求做出響應(yīng)的時間。例如系統(tǒng)處理一個HTTP請求需要200ms,這個200ms就是系統(tǒng)的響應(yīng)時間。
吞吐量: 單位時間內(nèi)處理的請求數(shù)量。
QPS: 每秒響應(yīng)請求數(shù)。在互聯(lián)網(wǎng)領(lǐng)域,這個指標和吞吐量區(qū)分的沒有這么明顯。
并發(fā)用戶數(shù): 同時承載正常使用系統(tǒng)功能的用戶數(shù)量。
高可用(High Availability)
通常來描述一個系統(tǒng)經(jīng)過專門的設(shè)計,從而減少停工時間,而保持其服務(wù)的高度可用性。
(一直都能用 99.9999%)
高性能:
是指服務(wù)響應(yīng)時間快,(CPU/處理器/內(nèi)存)特別是在高并發(fā)下響應(yīng)時間不會急劇增加。
4.Nginx特點:
高并發(fā)、高性能,
可擴展性好,
高可靠性,
熱部署,
BSD許可證。
對于反向代理和正向代理這篇文章講的很仔細了
正向代理和反向代理
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
一、docker安裝nginx
docker run -d --name mynginx --restart=always -v /home/nginx/nginx.conf:/etc/nginx/nginx.conf -v /home/nginx/default.conf:/etc/nginx/conf.d/default.conf -p 8080:80 -t nginx
提示:我是安裝在/home/nginx目錄下的,所以先建這個目錄 mkdir nginx。
-v
表示文件掛載,用法: -v 本地掛載文件:容器目標文件。
-d
容器將在后臺以守護進程的形式運行,而不會阻塞終端。
–restart=always
運行容器時使用–restart參數(shù)可以指定一個restart策略,來指示在退出時容器應(yīng)該如何重啟或不應(yīng)該重啟。
no – 容器退出時不要自動重啟。這個是默認值。
on-failure[:max-retries] – 只在容器以非0狀態(tài)碼退出時重啟??蛇x的,可以退出docker daemon嘗試重啟容器的次數(shù)。
always – 不管退出狀態(tài)碼是什么始終重啟容器。當(dāng)指定always時,docker daemon將無限次數(shù)地重啟容器。容器也會在daemon啟動時嘗試重啟,不管容器當(dāng)時的狀態(tài)如何。
unless-stopped – 不管退出狀態(tài)碼是什么始終重啟容器,不過當(dāng)daemon啟動時,如果容器之前已經(jīng)為停止狀態(tài),不要嘗試啟動它。
查看nginx版本可以通過命令 docker inspect nginx 查看
二、Nginx配置簡介
1.文件講解
文件掛載到本地后會看到兩個文件
default.conf nginx.conf
default.conf:
默認的 nginx 配置文件
nginx.conf:
nginx的主配置文件,它包含了全局配置和一些默認的設(shè)置,影響整個nginx服務(wù)器的行為,這個文件通常用于配置一些全局性的參數(shù)。
2.nginx.conf
cat nginx.conf
user nginx;
#Nginx 主配置文件中的一個重要選項,用于指定 Nginx 服務(wù)器的工作進程數(shù)。
#每個工作進程都是一個獨立的 Nginx 進程,用于處理客戶端請求
#Nginx 將根據(jù)可用的 CPU 核數(shù)動態(tài)確定工作進程的數(shù)量。這樣可以更好地利用多核系統(tǒng)的性能。
#例如:worker_processes 4,配置4個線程
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
#配置與連接處理相關(guān)的參數(shù),如最大連接數(shù)
events {
worker_connections 1024;
}
#配置 HTTP 服務(wù)器的參數(shù),設(shè)定http服務(wù)器,利用它的反向代理功能提供負載均衡支持
http {
#引入其他配置文件,通常用于模塊化配置。在conf/mime.types查看支持哪些類型
include /etc/nginx/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 /var/log/nginx/access.log main;
#是否使用sendfile傳輸文件
sendfile on;
#tcp_nopush on;
#連接超時時間
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
3.default.conf
server {
##配置監(jiān)聽端口
listen 80;
listen [::]:80;
#配置服務(wù)器名
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#配置404頁面
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#配置50x頁面
error_page 500 502 503 504 /50x.html;
#精確匹配
location = /50x.html {
#root是配置服務(wù)器的默認網(wǎng)站根目錄位置,在nginx目錄下html
root /usr/share/nginx/html;
}
#這是轉(zhuǎn)發(fā)php腳本代理到127.0.0.1:80的Apache偵聽
# 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
#
#禁止訪問 .htxxx 文件
#location ~ /\.ht {
# deny all;
#}
}
三、nginx負載均衡
1.配置服務(wù)器列表地址
修改配置文件 vim default.conf注意:我們nginx容器啟動時-p 8080:80, 下面8001,8002,8003端口為別對應(yīng)的三個web容器服務(wù),也需要在啟動時映射端口到80端口,例如 -p 8001:80
upstream servercluster
{
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
然后需要在 location / {…}中進行配置
location / {
#root /usr/share/nginx/html;
#index index.html index.htm;
proxy_pass http://servercluster;
}
2.多集群策略
輪詢 | 默認方式 |
---|---|
weight | 權(quán)重方式 |
ip_hash | 依據(jù)ip分配方式 |
least_conn | 最少連接方式 |
fair(第三方) | 響應(yīng)時間方式 |
url_hash(第三方) | 依據(jù)url分配方式 |
注意:在沒有配置情況下默認輪詢策略
2.1 權(quán)重配置
例如:
#權(quán)重越大,命中概率更高 weight,可按照服務(wù)器資源來分配
upstream servercluster
{
server 127.0.0.1:8001 weight=5;
server 127.0.0.1:8002 weight=3;
server 127.0.0.1:8003 weight=2;
}
2.2 ip_hash
指定負載均衡按照基于客戶端IP的分配方式,這個方法確保了相同的客戶端的請求一直發(fā)送到對應(yīng)的服務(wù)器,以保證session會話。這樣每個方可都固定訪問一個后端服務(wù)器,可以解決session不能跨服務(wù)器的問題。
例如:
#權(quán)重越大,命中概率更高 weight,可按照服務(wù)器資源來分配
upstream servercluster
{
ip_hash; #
server 127.0.0.1:8001 weight=5;
server 127.0.0.1:8002 weight=3;
server 127.0.0.1:8003 weight=2;
}
2.3 least_conn
把請求轉(zhuǎn)發(fā)給鏈接數(shù)較少的后端服務(wù)器。輪詢算法是把請求平均的轉(zhuǎn)發(fā)給各個后端,使它們的負載大致相同;但是有些請求占用的時間很長會導(dǎo)致其所在的后端負載較高。這種情況下,least_conn這種方式就可以達到更好的負載均衡效果
upstream servercluster
{
least_conn; #把請求轉(zhuǎn)發(fā)給鏈接數(shù)量較少的后端服務(wù)器
server 127.0.0.1:8001 weight=5;
server 127.0.0.1:8002 weight=3;
server 127.0.0.1:8003 weight=2;
}
2.4 fair
按照服務(wù)端的響應(yīng)時間來分配請求,響應(yīng)時間短的有限分配
upstream servercluster
{
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
fair; #實現(xiàn)響應(yīng)時間短的優(yōu)先分配
}
2.5 url_hash
按照訪問url的hash結(jié)果來分配請求,使用每個url定向到同一個后端服務(wù)器,要配合緩存命中來使用。同一個資源多次請求,可能會達到不同的服務(wù)器上,導(dǎo)致不必要的多次下載,緩存命中率不高,以及一些資源時間的浪費。而使用url_hash可以使用同一個url(也就是同一個資源請求)會到達同一臺服務(wù)器,一旦緩存了資源,再次收到請求,就可以從緩存中獲取
upstream servercluster
{
hash $request_url
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
3.nginx緩存配置
通過命令進入到nginx容器中,docker exec -it mynginx bash。
在 /etc/nginx文件夾下建立一個data文件夾用于做nginx緩存。
然后再本地關(guān)在文件的主配置文件配置緩存目錄經(jīng)
proxy_cache_path /etc/nginx/data levels=1:2
keys_zone=web_cache:50m inactive=1m max_size=1g
levels:表示有兩層文件夾
keys_zone:之情緩存key和緩存50m
max_size:緩存最大1g
然后還需要配置default.conf 開啟反向代理數(shù)據(jù)
proxy_store off; #反向代理數(shù)據(jù)
proxy_redirect off;
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://servercluster;
proxy_cache web_cache;
proxy_cache_valid 200 304 2m; #響應(yīng)200 304 進行緩存
proxy_cache_key
s
c
h
e
m
e
scheme
schemeproxy_host$request_uri; #使用當(dāng)前url地址作為當(dāng)前緩存key
注意:修改任何配置文件后都需要重啟nginx容器 docker restart mynginx
最終呈現(xiàn)文件
四 nginx路由規(guī)則
1.匹配格式
這個"/" 表示的是匹配路由規(guī)則進行路由轉(zhuǎn)發(fā)的。
我們可以在里面寫過個location進行路由匹配:
符號 | 規(guī)則 |
---|---|
= | 開頭表示精準匹配 |
~ | 大小寫敏感 |
~* | 忽略大小寫 |
^~ | 只需匹配url開頭 |
@ | 定義一個命名的location,在內(nèi)部定向時使用 |
location [ = | ~* | ^~ ] /url/ {…}
location @name {…}
規(guī)則使用匹配方式如下:
deny,設(shè)置禁止訪問的IP
#禁止IP:192.168.1.1訪問
location / {
deny 192.168.1.1;
}
#禁止所有IP訪問
location / {
deny all;
}
allow,設(shè)置允許訪問的IP
#只允許IP:192.168.1.1訪問
location / {
allow 192.168.1.1;
}
#允許所有IP訪問
location / {
allow all;
}
deny和allow的優(yōu)先級
nginx的權(quán)限指令是從上往下執(zhí)行的,在同一個塊下deny和allow指令同時存在時,誰先匹配誰就會起作用,后面的權(quán)限指令就不會執(zhí)行了。如下圖,如果 “deny 111.111.111.111” 觸發(fā)了,那它后面的兩條都不會觸發(fā)。
location / {
deny 192.168.1.1;
allow 192.168.1.2;
deny 192.168.1.3;
}
其實他們的關(guān)系就像 “if…else if…else if”,誰先觸發(fā),誰起作用。
if (deny 192.168.1.1) {...}
else if (allow 192.168.1.2) {...}
else if (deny 192.168.1.3) {...}
2.location匹配優(yōu)先級
在配置中需要注意的一點就是location的匹配規(guī)則和優(yōu)先級
- = 開頭表示精確匹配
- ^~ 開頭表示url以某個常規(guī)字符串開頭,不是正則匹配;
- ~ 開頭表示區(qū)分大小寫的正則匹配
- ~* 開頭表示不區(qū)分大小的正則匹配
- / 通用匹配,如果沒有其他匹配,任何請求都會匹配到;
3.location的匹配流程
1.、判斷是否精準匹配,如果匹配,直接返回結(jié)果并結(jié)束搜索匹配過程
2.、判斷是否普通匹配,如果匹配,看是否包含^~前綴,包含則返回,否則記錄匹配結(jié)果location時返回或記錄最長匹配的那個
3.、判斷是否正則匹配,按配置文件里的正則表達式的順序,由上到下開始匹配,一旦匹配結(jié)果成功,并結(jié)束搜索匹配過程.
4.、如果正則匹配沒有匹配到結(jié)果,則返回步驟2記錄的匹配結(jié)果
五、 nginx頁面攔截
在請求通過nginx的時候,在針對某些場景的使用做特殊處理,比如錯誤頁面,返回指定錯誤頁,例如:
當(dāng)前默認是在無法響應(yīng)對應(yīng)請求的情況下,默認在/usr/share/nginx/html文件下找到50x.html文件,返回頁面50x.html
既然是可以配置,我們也可以將自定義的文件復(fù)制到對應(yīng)的目錄下面在進行配置。
使用docker cp /url/xxx.html 容器名:ngnix docker中的目標文件下,在修改配置成對應(yīng)的文件名稱
六、 nginx動靜分離
對于前端的項目:可以是一個靜態(tài)服務(wù)器或資源池; --可以吧各種靜態(tài)文件都匹配到nginx中,可以直接請求nginx可以響應(yīng)不同頁面
對于后端項目:做反向代理;
動靜分離:需要動態(tài)的時候,就做轉(zhuǎn)發(fā)請求,需要靜態(tài)的時候,就直接返回靜態(tài)頁面(直接響應(yīng)我們的結(jié)果)
需求場景:在客戶端發(fā)起請求時,nginx會轉(zhuǎn)發(fā)到服務(wù)器服務(wù)器然后返回一個靜態(tài)文件,如果反復(fù)請求相同靜態(tài)文件都需要去轉(zhuǎn)發(fā)到服務(wù)器,就會增加開銷,性能降低,我們就可以將靜態(tài)文件報錯到nginx中,下次請求就直接返回。
基于.net6解決方式:
1.需要寫一個生成靜態(tài)文件的中間件,保存到指定目錄,在項目通過docker啟動時掛載到宿主機文件夾下
app.UseStaticPage("/app/data/staticfile", true, true);
/// <summary>
/// Middleware
/// </summary>
public class StaticPageMiddleware
{
private readonly RequestDelegate _next;
private string _directoryPath = null;
private bool _supportDelete = false;
private bool _supportWarmup = false;
public StaticPageMiddleware(RequestDelegate next, string directoryPath, bool supportDelete, bool supportWarmup)
{
this._next = next;
this._directoryPath = directoryPath;
this._supportDelete = supportDelete;
this._supportWarmup = supportWarmup;
}
/// <summary>
/// 任意HTTP請求,都要經(jīng)過這個方法
///
/// 如何抓到響應(yīng),并保存成HTML靜態(tài)頁
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path.Value!.StartsWith("/item/"))//規(guī)則支持自定義
{
Console.WriteLine($"This is StaticPageMiddleware InvokeAsync {context.Request.Path.Value}");
#region context.Response.Body
var originalStream = context.Response.Body;
using (var copyStream = new MemoryStream())
{
context.Response.Body = copyStream;
await _next(context);//后續(xù)的常規(guī)流程,正常請求響應(yīng)
copyStream.Position = 0;
var reader = new StreamReader(copyStream);
var content = await reader.ReadToEndAsync();
string url = context.Request.Path.Value;
this.SaveHtml(url, content);
copyStream.Position = 0;
await copyStream.CopyToAsync(originalStream);
context.Response.Body = originalStream;
}
#endregion
}
else
{
await _next(context);
}
}
private void SaveHtml(string url, string html)
{
try
{
if (string.IsNullOrWhiteSpace(html))
return;
if (!url.EndsWith(".html"))
return;
if (Directory.Exists(_directoryPath) == false)
Directory.CreateDirectory(_directoryPath);
var totalPath = Path.Combine(_directoryPath, url.Split("/").Last());
File.WriteAllText(totalPath, html);//直接覆蓋
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
/// <summary>
/// 刪除某個頁面
/// </summary>
/// <param name="url"></param>
/// <param name="index"></param>
private void DeleteHmtl(string url)
{
try
{
if (!url.EndsWith(".html"))
return;
var totalPath = Path.Combine(_directoryPath, url.Split("/").Last());
File.Delete(totalPath);//直接刪除
}
catch (Exception ex)
{
Console.WriteLine($"Delete {url} 異常,{ex.Message}");
}
}
/// <summary>
/// 清理文件,支持重試
/// </summary>
/// <param name="index">最多重試次數(shù)</param>
private void ClearDirectory(int index)
{
if (index > 0)
{
try
{
var files = Directory.GetFiles(_directoryPath);
foreach (var file in files)
{
File.Delete(file);
}
}
catch (Exception ex)
{
Console.WriteLine($"ClearDirectory failed {ex.Message}");
ClearDirectory(index--);
}
}
}
}
/// <summary>
/// 擴展中間件
/// </summary>
public static class StaticPageMiddlewareExtensions
{
/// <summary>
///
/// </summary>
/// <param name="app"></param>
/// <param name="directoryPath">文件寫入地址,文件夾目錄</param>
/// <param name="supportDelete">是否支持刪除</param>
/// <param name="supportClear">是否支持全量刪除</param>
/// <returns></returns>
public static IApplicationBuilder UseStaticPage(this IApplicationBuilder app, string directoryPath, bool supportDelete, bool supportClear)
{
return app.UseMiddleware<StaticPageMiddleware>(directoryPath, supportDelete, supportClear);
}
}
2.nginx也需要通過掛載將項目掛載在宿主機的靜態(tài)文件也掛載到nginx的docker容器中,然后通過修改配置來指定對應(yīng)的靜態(tài)文件
OK?。。。。。。。。。。。?!文章來源:http://www.zghlxwxcb.cn/news/detail-821939.html
總結(jié)
nginx主要的就是一個配置,如有補充或者有差異的地方,麻煩再評論下面指出,共勉?。。。?!文章來源地址http://www.zghlxwxcb.cn/news/detail-821939.html
到了這里,關(guān)于Docker 安裝Nginx與配置Nginx的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!