Nginx 产生背景

1. 日常生活中所见

  • 大学选课时学校官网会因为访问量较大经常崩溃。
  • 淘宝、京东等大型网站做营销活动时也会出现服务器异常。
  • 每年十一节假日或者春运抢票时,12306网站会发生瘫痪。

2. 上述场景产生的主要2大原因:

  • 巨大流量—海量的并发访问
  • 单台服务器资源和能力有限

那么如何解决这些问题呢,这就要先来了解一下负载均衡。

负载均衡

先来了解一下高并发的概念。

1. 高并发

见名知意,高(大量的),并发就是可以使用多个线程或者多个进程,同时处理(就是并发)不同的操作。简而言之就是每秒内有多少个请求同时访问。

2. 负载均衡

负载均衡:将请求/数据【均匀】分摊到多个操作单元上执行,负载均衡的关键在于【均匀】,也是分布式系统架构设计中必须考虑的因素之一。

3. tomcat并发图

可以发现,当每秒300个请求同时访问tomcat时,tomcat已经开始承受不住,出现波动。那么大型网站是如何处理高并发的呢?以下是高并发场景下,实现负载均衡的一个分布式架构图。

常见互联网分布式架构,分为客户端层、反向代理nginx层、站点层、服务层、数据层。只需要实现“将请求/数据 均匀分摊到多个操作单元上执行”,就能实现负载均衡。

什么是 Nginx

1. Nginx 的特点

Nginx是一款轻量级的Web 服务器/反向代理服务器【后面有介绍】及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发。

其特点是占有内存少,并发能力强,nginx的并发能力确实在同类型的网页服务器中表现非常好。

官方测试nginx能够支撑5万并发链接,并且CPU、内存等资源消耗却非常低,运行非常稳定。

2. 使用的地方

目前世界各地使用Nginx服务器的大型公司有很多,包括国内的阿里巴巴、腾讯、京东、网易、优酷等等。并且有些大型公司进行了二次开发,做出了自己的框架,如阿里巴巴的 tengine

3. Nginx纵深对比其优缺点(相比Apache)

  • nginx相对于apache的优点:

    轻量级,同样起web 服务,比apache 占用更少的内存及资源高并发,nginx 处理请求是异步非阻塞(如前端ajax)的,而apache 则是阻塞型的,在高并发下nginx能保持低资源低消耗高性能高度模块化的设计,编写模块相对简单还有,它社区活跃,各种高性能模块出品迅速(十几年时间发展)

  • apache 相对于nginx 的优点:

    Rewrite重写 ,比nginx 的rewrite 强大模块超多,基本想到的都可以找到少bug ,nginx 的bug 相对较多。(出身好起步高)

  • Nginx 配置简洁, Apache 复杂。

安装 Nginx(这里以tengine为例)

1. 安装依赖

依赖 gcc openssl-devel pcre-devel zlib-devel

yum -y install gcc openssl-devel pcre-devel zlib-devel

2. 解压文件

tar -zxvf tengine-2.1.0.tar.gz -C ../	#这里我把它解压到上级目录,-C后接要压缩到的路径,如不写默认当前路径

3. configure 配置

进入解压后的源码目录,然后执行configure命令进行配置

./configure --prefix=/usr/soft/nginx	#其中--prefix= 后接安装的路径,可以不写,默认安装在/usr/local/

此时发现 /usr/local/ 并没有,是因为还没有进行编译安装。

4. 编译并安装

make && make install

编译安装好后,就会默认在 /usr/local/ 下生成 nginx 文件夹。

nginx 命令

1. nginx 的启动

  • 我们可以直接执行 /usr/local/nginx/sbin/ 下的 nginx 脚本启动。

  • 还有一种方式就是将 nginx 添加至服务

    1、在/etc/rc.d/init.d/目录中建立文本文件nginx

    2、在文件中粘贴下面的内容:

#!/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/nginx/sbin/nginx"
prog=$(basename $nginx)

NGINX_CONF_FILE="/usr/local/nginx/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
  1. 修改nginx文件的执行权限
chmod +x nginx
  1. 添加该文件到系统服务中去
chkconfig --add nginx
  1. 查看是否添加成功
chkconfig --list nginx
  1. 启动,停止,重新装载
service nginx start|stop

启动后,访问虚拟机的80端口,可查看到以下界面。

当出现以上信息,说明安装启动成功。

Nginx 配置

nginx默认配置详解

#进程数,建议设置和CPU个数一样或2倍
worker_processes 2;

#日志级别
error_log logs/error.log warning;(默认error级别)

# nginx 启动后的pid 存放位置
#pid logs/nginx.pid;

events {
#配置每个进程的连接数,总的连接数= worker_processes * worker_connections
#默认1024
worker_connections 10240;
}

http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#连接超时时间,单位秒
keepalive_timeout 65;
server {
listen 80;
server_name localhost
#默认请求
   location / {
      root  html;   #定义服务器的默认网站根目录位置
      index index.php index.html index.htm;  #定义首页索引文件的名称
}
#定义错误提示页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

负载均衡配置

nginx支持以下负载均衡机制(或方法):

1. 轮询负载均衡 - 对应用程序服务器的请求以循环方式分发(默认此方式)

如果没有专门配置负载均衡方法,则默认为循环法。所有请求都被 代理到服务器组shsxt,并且nginx应用HTTP负载平衡来分发请求。

http { 
upstream shsxt{
server node01;
server node02;
server node03;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://shsxt;
}
}
}

2. 加权负载均衡

通过使用服务器权重,还可以进一步影响nginx负载均衡算法,谁的权重越大,分发到的请求就越多。

upstream shsxt {
server srv1.example.com weight=3;
server srv2.example.com;
server srv3.example.com;
}

3. 最少连接数 - 将下一个请求分配给活动连接数最少的服务器

在连接负载最少的情况下,nginx会尽量避免将过多的请求分发给繁忙的应用程序服务器,而是将新请求分发给不太繁忙的服务器,避免服务器过载。

upstream shsxt {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}

4. 会话持久性(ip-hash负载平衡机制)

如果需要将客户端绑定到特定的应用程序服务器 - 换句话说,就是始终选择相同的服务器而言,就要使客户端的会话“粘滞”或“持久” 。

ip-hash负载平衡机制就是有这种特性。使用ip-hash,客户端的IP地址将用作散列键,以确定应该为客户端的请求选择服务器组中的哪台服务器。此方法可确保来自同一客户端的请求将始终定向到同一台服务器,除非此服务器不可用。

upstream shsxt{
ip_hash;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}

5. Nginx的访问控制

Nginx还可以对IP的访问进行控制,allow代表允许,deny代表禁止。

location / {
deny 192.168.2.180;
allow 192.168.78.0/24;
allow 10.1.1.0/16;
allow 192.168.1.0/32;
deny all;
proxy_pass http://shsxt;
}

从上到下的顺序,匹配到了便跳出。如上的例子先禁止了1个,接下来允许了3个网段,其中包含了一个ipv6,最后未匹配的IP全部禁止访问。

虚拟主机

1. 何为虚拟主机

虚拟主机就是把一台物理服务器划分成多个“虚拟”的服务器,各个虚拟主机之间完全独立,在外界看来,每一台虚拟主机和一台单独的主机的表现完全相同。所以这种被虚拟化的逻辑主机被形象地称为“虚拟主机”。

2. 虚拟主机的特点和优点

由于多台虚拟主机共享一台真实主机的资源,每个虚拟主机用户承受的硬件费用、网络维护费用、通信线路的费用均大幅度降低。许多企业建立网站都采用这种方法,这样不仅大大节省了购买机器和租用专线的费用,网站服务器服务器管理简单,诸如软件配置、防病毒、防攻击等安全措施都由专业服务商提供,大大简化了服务器管理的复杂性;同时也不必为使用和维护服务器的技术问题担心,更不必聘用专门的管理人员。

3. 类别

  • 基于域名的虚拟主机,通过域名来区分虚拟主机
http { 
upstream shsxt{
server node01;
server node02;
}
upstream bjsxt{
server node03;
}
server {
listen 80;
//访问sxt2.com的时候,会把请求导到bjsxt的服务器组里
server_name sxt2.com;
location / {
proxy_pass http://bjsxt;
}
}
server {
listen 80;
//访问sxt1.com的时候,会把请求导到shsxt的服务器组里
server_name sxt1.com;
location / {
proxy_pass http://shsxt;
}
}
}
  • 基于端口的虚拟主机,通过端口来区分虚拟主机
http { 
upstream shsxt{
server node01;
server node02;
}
upstream bjsxt{
server node03
}
server {
//当访问nginx的80端口时,将请求导给bjsxt组
listen 8080;
server_name localhost;
location / {
proxy_pass http://bjsxt;
}
}
server {
//当访问nginx的81端口时,将请求导给shsxt组
listen 81;
server_name localhost;
location / {
proxy_pass http://shsxt;
}
}
}

正向代理和反向代理

正向代理

举个例子:我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。像我们经常通过vpn访问国外的网站,此时就是正向代理。

客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。

反向代理

**反向代理(Reverse Proxy)**方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

反向代理隐藏了真实的服务端,当我们请求 www.baidu.com 的时候,就像拨打 10086 一样,背后可能有成千上万台服务器为我们服务,但具体是哪一台,你不知道,也不需要知道,你只需要知道反向代理服务器是谁就好了,www.baidu.com 就是我们的反向代理服务器,反向代理服务器会帮我们把请求转发到真实的服务器那里去。

Nginx 就是性能非常好的反向代理服务器,用来做负载均衡。

关于Nginx中的session共享

http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。

那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术。

session的常见实现形式是会话cookie(session cookie),即未设置过期时间的cookie,这个cookie的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。

Session 共享

先我们应该明白,为什么要实现共享?

如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。

Session 一致性解决方案

1. session复制

tomcat 本身带有复制session的功能。

2、共享session

需要专门管理session的软件。

memcached 缓存服务,可以和tomcat整合,帮助tomcat共享管理session。

安装使用 memcached

1. 安装 memcached 内存数据库

yum –y install memcached

2. 启动可以用 telnet localhost 11211

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

3. web 服务器连接 memcached 的 jar 包拷贝到 tomcat 的 lib

4. 1. 配置 tomcat 的 conf 目录下的 context.xml

<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.17.9:11211"
sticky="true"
lockingMode="auto"
sessionBackupAsync="false"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
sessionBackupTimeout="1000" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
配置memcachedNodes属性,配置memcached数据库的ip和端口,默认11211,多个的话用逗号隔开.
目的是为了让tomcat服务器从memcached缓存里面拿session或者是放session
4.修改index.jsp,取sessionid看一看
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html lang="en">
SessionID:<%=session.getId()%>
</br>
SessionIP:<%=request.getServerName()%>
</br>
<h1>tomcat1</h1>
</html>