写这篇文章的目的是想用来帮助自己思考和理清头绪,以及如何从一个简单的网站架构演进发展成一个大型网站架构,主要侧重在技术方面
由于我没有做过php,那么就以jsp为例,jsp做网站前端,以电子商务网站为例,描述一个简单的网站架构
前端 jsp+css+js
后端 java ssh
Web容器 tomcat
数据库 mysql
开发人员,美工1个,前端一个,java一个
部署方案为:
一台服务器,部署tomcat和mysql
架构图如下:
应用和数据库分布式部署
那么网站运行一段时间,开始盈利了,用户也增多了,这时候数据库的数据量还不是很大
但是越来越多的用户访问,会占用大量的服务器内存和cpu,应该要将数据库和应用分开部署,架构图如下
这样网站还能运营一段时间
解耦合开发
那么我们再来看看开发方面的问题,但是开发和运维往往是分不开的,由于网站业务发展较快,我们肯定要在上面添加新的功能,否则没法玩了,功能也越来越多,开发人员 也变多了,互相之间依赖也变多了,以前的开发模式是,java程序员从jsp一直写到dao,全部包揽,那么现在有5个java一起开发了,各负责不同的功能,如用户模块,商品模块,订单模块,交易模块等,那么问题就来了
1 java程序员经常干些调css,和写大量javascript的活,我们用的是jquery
2 并不是每次都要等到所有模块都完成开发了才上线,很多时候只需要一个模块完成修改,就可以上线了,然后代码都写在一个项目里面,版本控制变得相当困难,而且每次修改一个模块的功能,可能影响到另一个模块的功能,导致项目变的非常不稳定,正在运营中的项目,出现这种情况将是致命的,无限的加班加点也于事无补,痛苦啊。
解决方案1(模块化)
这是多年前我想到的一个方案,这么多功能不能混乱的放在一个project里面,这里我指的是java web项目,至少要在开发的时候模块化,将不同的功能独立出去,模块之间通过接口调用,比如分为用户模块,应用模块,商品模块,订单模块,交易模块等,不同的人负责开发,那么模块之间怎么进行通信呢,我当时的方案是,每个后端模块都是一个jar包项目,发布的时候打成jar包给其他模块调用,项目通过maven进行构建,这样开发到部署就比较自动化,基本实现模块化开发了,项目发布也变得稳定多了。
用maven做模块化的缺点
这个思想是从spring那里得来的,他们也是将不同功能进行模块化,然后这种形式却有很多的缺点:
1 随着时间的推移,各个模块都在不停的更新,版本一直在升级,假如模块A依赖模块B,C
可以理解为A是web前置模块,B是用户模块,C是订单模块
如下图:
如果B或者C变更了,那么A有2种选择:
1 不更新B和C,仍然可以用,带来的后果将是得不到最新的b和c的功能支持
2 如果选择更新,A需要重新加入新的B或者C的jar包并进行调试和测试工作,
从接口依赖来看
由于B和C需要查数据库,因此B和C的jar包暴露了过多的api给A,且没办法很好的控制,对于项目A的开发者来说,接口不明确,几乎所有public的方法都可以调用,这样B和C的变更对上层的A来说,造成的影响是不可控的。
从系统性能来看
由于B和C都是要查数据库的,那么以jar的形式在A中,占用A项目所有服务器的内存和cpu等资源,无法分布式部署。
解决方案2:模块化并分布式部署
那么应该用什么方案呢,最好是分布式部署,A与B,C通过网络通信进行调用
这样带来的好处
1 A,B,C实现分布式部署
2 B,C提供明确的接口给A调用,只要接口不变,B和C修改内部业务逻辑,A不需要重新构建和部署,达到最大限度的解耦合,就是说修改系统的部分功能,其他模块可以不受影响,或者受较小影响,而且影响范围是可以控制的。
可选的方案有http tcp/ip(socket)等
基于http协议,xml报文传输
客户端具体框架为httpclient,服务端为struts2
客户端和服务端的通信在内网
该方案我们实行过一段时间,发现存在性能问题,首先是短连接,在并发量较大的时候,开启大量的tcp连接,这样连接资源容易耗尽,客户端首先成为瓶颈,tps上不去。
我总结的几点原因:
1.每次通信都重新开启新的tcp连接,握手协议耗时间
2.tcp是慢启动,TCP 数据传输的性能还取决于 TCP 连接的使用期(age)。TCP 连接会随着时间进行自我“调谐”,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐被称为 TCP 慢启动(slow start),用于防止因特网的突
然过载和拥塞
3.http协议是在tcp协议上封装了一层,因此还存在解析协议的消耗,如果直接用tcp协议进行传输,效率将要高一点
据说http1.1可以实现长连接,但是没有用java客户端试过,后续再研究
4.短时间内开启过多的连接,容易将系统资源耗尽
主要开发任务在客户端,我是用Mina做的长连接异步通信,
我自己编写代码实现了一个,有时间贴出来分享一下,如果有想了解Mina使用技术的,可以先看我的Mina系列博客http://www.cnblogs.com/tangyanbo/p/4297377.html
这里我做了相关的性能测试,下面把测试结果贴出来一下:
短连接测试
场景描述
socket 发送消息到服务端,接收到响应后关闭
结果:
一段时间过后,会出现死掉的现象,连接会被耗尽
服务器cpu |
2线程 3000Mhz |
服务器cpu使用率 |
110% |
客户端cpu |
4线程 2400Mhz |
客户端cpu使用率 |
95% |
客户端执行线程数 |
500 |
每秒并发数 |
1800 |
长连接异步通讯测试
场景描述
客户端开启2个长连接,与服务端通信
服务器cpu |
2线程 3000Mhz |
服务器cpu使用率 |
100%-150% |
客户端cpu |
4线程 2400Mhz |
客户端cpu使用率 |
60% |
客户端连接数 |
2 |
客户端执行线程数 |
500 |
每秒通过事务数 |
16000 |
性能明显提升,而且状态稳定,cpu利用率较低
这里大家会有个问题,为什么要用异步通信,不能是同步
这里其实我们先要搞清楚什么是同步通信,什么是异步通信
同步通信应该很好理解,这里我们以同一个socket连接为例,即多次请求都是从一个socket连接发送出去的。
Socket客户端发送一个请求,等待响应成功之后,再发送另一个请求,即在同一时间只能发送一个请求,假如我们的场景是这样的,发送的报文较小,服务端处理的速度较快,我们网站的大多数业务请求都是这样的,这样报文在网络中传输的时候,通道是很空闲的,通信的吞吐量将收到影响。
典型的同步通信案例是jdbc
还是以同一个socket连接为例,socket客户端发送一个请求之后,在响应还没到来的时候,可以继续发送另一个请求,具体场景是这样的,业务线程1发送请求,然后线程等待结果,业务线程2发送请求,然后等待结果,以此类推,但是socket输出通道可以一直发送消息,socket输入一直在接收消息,这样业务处理和通信逻辑是分离开来的互不干扰,且充分利用了通信通道,因为网络传输的速度比cpu和磁盘要慢的多,因此有效利用网络资源,将极大的提高系统吞吐量,当然要记住这里的使用场景,高并发,较小的报文传输,如果报文特别大,几十MB,那异步通信就没意义了
Mina是使用的NIO
这个网站上很多资料,我就简单的讲下,我们的场景是适合用NIO的,为什么呢?
我们的场景除了高并发,报文小,还有一个特点,就是客户端部署的点要远远多于服务端,因为越是底层的服务,可重用性越高,那么客户端就相对较多,服务端相对较少。
BIO的缺点
传统的BIO特点,有N个客户端连接服务端,服务端就需要开启N个线程来分别处理客户端的请求,而且很多时候客户端是空闲状态的,那么服务端给它开的线程也将空闲,造成了资源浪费,同时线程数还不够用。
NIO的优点
NIO很好的解决了这个问题,它使得服务端的一个线程可以处理多个客户端连接,只要协调的好,可以用较少的线程处理较多的客户端连接,使线程利用率得到很大的提高。
随着网站的业务越来越多,网站的服务就变的很重要,假设某天你的服务器挂了,会不会是一个天大的灾难呢?而且这种事情发生的概率还不小,断电了,服务器硬盘坏了,内存坏了等等,都会使你的系统挂掉,而且高并发的访问有时候也会使系统资源耗尽,然后导致服务器宕机,那么解决方案呢,那就是集群,将相同的系统分别放到不同的web服务器或者硬件服务器,这样其中一个挂掉了,网站还可以正常运营。
首先我们应该对web前置做集群,我们的方案是用Haproxy做http协议层的负载均衡,后端部署多个web前置,当然也可以用LVS,负载均衡效率更高,请参考我的另一篇博文:LVS实现负载均衡,这篇文章讲的是mysql的负载均衡,当然做web应用的集群原理是一样的,当然还有其他的一些中间件,如Ngnix也是可以的,关于负载均衡的中间件我会另起博客详细讲解的。
理解ip负载均衡和数据链路层负载均衡,需要熟悉tcp/ip协议。
反向代理负载均衡
典型的反向代理中间件有Haproxy和Ngnix,请求转发在http协议层面,其优点是和反向代理服务器功能集成在一起,部署简单,缺点是需要在中间件做http的转发,工作在应用层,且请求和响应都要经过反向代理服务器,容易成为性能瓶颈。
系统架构图:
Ip层负载均衡
通过修改请求目标地址进行负载均衡
具体实现:LVS
优点:ip负载均衡在内核完成ip转发,较反向代理性能要好,但请求和响应都要经过仍然要经过ip负载均衡服务器,因此吞吐量的瓶颈会出现在ip负载均衡服务器的网卡上。
系统架构图:
数据链路层负载均衡
通过修改mac地址来完成请求的转发,负载均衡数据分发过程中不修改IP地址,只修改目的mac地址,通过配置真实服务器集群所有机器虚拟IP和负载均衡IP地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的,由于实际处理请求的真实服务器IP和数据请求目的IP一致,不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡宽带成为瓶颈。
系统架构图:
Web应用一般都是需要保持用户会话的,因此做集群之后会出现问题,默认情况下,客户端请求是被均匀的分发到后端服务器的,那么同一个会话的两次请求可能会被分配到不同的服务器,那么session就会丢失。
如何解决这个问题呢?
方案1:session复制
就是将1台服务器的session复制到其它所有的服务器上,这样无论访问哪台服务器,都会得到用户的session
该方案的缺点
当服务器的数量比较大时,session同步将会变得相当耗时
方案2:session粘滞
就是用户请求一个服务器之后,同一个会话的其它请求,都会被分配到这台服务器,session粘滞的功能由负载均衡中间件完成。
该方案的优点,解决了session复制的性能问题
该方案的缺点,由于用户的会话被保存到单一的服务器,就容易出现单点故障。
那么有没有更好的解决方案呢?
方案3:session服务器
部署一个专门的服务,保存用户session,同时在web服务器本地也保存一份,当本地没有或者失效时,去访问session服务器,当然session服务器就成了单点,当用户量大的时候也容易宕机,这时可以做一个session服务器集群,做主备同步备份,这样就达到了较好的效果,具体实现可以用redies,memcached等缓存中间件。
系统架构图:
结语:负载均衡至少有2个优点
1. 多点部署,解决了单点故障问题,提高了网站的可用性
2. 能通过利用更多的硬件资源提高系统性能
上篇文章讲到了负载均衡的相关理论知识,这篇文章我打算讲讲实践方法以及实践中遇到的问题
方案:haproxy http层负载均衡
安装一个haproxy服务,两个web服务
haproxy:192.168.1.227:80
web1 http://192.168.1.226:8081/login
web2 http://192.168.1.246:8888/login
web服务自行准备,文章中就不说了
负载均衡算法为轮询调度
会话保持实现方式为cookie识别,插入cookie
优点:
1 配置简单
2 提供会话保持功能
3 性能不错
安装
tar -zxvf haproxy-1.49.tar.gz
cd haproxy-1.4.9
make TARGET=linux26 PREFIX=/haproxy
make install PREFIX=/haproxy 创建日志目录 mkdir /home/haproxy/logs/ 创建配置文件目录 mkdir /etc/haproxy/
PREFIX=/haproxy : 安装目录前缀
启动程序将安装在 /haproxy/sbin/haproxy
配置
global log 127.0.0.1 local3 #log 127.0.0.1 local1 notice #log loghost local0 info maxconn 4096 #chroot /usr/local/haproxy #chroot /home/haproxy uid 502 gid 502 daemon nbproc 1 pidfile /home/haproxy/logs/haproxy.pid #debug #quiet defaults log global mode http option httplog option dontlognull option forwardfor option redispatch log 127.0.0.1 local3 retries 3 maxconn 32000 balance roundrobin stats uri /haproxy-stats contimeout 5000 clitimeout 50000 srvtimeout 50000 listen web_proxy *:80 appsession JSESSIONID len 52 timeout 3h #插入cookie的方式 cookie SRV insert indirect nocache #模式有http tcp health mode http stats enable stats hide-version #查看状态 stats uri /haproxy-stats stats refresh 10s monitor-uri /haproxy_test #负载均衡方案:轮调 balance roundrobin option httpclose #后端可以获取客户端的真实ip option forwardfor #健康检查 option httpchk HEAD /login HTTP/1.0 #option httpchk GET /ping.jsp #后端真实服务 server webA 192.168.1.226:8081 cookie A check server webB 192.168.1.246:8888 cookie B check
这里注意配置检查地址
option httpchk HEAD /login HTTP/1.0
启动
/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg
查看进程
ps -ef|grep haproxy
关闭进程
kill –9 pid
查看监控页面
http://192.168.1.227/haproxy-stats
如下图:注意状态一栏显示200,如果不是则表示web服务器未启动,或者健康检查链接不可访问
测试
然后打开不同的浏览器,模拟用户访问
http://192.168.1.227/login/
会看到
证明请求被分发到不同的web服务器了
查看cookie
cookie被加入了SRV=A
会话保持的流程
1.客户端首次请求,经过haproxy到web服务端时,web服务端set-cookie并响应到haproxy
2.haproxy在cookie后插入SRV=A,并响应客户端
3.客户端第二次请求,经过haproxy时,haproxy将srv后缀去掉,然后请求服务端
总结
该方案解决的问题
1.负载均衡,并解决web服务的单点故障
2.会话保持
存在的缺点
1.web服务器的session保存存在单点故障,即其中一台web服务器宕机之后,存储在上面的session也会丢失
2.负载均衡服务器存在单点故障
上一篇文章讲到了haproxy+tomcat的方案,大家可以先温习一下,
文中提到了高可用,该集群方案也可以提高应用系统的高可用,如果tomcat应用出现故障,或者tomcat应用服务器出现故障,haproxy会检测到(这里指的是定期心跳检查),并将应用从可用列表中删除,打开监控页面http://192.168.1.227/haproxy-stats
可以看到有2个web应用运行,如果将webA停掉,可以看到webA显示down
这样客户端请求就不会分发给webA,下面模拟一下webA宕机的情况
这里对sessionId增加了一个后缀做标记
webA:jvm3
webB:jvm2
1. webA正常的情况,客户请求被分发到webA
此时产生的sessionId为jvm3
2. 停掉webA,刷新浏览器
可以看到请求被转发到webB
也就是说web应用出现故障,haproxy会做切换,因此可以保证web应用的高可用。
如果haproxy本身出现故障,那么网站将不可用,所以我们接下来要做的事情就是解决haproxy单点故障的问题。
我们可以运用虚拟ip技术,将haproxy部署在2台服务器上,一台做为master,正常运营,一台为backup,
当master出现问题的时候,接管master。
首先有一个虚拟ip暴露给客户端,虚拟ip对应的mac地址为master服务器,
用户向虚拟ip发送一个请求,该请求会被分发到master服务器上,当master出现故障时,被backup检测到,则backup成为master,
且发送消息将arp缓存虚拟ip对应的mac地址backup的mac地址,这样发送到虚拟ip的报文会被转发到backup 。
架构图:
该方案解决了haproxy单点故障的问题,具体用keepalived实现,详细请参考文章:
Keepalived 实现双机热备
Keepalived + haproxy双机高可用方案
如果想实践的朋友,请按照上面2篇文章安装和配置haproxy和keepalived
系统分布如下:
ha主机 192.168.1.227:80
ha备机 192.168.1.246
keepalived 主机 192.168.1.227
keepalived备机 192.168.1.246
web1 http://192.168.1.226:8081/login
web2 http://192.168.1.246:8888/login
虚拟ip 192.168.1.99
安装好haproxy和keepalived后,启动haproxy和keepalived
Haproxy访问地址:
http://192.168.1.99/haproxy-stats
注意pid为9644,这是master上的haproxy
应用访问地址
http://192.168.1.99/login/
注意sessionId的后缀为jvm3
查看虚拟ip1.99对应的mac地址
接下来,我们停掉master上的haproxy服务
kill -9 9644
查看haproxy http://192.168.1.99/haproxy-stats
发现haproxy的pid变成backup机器上的了
刷新web的访问页面http://192.168.1.99/login/
发现sessionId没有变化
查看虚拟ip1.99对应的mac地址
mac地址已经变为backup机器上的了
如果我们直接关闭主机服务器或者关闭主机的keepalived,发现测试结果也是一样的
因此该方案实现了haproxy的高可用,解决了haproxy的单点故障问题。
会话保持问题
那么这里我还要提出一个疑问,为什么sessionId也没有变化呢?
也就是说切换到backup服务器的haproxy之后,
可以保持用户的会话,那么它是怎么实现的呢?
这里就要回到上篇文章讲的负载均衡时保持会话的策略
会话保持的流程
1.客户端首次请求,经过haproxy到web服务端时,web服务端set-cookie并响应到haproxy
2.haproxy在cookie后插入SRV=A,并响应客户端
3.客户端第二次请求,经过haproxy时,haproxy将srv后缀去掉,然后请求服务端
这种保持会话的方法是无状态的,也就说主要haproxy配置的负载均衡策略相同,不管在哪台机器上运行
将得到同样的结果
在第三,四篇文章中讲到了会话保持的问题,而且还遗留了一个问题,就是会话保持存在单点故障,
当时的方案是cookie插入后缀,即haproxy指负责分发请求,应用服务自行保持用户会话,如果应
用服务器宕机,则session会丢失。
现在来温习下解决方案
方案1:session复制
原理 |
就是将1台服务器的session复制到其它所有的服务器上,这样无论访问哪台服务器,都会得到用户 的session |
优点 |
不存在单点故障问题 |
缺点 |
当服务器的数量比较大时,session同步将会变得相当耗时 |
方案2:session粘滞
原理 |
就是用户请求一个服务器之后,同一个会话的其它请求,都会被分配到这台服务器,session粘滞的 功能由负载均衡中间件完成 |
优点 |
解决了session复制的性能问题 |
缺点 |
由于用户的会话被保存到单一的服务器,就容易出现单点故障 |
方案3:session服务器
原理 |
部署一个专门的服务,保存用户session,同时在web服务器本地也保存一份,当本地没有或者失效时, 去访问session服务器,当然session服务器就成了单点,当用户量大的时候也容易宕机,这时可以做一 个session服务器集群,做主备同步备份,这样就达到了较好的效果,具体实现可以用redies,memcached 等缓存中间件。 |
优点 |
解决了单点故障和性能问题 |
缺点 |
实现复杂 |
redis保存session方案
上篇文章讲到的就是session粘滞的方案,既然前2种方案都有各自的缺点,那么就采用第三中方案
可以用redis做session缓存,保存用户session,做成主备模式,采用同步备份或者异步备份。
同步备份:在主机宕机时,备机接管之后session数据不丢失。
异步备份:在主机宕机时,备机接管主机,但是如果有一部分session还没来得及同步到备机,session将丢失。
可以根据实际情况来决定采用同步备份还是异步备份。
系统架构图如下:
如果用户量比较大,单服务器访问和存储session将会成为瓶颈,可以考虑用session服务器集群,架构图如下:
redis集群特点
1)将数据分散到集群中的多个节点,每个节点存储的数据量就会变少,这样存储和访问
的效率会得到提升。
2)每个节点都有主备,如果节点的主存储挂了,备份存储会接管主存储,提高可用性。
session流程
1.客户端首次请求服务端
2.服务端产生session并set cookie响应给客户端
3.客户端再次请求服务端,会带上cookie
4.服务端根据cookie找到对应的session
实现思路
如果我们要编写程序实现这个方案,需要解决以下问题:
1.session的安全性,即不容易被仿造。
2.session的唯一性,如果用tomcat产生session的策略,多台tomcat会产生的session会存在重复的可能。
3.session的有效期维护,session会有个有效期,用户在这个时间内不访问系统,session将会失效,如果
用户一直访问,则要自动延长session有效期。
4.在集群session服务器中,要考虑负载均衡,这也是需要编写客户端代码的,在分布式session缓存中,
需要根据sessionId哈希分布,那么就和服务器个数进行了耦合,在添加和移除服务器的时候,将出现数
据不一致的问题 。
5.如何实现才能让应用程序改动最小,或者是不改动。
我们可以选择自己写程序来实现以上功能,不过在这里我使用一个现成的框架,即tomcat-redis-session-manager
有时间并感兴趣的朋友,可以在这个基础上自行实现一个,这样更适合自己的项目。
服务器部署分布:
ha主机 192.168.1.227:80
ha备机 192.168.1.246:80
keepalived 主机 192.168.1.227
keepalived备机 192.168.1.246
web1 http://192.168.1.226:8888/login
web2 http://192.168.1.246:8888/login
redis主 192.168.1.245 6380
redis备
安装redis
主机和备机都安装redis
wget http://download.redis.io/releases/redis-2.8.5.tar.gz
解压:
tar xzf redis-2.8.5.tar.gz
cd redis-2.8.5
make
启动
src/redis-server redis.conf --port 6380 &
客户端登录
src/redis-cli -p 6380
备机配置复制:
redis.conf文件中
添加
slaveof 192.168.1.245 6380
Tomcat配置
tomcat版本:7.0.61
相关jar包:
注意这里的jar包最好是按下面的版本,否则会出现jar包冲突的问题。
tomcat-redis-session-manager-1.1.jar
commons-pool-1.6.jar
jedis-2.1.0.jar
下载tomcat redis session manager
https://github.com/jcoleman/tomcat-redis-session-manager/downloads
下载 apache common pool
http://commons.apache.org/proper/commons-pool/download_pool.cgi
下载版本:tomcat-redis-session-manager-1.1
redis的jar包可以从maven中央仓库下载
将以上3个jar包放入tomcat/lib目录中
在tomcat context.xml中加入如下内容
<!-- host: optional: defaults to "localhost" --> <!-- port: defaults to "6379" --> <!-- database: optional: defaults to "0" --> <!-- maxInactiveInterval: optional: defaults to "60" (in seconds) --> <Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" /> <Manager className="com.radiadesign.catalina.session.RedisSessionManager" host="192.168.1.245" port="6380" database="0" maxInactiveInterval="60" />
启动tomcat,浏览器请求tomcat
http://192.168.1.226:8888/login/
登录redis客户端,查看session
session已经被保存到redis
下面,我们进行一项测试
测试流程:
1.先访问虚拟ip1.99的应用,得到sessionId
web服务器是226
2.然后将对应的tomcat停掉
3.刷新该应用,若sessionId未变,则表示redis保存session成功。
我们发现web服务器变成了246,但是sessionId未发生变化
该方案将session集中保存在了redis服务器,并做了主备容灾,从一定程度上提高了系统的高可用,由于
redis是内存存储,访问效率较高,在性能上也是比较好的,但是本例中session不是分布式存储,因此当用户量
非常大,并发访问量非常高的时候,session服务器会成为性能瓶颈。
1. 初始阶段
一台服务器就绰绰有余,应用程序、数据库、文件等所有资源都在一台服务器上,使用开源的lamp.
2. 应用服务和数据服务分离:
随着网站业务快速发展,一台服务器已无法满足需求,越来越多的数据导致存储空间不足。这时就需要将应用和数据分类。应用和数据分离后整个网站使用三台服务器:应用服务器、文件服务器、数据库服务器。
这三台服务器对硬件资源的要求各不相同,应用服务器需要处理大量的业务逻辑,因此需要更快更强大的cpu;数据库服务器需要快速硬盘检索和数据缓存,因此需要更快的硬盘和更大的内存;文件服务器需要存储大量用户上传的文件,因此需要更大的硬盘。
3. 使用缓存改善网站性能
大部分的业务访问集中在一小部分数据上,所以如果把这一小部分数据缓存在内存中,就可以减少数据库的访问压力,提高整个网站的数据访问速度。
4. 使用应用服务器集群改善网站并发处理能力
使用集群是网站解决高并发、海量数据问题的常用手段。增加服务器可以分担原有服务器的访问及存储压力。
应用服务器实现集群是网站可伸缩集群架构设计中较为简单成熟的一种。
5. 数据库读写分离
应用服务器在写数据的时候,访问主数据库,主数据库通过主从复制机制将数据更新同步到从数据库,这样当应用服务器读数据的时候,就可以通过从数据库获得数据。
数据库读写分离,可以改善数据库负载压力。
6. 使用反向代理和cdn加速网站响应
cdn和反向代理的基本原理都是缓存,区别在于cdn部署在网络供应商的机房,使用户在请求网站服务时,可以从距离自己最近的网络供应商机房获取数据;而反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存这用户请求的资源,就将其直接返回给用户。
使用cdn和反向代理的目的都是尽快返回数据给用户,一方面加快用户访问速度,另一方面也减轻后端服务器的负载压力。
7. 使用分布式文件系统和分布式数据库系统
分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务分库,将不同业务的数据库部署在不同的物理服务器上。
8. 使用Nosql和搜索引擎
随着网站业务越来越复杂,对数据存储和检索的需求也越来越复杂,网站需要采用一些非干洗数据库技术如Nosql和非数据库查询技术如搜索引擎。
9. 业务拆分
大型网站为了应对日益复杂的业务场景,通过使用分而治之的手段将整个网站业务分成不同的产品线。
具体到技术上,将一个网站拆分成许多不同的应用,每个应用独立部署维护。应用之间通过一个超链接建立关系,也可以通过消息队列进行数据分发
10.分布式服务