目录
nginx代理多个服务器
多站点
多location
负载均衡配置
nginx代理socket.io服务
web前端
配置nginx.conf
socket.io服务器
主要有两种方式
常用于在一台机器上部署多个不同站点, 各自有不同的域名,配置如下:
// nginx.conf
# nginx 80端口配置 (二级域名)
server {
listen 80;
server_name abc.jd.com;
location / {
proxy_pass http://localhost:8080; # 转发
}
}
# nginx 80端口配置
server {
listen 80;
server_name xyz.jd.com;
location / {
proxy_pass http://localhost:8081;
}
}
abc.jd.com将被自动代理到http://localhost:8080服务器上, 而xyz.jd.com则被自动代理到http://localhost:8081服务器上。
而对于那些只有一个域名,又不想申请多个域名的情况,可以选择下面的多location方式
location是nginx配置文件中的一个配置项, 当需要在一个域名下面部署多个不同服务器,可使用该方案,配置如下:
location / {
root /html/;
index index.html index.html;
}
location /sig {
root /sig/;
index index.html index.html;
}
www.xxx.com 将会被导流到/html目录下
www.xxx.com/sig/ 将被导流到/sig目录下
在nginx中配置proxy_pass代理转发时,如果在proxy_pass后面的url加/,表示绝对根路径;如果没有/,表示相对路径,把匹配的
路径部分也给代理走。
下面列举四种情况分别用 http://192.168.2.1/proxy/b.html 进行访问。
location /proxy/ {
proxy_pass http://127.0.0.1/;
}
代理到:http://127.0.0.1/b.html
location /proxy/ {
proxy_pass http://127.0.0.1;
}
代理到:http://127.0.0.1/proxy/b.html
location /proxy/ {
proxy_pass http://127.0.0.1/aaa/;
}
代理到:http://127.0.0.1/aaa/b.html
location /proxy/ {
proxy_pass http://127.0.0.1/aaa;
}
代理到:http://127.0.0.1/aaab.html
nginx的负载均衡配置包含多个配置项,主要有backup,weight,down,max_fails,fail_timeout.. proxy_next_upstream,结合一个案例进行说明:
upstream S1{
ip_hash;
server 127.0.0.1:8501;
server 127.0.0.1:8502;
}
upstream S2{
server 127.0.0.1:8503;
server 127.0.0.1:8504;
fair;
}
upstream S3{
server 127.0.0.1:8505;
server 127.0.0.1:8506;
hash $request_uri;
hash_method crc32;
}
upstream server_A {
server 127.0.0.1:9000 weight=2 max_fails=3 fail_timeout=30s;
server 127.0.0.1:9001 weight=1 max_fails=3 fail_timeout=30s;
server 127.0.0.1:9002 weight=1 max_fails=3 fail_timeout=30s backup;
}
server {
listen 443 ssl;
include /etc/nginx/ssl_certificate/ssl.conf;
server_name test.xx.cn ;
location / {
# root /html;
proxy_next_upstream error | timeout | http_502 | http_503 | http_504 ;
proxy_pass http://server_A/;
proxy_buffer_size 64k;
proxy_buffers 32 32k;
proxy_busy_buffers_size 128k;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 120;
}
location ~ ^/favicon\.ico$ {
access_log off;
deny all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
upstream: server_A{}指定了三个服务器,其中9002端口服务器因为带有backup标识,作为备用服务器存在,也就是说当9001服务器正常时,9002服务器是不参与工作的,仅当9001服务器遇到了proxy_next_upstream指定的错误类型( error | timeout | http_502 | http_503 | http_504),nginx才会切换到备用服务器。
weight: 指定了服务器的权重, 其中9000服务器的流量将会是9001服务器的2倍。
max_fails:允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误
fail_timeout: 默认值10s,代表超时时间。
down: 表示当前的server暂时不参与负载
ip_hash:每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session不能跨服务器的问题,如果后端服务器down掉,要手工down掉。
fair:(第三方插件)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
url_hash:(第三方插件)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存服务器时比较有效。
在upstream中加入hash语句,hash_method是使用的hash算法。
proxy_pass: 指定要代理的服务器,当收到相应的location时,会导流到对应的服务器上。
proxy_next_upstream:
语法格式:
proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ...;
含义:
error:和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现错误
timeout:和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现超时
invalid_header:后端服务器返回空响应或者非法响应头
http_500:后端服务器返回的响应状态码为500
http_502:后端服务器返回的响应状态码为502
http_503:后端服务器返回的响应状态码为503
http_504:后端服务器返回的响应状态码为504
http_404:后端服务器返回的响应状态码为404
off:停止将请求发送给下一台后端服务器
默认值:
proxy_next_upstream error timeout;
默认情况下, nginx只会捕获error,timeout这两种错误, nginx默认判断失败节点状态是并不以http错误状态来进行判断失败。
proxy_next_upstream使用场景: 当业务服务器返回500,502...错误时,将流量切换到备用服务器, 则可做如下配置:
proxy_next_upstream http_500 | http_502 | http_503 | http_504 |http_404;
proxy_next_upstream作用相当于是告知nginx来捕获相应的错误类型
proxy_next_upstream off
关闭proxy_next_upstream.
因为proxy_next_upstream 默认值: proxy_next_upstream error timeout;
场景:当访问server-A时,server-A返回error timeout时,访问会继续分配到下一台服务器处理,就等于一个请求分发到多台服务器,就可能出现多次处理的情况,如果涉及到充值,就有可能充值多次的情况,这种情况下就要把proxy_next_upstream关掉
我需要在一台服务器中部署多个服务, 包括网站,信令服务器等,且只有一个域名, 自然而然需要使用'多location'方式。在使用nginx代理socket.io信令服务器的时候,走了不少弯路,总结如下三个方面:
socket = io.connect('http://192.168.12.22');
socket.on(ping, function (data) {
console.log(data);
socket.emit('p','test');
弯路{
一开始我是希望在nginx配置文件中增加一个location:
location /proxy_sig/ {
...
}
我设想的是在web端通过 io.connect('http://192.168.12.22/proxy_sig/')来导流至该location,结果失败了。 查明原因,原来是io.connect()导致的, 无论我们使用何种域名, 经过socket.io转换后,到达nginx的请求url都变为:
http://192.168.12.22/socket.io/?EIO=3&transport=polling&t=Mwt30Fu
所以, 我们设想location proxy_sig是永远无法到达的, 于是,在nginx配置文件中增加location socket.io
location ~* \.io {
...
}
成功了.
}
location ~* \.io {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
'use strict'
var log4js = require('log4js');
var http = require('http');
var https = require('https');
var fs = require('fs');
var socketIo = require('socket.io');
var express = require('express');
var serveIndex = require('serve-index');
log4js.configure({
appenders: {
file: {
type: 'file',
filename: 'app.log',
layout: {
type: 'pattern',
pattern: '%r %p - %m',
}
}
},
categories: {
default: {
appenders: ['file'],
level: 'debug'
}
}
});
var logger = log4js.getLogger();
var serverApp = express();
serverApp.use(serveIndex('./public'));
serverApp.use(express.static('./public'));
//var http_server = http.createServer(serverApp);
var http_server = http.createServer();
console.log(http_server);
var options = {
key: fs.readFileSync('/luckzone_cert/key'),
cert: fs.readFileSync('/luckzone_cert/pem')
};
var pepople_num = 0;
var https_server = https.createServer(options, serverApp);
var io = socketIo.listen(http_server);
http_server.listen(9001, '0.0.0.0');
function ioConnection(socket) {
console.log('enter ioConnection');
socket.on('message', (room, socketid, data) => {
console.log('socket: recv message:', socket.id, socketid);
// send message to the room , excpet myself.
socket.to(room).emit('message', room, socketid, data);
});
socket.on('join', (room) => {
socket.join(room);
pepople_num = pepople_num + 1;
console.log('socket: join', room);
socket.emit('joined', room, socket.id);
if (pepople_num > 1) {
// there have other people in the room
socket.to(room).emit('otherjoin', room, socket.id);
}
});
socket.on('leave', (room) => {
socket.to(room).emit('bye', room, socket.id);
//send message to myself
socket.emit('leaved', room, socket.id);
});
}
function ioDisconnection(socket) {
}
io.sockets.on('connection', ioConnection);
https_server.listen(9002, '0.0.0.0');
需要注意的是, 我们是通过http服务,所以,一定要将socket.io和http服务绑定一起,从9001端口启动, nginx配置文件来处理前端请求和socket.io服务器之间的映射.