LVS+Keepalived+Nginx实战

LVS+Keepalived+Nginx实战,从背景介绍到搭建测试。

大型网站架构演进历程

初始阶段

应用程序、数据库、文件等所有资源在一台服务器上。典型架构Linux+Apache+Mysql+PHP,简称LAMP。

应用服务和数据服务分离

随着网站业务的发展,一台服务器逐渐不能满足需求:越来越多的用户访问导致性能越来越差,越来越多的数据导致存储空间不足。这时就需要将应用和数据分离。这三台服务器对硬件资源的要求各不相同,应用服务器要处理大量业务逻辑,因此需要更快更强大的CPU;数据库服务器需要磁盘检索和数据缓存,因此需要更大的硬盘和内存,文件服务器需要存储大量用户上传的文件,因此需要更大的硬盘。

使用缓存改善网站性能

网站访问特点和现实世界的财富分配一样遵循二八定律:80%的业务访问集中在20%的数据上。例如淘宝买家浏览的商品集中在少部分成交数多、评价良好的商品上;百度搜索关键词集中在少部分热门词汇上。网站使用的缓存分为两种:缓存在应用服务器上的本地缓存和缓存在专门的分布式缓存服务器的远程缓存。本地缓存的速度更快一些,但是受应用服务器内存限制,其缓存数量有限,而且会出现与应用程序争用内存的情况。远程分布式缓存可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可以在理论上做到不受内存容器限制的缓存服务。

使用应用服务器集群改善网站并发处理处理能力

使用集群是网站解决高并发、海量数据问题的常用手段。通过使用应用服务器集群,改善负载压力,实现系统的可伸缩性。通过负载均衡调度服务器,可将来自用户浏览器的访问请求分发到应用服务器集群中的任何一台服务器。当有更多的用户时,在集群中加入更多的应用服务器即可。当一台服务器的处理能力、存储空间不足时,不要企图去更换更强大的服务器,对答应网站而言,不管多么强大的服务器,都满足不了网站持续增长的业务需求,这种情况下,跟恰当的做法是增加一台服务器分担缘由服务器的访问及存储压力。

数据库读写分离

网站在使用缓存后,是绝大部分数据读操作访问都可以不通过数据库就能完成,但是仍有一部分读操作(缓存访问不命中、缓存过期)和全部的写操作需要访问数据库,在网站的规模达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈。目前大部分的主流数据库都提供主从热备的功能,通过配置两台数据库主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。网站利用数据库的这一功能,实现数据库读写分离,从而改善数据库负载压力。

使用反向代理和CDN加速网站响应

使用网站业务不断发展,用户规模越来越大,由于中国复杂的网络环境,不同地区的用户访问网站时,速度差别也极大。使用CDN和反向代理的目的都是早返回数据给用户。一方面加快用户访问速度,另一方面也减轻后端服务器的负载压力。CDN和反向代理的基本原理都是缓存,区别在于CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房提取数据;而反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器缓存着用户请求的资源,就将其直接返回给用户。

使用分布式文件系统和分布式数据库系统

分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大时才使用。网站最长使用的数据库拆分手段是业务分库,将不同业务的数据库部署在不同的物理服务器上。

业务拆分

大型网站为了应付日益复杂的业务场景,通过使用分而治之的手段将整个网站业务分为不同的产品线,如大型电商网站会将首页、商铺、订单、买家、卖家等拆分成不同的产品线,分归不同的业务团队负责。将一个网站拆分成不同的应用,每个应用独立部署维护。应用之间可以通过超链接建立联系,也可以通过消息队列进行数据转发,也可通过同一个数据库系统构建一个关联的完整系统。

使用NoSQL和搜索引擎

随着网站业务越来越复杂,对数据存储和检索的需求也越来越复杂,网站需要采用一些非数据库技术如NoSQL和非数据库查询技术如搜索引擎。源自互联网的技术手段,对可伸缩的分布式特性具有更好的支持。应用服务器则通过一个统一的数据模块访问各种数据,减轻应用程序管理诸多数据的麻烦。

分布式服务

随着业务拆分越来越小,存储系统越来越庞大,应用系统的整体复杂度呈指数级增加,部署维护越来越难。由于所有应用要和所有数据库系统连接,在数万台服务器规模的网站中,这些连接的数目是服务器规模的平方,导致数据库连接资源不足,拒绝服务。各个应用系统需要执行很多相同的业务操作,比如用户管理、商品管理等。可以将这些共用业务提取出来,独立部署。应用系统只需要通过调用共用业务服务完成具体业务操作。

大型网站架构核心技术

分布式缓存系统

分布式缓存概述

分布式缓存系统是进化的产物。
本地缓存 -> 集群缓存 -> 分布式缓存(数据网格)。

性能:
访问缓存中的一个对象比直接访问远端数据存储引擎(例如数据库)要快很多。
直接访问一个已经存在的对象比从数据创建一个对象要快。
数据网格支持一些性能调优特性可能不被集群缓存所支持,例如,应用程序可以根据数据之间关联关系的紧密程度来确保相互关联的对象被保存在相同的缓存节点。
一致性:
本地缓存只有在应用程序被部署到单一的应用服务器上的时候才有意义,如果它被部署到了多台应用服务器上的话, 那么本地缓存一点意义都没有,问题出在过期数据。集群缓存是通过复制和让缓存数据失效来解决这个问题的。
除了支持JTA事物之外,分布式缓存还支持XA(分布式)和两阶段提交事物。
可伸缩性:
集群缓存和数据网格的区别就在于可伸缩性。数据网格是可伸缩的。缓存数据是通过动态的分区被分发的。结果就是,增加一个缓存节点既提高了吞吐量也提高了容量。
独立性:
允许分布式缓存能够独立于应用服务器而被独立的扩展. 也让其服务器能够被指派与应用服务器不同的资源。
这样的架构也让数据网格的基础架构能够独立于应用服务器的惯例和调整。
能够独立于应用而被升级,应用的重新部署也不会对数据网格本身产生任何影响。

基础架构:
使用在基础架构中作为顶级系统的独立数据网格服务。

使用分布式缓存的好处是它的可扩展性和独立性,并且,作为顶级基础设施组件,它能够同时提供本地缓存和集群缓存所能够提供的性能和一致性。

典型应用场景

页面缓存:
用来缓存Web页面的内容片段,包括HTML、CSS和图片等,多应用于社交网站等。
应用对象缓存:
缓存系统作为ORM框架的二级缓存对外提供服务,目的是减轻数据库的负载压力,加速应用访问。
状态缓存:
缓存包括Session会话状态及应用横向扩展时的状态数据等,这类数据一般是难以恢复的,对可用性要求较高,多应用于高可用集群。
并行处理:
通常涉及大量中间计算结果需要共享。
事件处理:
分布式缓存提供了针对事件流的连续查询(continuous query)处理技术,满足实时性需求。

Memcached分布式缓存系统

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。
Memcached是基于一个存储键/值对的HashMap。其守护进程是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。

Memcached的存储方式:
为了提高性能,Memcached中保存的数据都存储在Memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启Memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于LRU(Least Recently Used,近期最少使用)算法自动删除不使用的缓存。Memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题。

Redis分布式缓存系统

Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。
与Memcached一样,为了保证效率,数据都是缓存在内存中。区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis支持语言:

Redis的存储方式:
Redis的存储分为:内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。
save seconds updates,save配置,指出在多长时间内,有多少次更新操作,就将数据同步到数据文件。这个可以多个条件配合,比如默认配置文件中的设置,就设置了三个条件。
appendonly yes/no ,appendonly配置,指出是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面的save条件来同步的,所以有的数据会在一段时间内只存在于内存中。
appendfsync no/always/everysec ,appendfsync配置,no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示每秒同步一次。

两种分布式缓存系统比较

存储数据位置:
Redis中,并不是所有的数据都一直存储在内存中的,这是和Memcached相比一个最大的区别。
数据类型支持:
Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
对数据备份的支持:
Redis支持数据的备份,即master-slave模式的数据备份。
数据持久化:
Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

负载均衡

负载均衡概述

负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
服务器负载均衡从字面意义来讲可以理解为,单台服务器不能称之为均衡,只有多个服务器才能称之为均衡,也就是说:多个服务器组成的这样一个系统,我们称之为服务器均衡系统。负载均衡组成的方式:
负载均衡的服务器(管理器)
被均衡的服务器集群(客户机)
负载均衡管理器,是整个负载均衡的控制服务器(DR),所有用户的请求都要先经过这台服务器,然后由此服务器根据各个实际处理服务器状态将请求具体分配到某个实际处理
服务器中,用户是感觉不到后端的服务器的,他们只看到当前这台DR服务器。DR服务器只负责转发和安装相应的管理软件,所以一般企业负载均衡服务器非常重要,但是资源使用非常少,所以不必用非常高的配置来担当负载均衡管理器。

负载均衡分类:软/硬件
软件负载均衡解决方案是指在一台或多台服务器相应的操作系统上安装一个或多个附加软件来实现负载均衡,它的优点是基于特定环境,配置简单,使用灵活,成本低廉,可以满足一般的负载均衡需求。软件解决方案缺点也较多,因为每台服务器上安装额外的软件运行会消耗系统不定量的资源,越是功能强大的模块,消耗得越多,所以当连接请求特别大的时候,软件本身会成为服务器工作成败的一个关键;软件可扩展性并不是很好,受到操作系统的限制;由于操作系统本身的Bug,往往会引起安全问题。

硬件负载均衡解决方案是直接在服务器和外部网络间安装负载均衡设备,这种设备通常称之为负载均衡器,由于专门的设备完成专门的任务,独立于操作系统,整体性能得到大量提高,加上多样化的负载均衡策略,智能化的流量管理,可达到最佳的负载均衡需求。负载均衡器有多种多样的形式,除了作为独立意义上的负载均衡器外,有些负载均衡器集成在交换设备中,置于服务器与Internet链接之间,有些则以两块网络适配器将这一功能集成到PC中,一块连接到Internet上,一块连接到后端服务器群的内部网络上。
一般而言,硬件负载均衡在功能、性能上优于软件方式,不过成本昂贵。

部署方式:路由模式
负载均衡有三种部署方式:路由模式、桥接模式、服务直接返回模式。
路由模式部署灵活,约60%的用户采用这种方式部署;桥接模式不改变现有的网络架构;服务直接返回(DSR)比较适合吞吐量大特别是内容分发的网络应用。约30%的用户采用这种模式。
服务器的网关必须设置成负载均衡机的LAN口地址,且与WAN口分属不同的逻辑网络。因此所有返回的流量也都经过负载均衡。这种方式对网络的改动小,能均衡任何下行流量。

应用场景

在当业务系统服务器无法支撑当前的业务量时,用户可以选择更高性能的服务器。但更为合理的做法是通过在既有业务服务器基础上,增量的方式增加相同功能的服务器,将计算任务分摊到后台多台较低配置的服务器处理,每台服务器都可以响应服务请求。实现合理安排客户请求并加快了请求相应速度,来提高用户体验。而用户仅感受到是一台高性能服务器在提供服务。

负载均衡硬件

负载均衡软件

消息队列

消息队列概述

介绍:消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。
常用消息队列系统:目前在生产环境,使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等。

应用场景

异步处理:

流量削峰:

应用解耦:

日志处理:

消息通讯—点到点方式:

消息通讯—发布订阅方式:

开源消息队列软件RabbitMQ

RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。

AMQP当中有四个概念非常重要: 虚拟主机(virtual host),交换机(exchange),队列(queue)和绑定(binding)。一个虚拟主机持有一组交换机、队列和绑定。

页面静态化技术

页面静态化概述
静态页面:

最早的时候,网站内容是通过在主机空间中放置大量的静态网页实现的。为了方便对这些分散在不同目录的静态网页的管理,(一般是通过FTP),象frontpage/dreamweaver这样软件甚至直接提供了向主页空间以FTP方式直接访问文件的功能。以静态网页为主的网站最大的困难在于对网页的管理,在这种框架里,网页框架和网页中的内容混杂在一起,很大程度地加大了内容管理的难度。为了减轻这种管理的成本,发展出了一系列的技术,甚至连css本身,原本也是针对这种乱七八糟的网页维护而设计的,目的就是把网页表达的框架和内容本身抽象分离出来。
A.静态网页的内容稳定,页面加载速度快。
B.静态网页的没有数据库支持,在网站制作和维护方面的工作量较大。
C.静态网页的交互性差,有很大的局限性。

动态页面:

通过执行asp、php、jsp和.net等程序生成客户端网页代码的网页。通常可以通过网站后台管理系统对网站的内容进行更新管理。发布新闻,发布公司产品,交流互动,博客,网上调查等,这都是动态网站的一些功能。也是我们常见的。 常见的扩展名有:.asp、php、jsp、cgi和aspx 等。 注意:动态页面的“动态”是网站与客户端用户互动的意思,而非网页上有动画的就是动态页面。
A.交互性好。
  B.动态网页的信息都需要从数据库中读取,每打开一个一面就需要去获取一次数据库,如果访问人数很多,也就会对服务器增加很大的荷载,从而影响这个网站的运行速度。
其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。
为什么需要动态页面静态化:
1) 搜索引擎的优化
尽管搜索机器人有点讨厌,各个网站不但不会再象从前一样把它封起来,反而热情无比地搞SEO,所谓的面向搜索引擎的优化,其中就包括访问地址的改写,令动态网页看上去是静态网页,以便更多更大量地被搜索引擎收录,从而最大限度地提高自已的内容被目标接收的机会。但是,在完全以动态技术开发的网站,转眼中要求变换成静态网页提供,同时,无论如何,动态网页的内容管理功能也是必须保留的;就如同一辆飞驶的奔驰忽然要求180度转弯,要付出的成本代价是非常大的,是否真的值得,也确实让人怀疑。
2) 提高程序性能
很多大型网站,进去的时候看它很复杂的页面,但是加载也没有耗费多长时间,除了其它必要原因以外,静态化也是其中必需考虑的技术之一。
先于用户获取资源或数据库数据进而通过静态化处理,生成静态页面,所有人都访问这一个静态页面,而静态化处理的页面本身的访问速度要较动态页面快很多倍,因此程序性能会有大大的提升。
静态化在页面上的体现为:访问速度加快,用户体验性明显提升;在后台体现为:访问脱离数据库,减轻了数据库访问压力。

FreeMarker实现页面静态化

FreeMarker是什么:
FreeMarker是一个基于Java的开发包和类库的一种将模板和数据进行整合并输出文本的通用工具,FreeMarker实现页面静态化的原理是:将页面中所需要的样式写入到FreeMarker模板文件中,然后将页面所需要的数据进行动态绑定并放入到Map中,然后通过FreeMarker的模板解析类process()方法完成静态页面的生成。
模板引擎:一种基于模板的、用来生成输出文本的通用工具;基于Java的开发包和类库。
FreeMarker能做什么:
MVC框架中的View层组件、html页面静态化、代码生成工具和CMS模板引擎。
为什么要用FreeMarker:
程序逻辑(Java 程序)和页面设计(FreeMarker模板)分离;
分层清晰,利于分工合作;
主流Web框架良好的集成(struts2,springmvc);
简单易学、功能强大;
免费开源。

Velocity实现页面静态化

Velocity是什么:
Velocity是一个基于Java的模板引擎(template engine)。它允许任何人仅仅使用简单的模板语言(template language)来引用由Java代码定义的对象。
Velocity的应用:
当Velocity应用于Web开发时,界面设计人员可以和Java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由Java程序开发人员关注业务逻辑编码。Velocity将Java代码从web页面中分离出来,这样为web站点的长期维护提供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。

分布式数据库中间件

分布式数据库中间件概述

虽然云计算时代,传统数据库存在着先天性的弊端,但是NoSQL数据库又无法将其替代。如果传统数据易于扩展,可切分,就可以避免单机(单库)的性能缺陷。传统数据库系统随着规模的增大,遇到了主要问题:
单个表数据量太大;
单个库数据量太大;
单台数据量服务器压力很大;
读写速度遇到瓶颈。
当面临以上问题时,我们会想到的第一种解决方式就是 向上扩展(scale up) 简单来说就是不断增加硬件性能。此时我们不得不依赖于第二种方式: 水平扩展 。 直接增加机器,把数据库放到不同服务器上,在应用到数据库之间加一个proxy进行路由,这样就可以解决上面的问题了。

分布式数据库中间件比较

分布式数据库中间件MyCat

MyCat是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信。其核心功能是分表分库,即将一个大表水平切分为N个小表,存储在后端MySQL服务器里或者其他数据库里。
MyCat使用手册:http://mycat.org.cn/document/Mycat_V1.6.0.pdf

MyCat的技术原理:
MyCat技术原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。

MyCat的核心功能:
1. 支持水平切分

2. 支持垂直切分

3. 支持读写分离
4. 支持全局表

5. 支持独创的ER关系分片,解决E-R分片难处理问题
存在关联关系的父子表在数据插入的过程中,子表会被MyCat路由到其相关父表记录的节点上,从而父子表的Join查询可以下推到各个数据库节点上完成,这是最高效的跨节点Join处理技术

LVS

LVS使用的三种模式:NAT、TUN、DR

NAT模式-网络地址转换

Virtual Server via Network Address Translation(VS/NAT)
通过网路地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器,真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。
图1  VS/NAT的体系结构
图2 NAT模式工作流程图
NAT模式特点:
1. NAT技术请求和响应的报文都必须经过调度器地址重写然后再转发,返回时再改写
2. 只需要在LB(调度器)上配置WAN IP即可,也要有LAN IP和内部通信,内部RS只需要配置LAN IP
3. 每台内部节点RS的网关要配成LB的LAN物理网卡地址,这样才能确保数据返回时仍能经过LB
4. 由于请求与回传数据都必须经过负载均衡器,因此访问量大时LB有瓶颈
5. 支持对IP及端口进行转换

TUN模式-隧道模式

Virtual Server via IP Tunneling(VS/TUN)
为了解决NAT模式的瓶颈问题,调度器把请求报文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,这样调度器只处理请求报文,由于一般网络服务应答数据比请求数据大很多,采用TUN模式后,集群系统的吞吐量可以提高10倍。
TUN的连接调度和管理与NAT一样,只是转发报文的方法不同,调度器根据各个服务器的负载情况,动态地选择一台服务器,将请求报文封装在另一个IP报文中,再将封装后的报文转发给选出的服务器,服务器收到报文后,先将报文解封获得来自目标地址为VIP的报文,服务器发现VIP地址被配置在本地的IP隧道设备上,所以就处理这个请求,然后根据路由表将响应报文直接返回给客户。
图3  VS/TUN的体系结构
图4  VS/TUN的工作流程图
TUN模式的特点:
1. 负载均衡器把请求的报文通过IP隧道的方式(不改写请求报文的地址,而是直接封装成另外的IP报文)转发给真实服务器,真实服务器处理请求后把响应直接返回给客户端。
2. 由于真实服务器把响应后的报文直接返回给客户端,因此虽然理论上只要能出网,无需外网IP地址,但RS最好有一个外网IP地址,这样效率高。
3. 由于调度器只处理入站报文,因此集群系统的效率会提高10倍以上,但是隧道模式会带来一定的开销,它适合LAN/WAN。
4. LAN环境下不如DR模式效率高,有的系统还需要考虑IP隧道的支持问题,还需要绑定VIP,配置复杂。
5. LAN下多采用DR,WAN环境下可以用TUN模式,但是在WAN下更多的被DNS+haproxy/nginx等代理取代,因此TUN模式在国内公司已经使用的很少。

DR模式-直接路由

Virtual Server via Direct Routing(VS/DR)
VS/DR模式是通过改写请求报文的目标MAC地址,将请求发给真实服务器的,而真实服务器将响应后的处理结果直接返回给客户端用户。同VS/TUN技术一样,VS/DR技术可极大地提高集群系统的伸缩性。而且,这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,但是要求调度器与真实服务器都有一块网卡连在同一物理网段上。
图5 VS/DR的体系结构
在LVS-DR配置中,Dierctor将所有入站请求转发给集群内部节点,但集群内部节点直接将它们的回复发送给客户端计算机(没有通过Director回来)。如图所示:
图6 DR直接路由工作模式逻辑图
VS/DR模式是互联网使用的最多的一种模式。VS/DR模式的工作流程如下图7所示。它的连接调度和管理与VS/NAT和VS/TUN中的一样,它的报文转发方法和前两种又有不同,将报文直接路由给目标服务器。在VS/DR中,调度器根据各个服务器的负载情况、连接数等因素,动态的选择一台服务器,不修改目的IP地址和目的端口,也不封装IP报文,而是将请求的数据帧的MAC地址改为选出服务器的MAC地址,再将修改后的数据帧在服务器组的局域网上发送。因为请求数据帧的MAC地址是选出的真实服务器,所以服务器肯定可以收到这个数据帧,从中可以获得该IP报文。当真实服务器发现报文的目标地址VIP是在本地的网络设备上,服务器就会处理这个报文,然后根据路由表将响应报文直接返回给用户。
图7 VS/DR工作流程图
DR模式的特点:
1. 通过在调度器LB上修改数据包的目标MAC地址实现转发。注意,源地址仍然是CIP地址,目标地址仍然是VIP。
2. 由于只有请求的报文经过负载均衡器,而回传的报文无需经过负载均衡器,因此,访问量大的时候效率很高(和NAT相比)。
3. 因DR模式是通过MAC地址改写机制实现的转发,因此,所有RS节点和调度器LB只能在一个LAN中。(小缺点)
4. 需要注意RS节点的VIP的绑定(lo:VIP)和ARP抑制问题。强调,RS节点的默认网关不需要是LB的IP,而是出口路由器的IP。由于仅进行了MAC地址的改写,因此,LB无法改变请求的目标端口(和NAT主要区别)。LB几乎支持所有的UNIX,Linux系统,目前无Windows版,但是RS节点可以是windows。
5. 总体来说DR模式效率很高,但是配置也比较麻烦,访问量不是特别大的企业可以用haproxy/nginx取代它。直接对外的访问业务,例如:web服务做RS节点,最好用公网IP地址,不直接对外的业务,例如MySQL,存储系统RS节点,最好用内部IP地址。

3种模式的对比

在LINUX环境下搭建DR模式

原理图

一些概念

VIP: 虚拟服务器地址
DIP: 转发的网络地址,有两个作用:
和RIP通信:ARP协议,获取Real Server的RIP:MAC地址
转发Client的数据包到RIP上(隐藏的VIP)
RIP: 后端真实主机(后端服务器)
CIP: 客户端IP地址
VIP: 虚拟主机IP

步骤
1.准备3台Linux机器并配置它们的eth0网卡的IP(在一个网段)

node001:LVS,IP:192.168.9.101
node002:Real Server,IP:192.168.9.102
node003:Real Server,IP:192.168.9.103

2.在LVS的eth0:0接口上配置VIP
1
2
3
4
3. [root@node001 ~]# ifconfig eth0:0 192.168.9.100/24
[root@node001 ~]# ifconfig
eth0 inet addr:192.168.9.101 Bcast:192.168.9.255 Mask:255.255.255.0
eth0:0 inet addr:192.168.9.100 Bcast:192.168.9.255 Mask:255.255.255.0

24代表该IP的子网掩码为255.255.255.0
注意,要想让配置永久生效,应修改配置文件
vi /etc/sysconfig/network-scripts/ifcfg-eth0:0
DEVICE=eth0:0
IPADDR=192.168.9.100
NETMASK=255.255.255.0

3. 修改node002和node003的内核ARP通告和响应级别(隐藏VIP)

arp_ignore: 定义接收到ARP请求时的响应级别
0:只要本地配置的有相应地址,就给予响应
1:仅在请求的目标(MAC)地址配置请求到达的接口上的时候,才给予响应;
arp_announce:定义将自己地址向外通告时的通告级别
0:将本地任何接口上的任何地址向外通告
1:试图仅向目标网络通告与其网络匹配的地址
2:仅向与本地接口上地址匹配的网络进行通告

1
2
3
4
5
6
7
8
9
[root@node002 ~]# echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore
[root@node002 ~]# echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce
#后两步可选,为保险起见,防止再配置的网卡进行通告,可以这么设置
[root@node002 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@node002 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
[root@node003 ~]# echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore
[root@node003 ~]# echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce
[root@node003 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@node003 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
4. 在node002和node003上配置VIP
1
2
[root@node002 ~]# ifconfig lo:0 192.168.9.100 netmask 255.255.255.255
[root@node003 ~]# ifconfig lo:0 192.168.9.100 netmask 255.255.255.255

注意,要想让配置永久生效,应修改配置文件
vi /etc/sysconfig/network-scripts/ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.9.100
NETMASK=255.255.255.255

5. 在node002和node003上安装httpd

(apache静态web server,默认端口号80)服务并启动

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@node002 ~]# yum install httpd –y
[root@node002 ~]# cd /var/www/html
[root@node002 html]# vi index.html
<h1>From 192.168.9.102</h1>
[root@node002 html]# service httpd start
[root@node002 html]# chkconfig httpd on 设置httpd服务开机启动
[root@node003 ~]# yum install httpd –y
[root@node003 ~]# cd /var/www/html
[root@node003 html]# vi index.html
<h1>From 192.168.9.103</h1>
[root@node002 html]# service httpd start
[root@node002 html]# chkconfig httpd on

浏览器访问node002和node003,验证一下:


但此时还不能通过LVS访问RS

6. 在LVS上安装ipvsadm客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@node001 network-scripts]# yum install ipvsadm –y
添加监听的IP
[root@node001 network-scripts]# ipvsadm -A -t 192.168.9.100:80 -s rr
查看是否设置成功
[root@node001 network-scripts]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.9.100:80 rr
添加后台主机
[root@node001 network-scripts]# ipvsadm -a -t 192.168.9.100:80 -r 192.168.9.102 -g
[root@node001 network-scripts]# ipvsadm -a -t 192.168.9.100:80 -r 192.168.9.103 -g
验证
[root@node001 network-scripts]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.9.100:80 rr
-> 192.168.9.102:80 Route 1 0 0
-> 192.168.9.103:80 Route 1 0 0

去页面验证:
在浏览器输入192.168.9.100并反复刷新,页面交替显示node002和node003的主页,说明LVS集群配置成功。


也可以通过ipvsadm –lnc命令查看LVS调度状态。
说明
ipvsadm -A -t 192.168.9.100:80 -s rr命令中,rr指定了LVS调度RS的算法,rr代表轮询,即依次循环的调用所有的RS节点,其他算法还有wrr、dh、sh等。
-t: TCP协议的集群
-u: UDP协议的集群
-f: FWM: 防火墙标记
添加:-A
修改:-E
删除:-D -t|u|f service-address

LVS+Keepalived搭建高可用集群

Keepalived介绍

LVS的弊端:

  1. 后端:需要镜像服务器
  2. 后端:没有健康检查机制
  3. 自身:单点故障(LVS出现故障后,整个集群都不能正常使用)
    keepalived是集群管理中保证集群高可用(High Available)的服务软件,对LVS进行了改进:
  4. 使用心跳机制探测后端RS是否提供服务。
    a) 探测网卡接口是否down,如果是,从LVS中删除该RS
    b) 检测到down的机器又up,则从LVS中再次添加该RS
  5. LVS DR,使用主从(HA)模式,即LVS有备用的机器
    Keepalived结构图:

LINUX中搭建LINUX中搭建LVS+Keepalived集群

准备工作

需要修改集群中RS的内核ARP通告和响应级别,配置好VIP,并启动httpd服务,LVS不需要做任何配置

1. 在node001和node004上安装keepalived
1
2
[root@node001 ~]# yum install keepalived –y
[root@node004 ~]# yum install keepalived –y
2. 修改keepalived的配置文件
1
2
3
[root@node001 ~]# cd /etc/keepalived/
[root@node001 keepalived]# cp keepalived.conf keepalived.conf.bak
[root@node001 keepalived]# vi keepalived.conf

对keepalived.conf配置文件做说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
! Configuration File for keepalived
<!-- global_defs start-->
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
<!-- global_defs end-->
<!-- vrrp_instance VI_1 start-->
vrrp_instance VI_1 {
state MASTER //指定本机是主机还是从机,node004改为BACKUP
interface eth0
virtual_router_id 51
priority 100 //从机的改为其一半
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.9.100/24 dev eth0 label eth0:0 //指定监听的接口
}
}
//可以添加多台LVS
virtual_server 192.168.9.100 80 {
delay_loop 6
lb_algo rr //LVS调度RS的算法
lb_kind DR //LVS的模式
nat_mask 255.255.255.0 //LVS的子网掩码
persistence_timeout 0
protocol TCP
real_server 192.168.9.102 80 { //指定RS的IP和端口
weight 1
HTTP_GET { //监听的协议
url {
path /
status_code 200 //根据状态码检测RS是否运行正常
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
//另一台RS,可以添加多台
real_server 192.168.9.103 80 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
<!-- vrrp_instance VI_1 end->

修改配置文件用到一些VI命令:
dG:从当前行到最后一行全部删除
:.,$-1y:从当前行到倒数第二行全部复制

3. 修改node004的keepalived配置文件
1
2
3
4
5
6
7
8
9
10
11
12
[root@node004 ~]# cd /etc/keepalived/
[root@node004 keepalived]# mv keepalived.conf keepalived.conf.bak
[root@node001 keepalived]# scp keepalived.conf root@node004:`pwd`
[root@node004 keepalived]# vi keepalived.conf
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 50 //是主机的一半
……
}
4. 启动keepalived服务
1
2
[root@node001 keepalived]# service keepalived start
[root@node004 keepalived]# service keepalived start
5. 配置完成,进行测试



LVS功能正常
破坏掉主机的eth0网卡
[root@node001 keepalived]# ifconfig eth0 down
发现VIP已经漂移到node004

1
2
3
4
5
[root@node004 keepalived]# ifconfig
eth0 inet addr:192.168.9.104 Bcast:192.168.9.255 Mask:255.255.255.0
eth0:0 Link encap:Ethernet HWaddr 00:0C:29:54:A1:77
inet addr:192.168.9.100 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

浏览器也不受影响

再恢复node001的eth0网卡,VIP再次漂移回node001

1
2
3
4
5
6
7
8
9
[root@node001 keepalived]# ifconfig eth0 down
[root@node001 keepalived]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:67:1D:65
inet addr:192.168.9.101 Bcast:192.168.9.255 Mask:255.255.255.0
eth0:0 Link encap:Ethernet HWaddr 00:0C:29:67:1D:65
inet addr:192.168.9.100 Bcast:0.0.0.0 Mask:255.255.255.0
[root@node004 keepalived]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:54:A1:77
inet addr:192.168.9.104 Bcast:192.168.9.255 Mask:255.255.255.0

杀掉keepalived进程

1
2
3
4
5
6
7
8
9
10
11
[root@node001 ~]# ps –ef
root 1136 1 0 21:26 ? 00:00:00 /usr/sbin/keepalived -D
root 1138 1136 0 21:26 ? 00:00:00 /usr/sbin/keepalived -D
root 1139 1136 0 21:26 ? 00:00:00 /usr/sbin/keepalived –D
[root@node001 ~]# kill -9 1136
[root@node004 keepalived]# ps –ef
root 1145 1 0 21:27 ? 00:00:00 /usr/sbin/keepalived -D
root 1146 1145 0 21:27 ? 00:00:00 /usr/sbin/keepalived -D
root 1147 1145 0 21:27 ? 00:00:00 /usr/sbin/keepalived –D
[root@node004 keepalived]# kill -9 1145
多次查看进程,确保杀死所有keepalived进程

此时主机和从机都拥有了VIP

1
2
3
4
5
6
7
8
9
10
[root@node001 ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:67:1D:65
inet addr:192.168.9.101 Bcast:192.168.9.255 Mask:255.255.255.0
eth0:0 Link encap:Ethernet HWaddr 00:0C:29:67:1D:65
inet addr:192.168.9.100 Bcast:0.0.0.0 Mask:255.255.255.0
[root@node004 keepalived]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:54:A1:77
inet addr:192.168.9.104 Bcast:192.168.9.255 Mask:255.255.255.0
eth0:0 Link encap:Ethernet HWaddr 00:0C:29:54:A1:77
inet addr:192.168.9.100 Bcast:0.0.0.0 Mask:255.255.255.0

这种情况说明keepalived会出现问题,在互联网中出现这种情况后,会导致发送的数据包同时发送到主机和从机,需要使用zookeeper来解决这个问题。

Nginx

Nginx简介

Nginx(”engine x”)是一个高性能的HTTP和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。官方测试nginx能够支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。2011年6月1日,nginx 1.0.4发布。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发,其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:新浪、网易、腾讯等。
功能:web服务器、web reverse proxy、smtp reverse proxy

Nginx和apache的比较
  1. nginx相对于apache的优点:
    轻量级,同样起web服务,比apache占用更少的内存及资源 ;
    抗并发,nginx处理请求是异步非阻塞的,而apache则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能 ;
    高度模块化的设计,编写模块相对简单 ;
    社区活跃,各种高性能模块出品迅速。
  2. apache 相对于nginx 的优点:
    rewrite ,比nginx的rewrite强大 ;
    模块超多,基本想到的都可以找到 ;
    少bug,nginx的bug相对较多。
  3. Nginx配置简洁,Apache复杂 。
  4. 最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程。
    单个tomcat支持的最高并发
    解决高并发和单个服务器过载问题

    Tengine安装

    Tengine是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。
1. 解压安装包

[root@node001 local]# tar xf tengine-2.1.0.tar.gz

2. 进入tengine目录

[root@node001 local]# cd tengine-2.1.0/

3. 查看README文件,找到安装方法

To install Tengine, just follow these three steps:
$ ./configure
$ make

# make install
4. 执行configure文件,指定安装目录
1
2
3
4
5
6
7
8
9
10
[root@node001 tengine-2.1.0]# ./configure --prefix=/usr/local/nginx
使用如下命令查看更多安装选项
[root@node01 tengine-2.1.0]# ./configure --help
--help print this message
--prefix=PATH set installation prefix
--sbin-path=PATH set nginx binary pathname
--conf-path=PATH set nginx.conf pathname
--error-log-path=PATH set error log pathname
……
5.报错:

./configure: error: C compiler cc is not found

6.安装gcc,再执行configure文件

[root@node001 tengine-2.1.0]# yum install gcc

7. 报错:

./configure: error: the HTTP rewrite module requires the PCRE library.

8. 查看PCRE有哪些版本
1
2
3
4
5
6
[root@node001 tengine-2.1.0]# yum search pcre
pcre-devel.i686 : Development files for pcre
pcre-devel.x86_64 : Development files for pcre
pcre-static.x86_64 : Static library for pcre
pcre.x86_64 : Perl-compatible regular expression library
pcre.i686 : Perl-compatible regular expression library
9. 选择安装开发版,系统自动识别安装什么位数的软件

[root@node001 tengine-2.1.0]# yum install pcre-devel

10. 再执行configure文件

[root@node001 tengine-2.1.0]# ./configure --prefix=/usr/local/nginx

11. 报错:

./configure: error: SSL modules require the OpenSSL library.

12. 根据pcre的经验,安装OpenSSL开发版

[root@node001 tengine-2.1.0]# yum install openssl-devel

13. 再执行configure文件

[root@node001 tengine-2.1.0]# ./configure --prefix=/usr/local/nginx
看到如下信息说明configure文件执行成功:

14. 执行make命令

[root@node001 tengine-2.1.0]# make

15. 执行make install命令

[root@node001 tengine-2.1.0]# make install

16. 将nginx文件放到/etc/init.d目录下,并做修改
1
2
3
[root@node001 tengine-2.1.0]# vi /etc/init.d/nginx
nginx="/usr/local/nginx/sbin/nginx"
NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"
17. 给nginx文件赋予执行权限

[root@node001 tengine-2.1.0]# chmod +x nginx

18. 启动服务

[root@node001 sbin]# service nginx start

19. 验证是否启动
1
2
[root@node001 sbin]# service nginx status
nginx (pid 6510 6508) is running...
20.去网页验证,看到如下页面说明nginx安装成功!

Nginx配置解析

nginx.conf配置文件的结构

……
events{
……
}
http {
……
server{
……
}
server{
……
}
}

全局的配置

user nobody; #定义Nginx运行的用户和用户组
说明:

1
2
3
4
5
6
7
[root@node01 tengine-2.1.0]# ps -fe | grep nginx
root 1367 1335 0 13:18 pts/1 00:00:00 vi nginx.conf
root 1608 1 0 14:32 ? 00:00:00 nginx: master process /opt/sxt/nginx/sbin/nginx –c /opt/sxt/nginx/conf/nginx.conf
nobody 1610 1608 0 14:32 ? 00:00:00 nginx: worker process
root 1626 1097 0 14:45 pts/0 00:00:00 grep nginx
[root@node01 tengine-2.1.0]# service nginx status
nginx (pid 1610 1608) 正在运行...

master process不负责处理客户端连接请求,负责对worker process的监管,而worker process负责处理客户端请求。Nginx支持热加载和热升级,比如更新了配置文件后执行reload命令,master会开出一个新进程去读取更新过的配置文件,而worker进程继续保持从旧请求的连接,直到旧进程死亡,新进程会与新请求连接。master process由root启动,worker process由nobody启动,权限较小。

1
2
3
4
5
6
worker_processes 1; #nginx进程数,建议设置为等于虚拟机CPU总核心数
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
pid logs/nginx.pid; #进程文件

event下的一些配置及其意义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use epoll;
#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ];
#epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型
#如果跑在FreeBSD上面,就用kqueue模型。
worker_connections 1024; #单个进程最大连接数(最大连接数=连接数*进程数)
#假设worker_processes为8
#系统可以打开的最大文件数和内存大小成正比
#查看自己的系统可以打开的最大文件数 cat /proc/sys/fs/file-max :97318
#并发连接总数小于系统可以打开的文件总数,这样就在操作系统可以承受的范围之内
#选择最大连接数为80000
#在设置了反向代理的情况下,根据经验,最大连接数应该再除以4,就是20000
#所以单个进程最大连接数为20000/8 = 2500
#同时应该调整系统的单个进程可以打开的文件数
#使用ulimit –a查看到open file =1024
#应该调整系统的单个进程最大打开文件数(该数值x进程数<=97318)
#ulimit -SHn 10000
http下的一些配置及其意义
1
2
3
4
5
6
7
8
9
10
11
12
13
include 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 logs/access.log main; #日志文件位置
sendfile on;
#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off.
原理,比如Nginx接受用户对某文件的请求,nginx不能直接读取磁盘的内容,需要经过内核的调用,nginx告诉内核需要读取x文件,内核会读取x文件到内核的内存中,在把这个文件copy到nginx的内存堆中,nginx得知数据已经准备好,会再把这个文件发给内核,内核切片之后发送给用户。当并发数过大时太耗费资源,所以这个选项的存在是为了减少文件在两个内存之间的copy,提高效率。
keepalive_timeout 0; #长连接超时时间,单位是秒(与keeplived软件无关)
#gzip on; #开启gzip压缩输出
server下的一些配置及其意义
1
2
3
4
5
6
7
8
listen 80; #监听的IP和地址
server_name www.bbb.com; #主机名
location / {
root /opt; #网页文件存放的目录
index index.html index.htm;
#默认首页文件,顺序从小到右,如果找不到index.html,则index.htm为首页
autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。
}

虚拟主机

虚拟主机是一种特殊的软硬件技术,它可以将网络上的每一台计算机分成多个虚拟主机,每个虚拟主机可以独立对外提供www服务,这样就可以实现一台主机对外提供多个web服务,每个虚拟主机之间是独立的,互不影响的。

基于IP的虚拟主机
1. 查看服务器的IP地址
1
2
3
4
5
[root@node01 ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:A6:C6:18
inet addr:192.168.9.11 Bcast:192.168.9.255 Mask:255.255.255.0
lo Link encap:Local Loopback
ine###### inet addr:127.0.0.1 Mask:255.0.0.0
在eth0网卡设备上添加两个IP别名192.168.9.98和192.168.9.99
1
2
3
4
[root@node01 ~]# ifconfig eth0:1 192.168.9.98 broadcast 192.168.9.255 netmask 255.255.255.0 up
[root@node01 ~]# route add -host 192.168.9.98 dev eth0:1
[root@node01 ~]# ifconfig eth0:2 192.168.9.99 broadcast 192.168.9.255 netmask 255.255.255.0 up
[root@node01 ~]# route add -host 192.168.9.99 dev eth0:2

注意:以上配置只是临时生效,想让它们永久生效,可以将这两条ifconfig和route命令添加到/etc/rc.local文件中,让系统开机时自动运行。在文件末尾增加以下内容,保存退出即可。

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
ifconfig eth0:1 192.168.9.98 broadcast 192.168.9.255 netmask 255.255.255.0 up
route add -host 192.168.9.98 dev eth0:1
ifconfig eth0:2 192.168.9.99 broadcast 192.168.9.255 netmask 255.255.255.0 up
route add -host 192.168.9.99 dev eth0:2

3. 验证是否配置成功
1
2
3
4
5
6
7
8
9
[root@node01 ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:A6:C6:18
inet addr:192.168.9.11 Bcast:192.168.9.255 Mask:255.255.255.0
eth0:1 Link encap:Ethernet HWaddr 00:0C:29:A6:C6:18
inet addr:192.168.9.98 Bcast:192.168.9.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
eth0:2 Link encap:Ethernet HWaddr 00:0C:29:A6:C6:18
inet addr:192.168.9.99 Bcast:192.168.9.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
4. 配置基于IP的虚拟主机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@node01 ~]# vi /opt/sxt/nginx/conf/nginx.conf
http {
server {
listen 192.168.9.11:80;
server_name 192.168.9.11;
access_log logs/host.access.log main;
location / {
root /var/www/server1;
index index.html index.htm;
}
}
server {
listen 192.168.9.98:80;
listen 192.168.9.98;
access_log logs/host.access.log main;
location / {
root /var/www/server2;
index index.html index.htm;
}
}
server {
listen 192.168.9.99:80;
server_name 192.168.9.99;
access_log logs/host.access.log main;
location / {
root /var/www/server3;
index index.html index.htm;
}
}
}
5.在/var/www/下创建3个文件夹server1、server2、server3,在其中分别定义三个虚拟主机的首页index.html
1
2
3
4
5
6
7
[root@node01 ~]# mkdir -p /var/www/server{1,2,3}
[root@node01 ~]# vi /var/www/server1/index.html
<h1>From Virtual Host 1:192.168.9.11</h1>
[root@node01 ~]# vi /var/www/server2/index.html
<h1>From Virtual Host 2:192.168.9.98</h1>
[root@node01 ~]# vi /var/www/server3/index.html
<h1>From Virtual Host 3:192.168.9.99</h1>
6. 开启nginx服务(如果已经启动则重启nginx服务)
1
2
[root@node01 ~]# service nginx start
[root@node01 ~]# service nginx reload
7. 在网页查看效果



基于域名的虚拟主机
1.在nginx.conf文件中配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
http {
server {
listen 80;
server_name www.aaa.com;
location / {
root /var;
autoindex on;
}
}
server {
listen 80;
server_name www.bbb.com;
location / {
root /opt;
autoindex on;
}
}
}
2. 修改Windows的hosts文件

192.168.9.11 node01 www.aaa.com www.bbb.com

3.重启服务

[root@node01 ###### [root@node01 ~]# service nginx reload

4.去网页验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@node01 ~]# ll /var
总用量 60
drwxr-xr-x. 6 root root 4096 6月 29 11:50 cache
drwxr-xr-x. 3 root root 4096 5月 22 12:05 db
drwxr-xr-x. 3 root root 4096 5月 22 12:05 empty
drwxr-xr-x. 2 root root 4096 9月 23 2011 games
drwxr-xr-x. 17 root root 4096 6月 29 11:50 lib
drwxr-xr-x. 2 root root 4096 9月 23 2011 local
drwxrwxr-x. 5 root lock 4096 7月 3 07:50 lock
drwxr-xr-x. 4 root root 4096 7月 3 12:39 log
lrwxrwxrwx. 1 root root 10 5月 22 12:04 mail -> spool/mail
drwxr-xr-x. 2 root root 4096 9月 23 2011 nis
drwxr-xr-x. 2 root root 4096 9月 23 2011 opt
drwxr-xr-x. 2 root root 4096 9月 23 2011 preserve
drwxr-xr-x. 13 root root 4096 7月 3 12:39 run
drwxr-xr-x. 8 root root 4096 5月 22 12:05 spool
drwxrwxrwt. 2 root root 4096 6月 30 09:41 tmp
drwxr-xr-x. 2 root root 4096 9月 23 2011 yp


1
2
3
[root@node01 ~]# ll /opt
总用量 4
drwxr-xr-x 3 root root 4096 6月 29 09:46 sxt


注意:确认配置没有问题的情况下如果报错,可尝试service nginx restart(当reload不能解决问题时)

location映射

解析

location [ = | ~ | ~ | ^~ ] uri { … }
location URI {}:
对当前路径及子路径下的所有对象都生效;
location = URI {}:
注意URL最好为具体路径。精确匹配指定的路径,不包括子路径,因此,只对当前资源生效;
location ~ URI {}与location ~
URI {}:
模式匹配URI,此处的URI可使用正则表达式,~区分字符大小写,~不区分字符大小写;
location ^~ URI {}:
不使用正则表达式
优先级:= > ^~ > ~|~
> /|/dir/

精确匹配优先级最高,如果找到,停止搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 192.168.9.11:80;
server_name 192.168.9.11;
location = /images/test.png {
return 601;
}
location /images/test {
return 602;
}
location /images {
return 603;
}
}


所有剩下的常规字符串,最长的匹配

如果这个匹配使用^〜前缀,搜索停止

1
2
3
4
5
6
location /images/test {
return 602;
}
location ^~ /images {
return 604;
}


正则表达式按照顺序匹配

1
2
3
4
5
6
location ~ login {
return 605;
}
location ~ (.*)\.html$ {
return 606;
}


1
2
3
4
5
6
location ~ (.*)\.html$ {
return 606;
}
location ~ login {
return 605;
}

说明
  1. “普通 location” 的匹配规则是“最大前缀”,因此“普通 location ”的确与 location 编辑顺序无关;
  2. “正则 location” 的匹配规则是“顺序匹配,且只要匹配到第一个就停止后面的匹配”;
  3. “普通location ”与“正则 location ”之间的匹配顺序是先匹配普通 location ,再“考虑”匹配正则 location ;也就是说匹配完“普通 location ”后,有的时候需要继续匹配“正则 location ”,有的时候则不需要继续匹配“正则 location ”。两种情况下,不需要继续匹配正则 location :
    1) 当普通 location 前面指定了“ ^~ ”,特别告诉 Nginx 本条普通 location 一旦匹配上,则不需要继续正则匹配;
    2) 当普通location 恰好严格匹配上,不是最大前缀匹配,则不再继续匹配正则
    总结
    location匹配顺序:
    先普通
    顺序无关
    最大前缀
    被打断
    ^~
    完全匹配
    再正则
    不完全匹配
    有顺序
    先匹配,先应用,即时退出匹配

    反向代理

    1
    2
    3
    4
    5
    6
    7
    8
    server {
    listen 192.168.9.11:80;
    server_name 192.168.9.11;
    location / {
    root html;
    index index.html index.htm;
    }
    }



1
2
location /mp3 {
proxy_pass http://192


前提:node03安装了httpd

1
2
3
location /baidu {
proxy_pass http://www.baidu.com/;
}


客户端发生了跳转!http://www.baidu.com会被百度转换为https://www.baidu.com再返回

1
2
3
location /baidu {
proxy_pass https://www.baidu.com/;
}

Nginx负载均衡

1
2
3
4
5
6
7
8
9
10
11
upstream httpd {
server 192.168.9.12:80;
server 192.168.9.13:80;
}
server {
listen 192.168.9.11:80;
server_name 192.168.9.11;
location /mp3 {
proxy_pass http://httpd/;
}
}


Nginx的session一致性问题

http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术。
session的常见实现形式是会话cookie(session cookie),即未设置过期时间的cookie,这个cookie的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。实现机制是当用户发起一个请求的时候,服务器会检查该请求中是否包含sessionid,如果未包含,则系统会创造一个名为JSESSIONID的输出 cookie返回给浏览器(只放入内存,并不存在硬盘中),并将其以HashTable的形式写到服务器的内存里面;当已经包含sessionid是,服务端会检查找到与该session相匹配的信息,如果存在则直接使用该sessionid,若不存在则重新生成新的 session。这里需要注意的是session始终是有服务端创建的,并非浏览器自己生成的。但是浏览器的cookie被禁止后session就需要用get方法的URL重写的机制或使用POST方法提交隐藏表单的形式来实现。
session共享:
首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@node02 software]# rpm -i jdk-7u67-linux-x64.rpm
[root@node02 software]# tar xf apache-tomcat-7.0.61.tar.gz
[root@node02 software]# vi /etc/profile
export JAVA_HOME=/usr/java/jdk1.7.0_67
export PATH=$PATH:$JAVA_HOME/bin
[root@node02 software]# . /etc/profile
[root@node02 software]# java -version
java version "1.7.0_67"
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
[root@node02 software]# jps
1309 Jps
[root@node02 software]# cd apache-tomcat-7.0.61/webapps/ROOT/
[root@node02 ROOT]# cp index.jsp index.jsp.bak
[root@node02 ROOT]# vi index.jsp
From 192.168.9.12<br>
session=<%= session.getId() %>

对node03做相同的配置,index.jsp改为From 192.168.9.13
启动node02和node03的tomcat

1
2
3
4
5
6
7
8
[root@node02 ~]# cd /usr/local/software/apache-tomcat-7.0.61/bin/
[root@node02 bin]# ./startup.sh
Using CATALINA_BASE: /usr/local/software/apache-tomcat-7.0.61
Using CATALINA_HOME: /usr/local/software/apache-tomcat-7.0.61
Using CATALINA_TMPDIR: /usr/local/software/apache-tomcat-7.0.61/temp
Using JRE_HOME: /usr/java/jdk1.7.0_67
Using CLASSPATH: /usr/local/software/apache-tomcat-7.0.61/bin/bootstrap.jar:/usr/local/softwar
e/apache-tomcat-7.0.61/bin/tomcat-juli.jarTomcat started.



在两个页面交替访问192.168.9.12:8080和192.168.9.13:8080,sessionID不变

在nginx上配置,让请求转到node02和node03

1
2
3
4
5
6
7
8
9
10
11
12
upstream tom {
server 192.168.9.12:8080;
server 192.168.9.13:8080;
}
server {
listen 192.168.9.11:80;
server_name 192.168.9.11;
location /cat {
proxy_pass http://tom/;
}
}
[root@node01 software]# service nginx reload





随着页面刷新,sessionId会一直改变!
解决这个问题:memcached(一个内存数据库)

1.安装memcached

[root@node01 software]# yum install memcached -y

2. 启动memcached

[root@node01 software]# memcached -d -m 128m -p 11211 -l 192.168.9.11 -u root -P /tmp/

3. 让node02和node03的tomcat使用memcached
1
2
3
4
5
6
7
8
9
10
11
[root@node02 bin]# cd /usr/local/software/apache-tomcat-7.0.61/conf/
[root@node02 conf]# vi context.xml
加入如下配置:
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.9.11: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目录下

5.重启node02和node03的tomcat服务
1
2
[root@node03 bin]# ./shutdown.sh
[root@node03 bin]# ./startup.sh


此时刷新页面,sessionId不会再改变,session在集群中的一致性问题得到解决,但还存在一种比memcached更优秀的内存数据库——redis.