如果项目的用户量少、访问量不大、数据量也不多的时候备案域名dns负载均衡,一台服务器足以支撑,那么直接项目部署一套,直接访问使用就可以了,但是当用户和数据量不断增多,访问量(并发量)不断增加,一台服务器不在能够支撑业务的时候,就需要使用多台机器,设计高性能的集群来应对。dns负载均衡,在软件架构中,有哪些负载均衡它们起到的作用是什么(负载均衡常用的工具有哪些)那么当我部署了多台服务器(这里假如是两台),那么调用方是如何访问的呢?服务方如何均衡访问的流量呢?这时候就需要引出负载均衡了。负载均衡就是通过一定的策略,把用户的访问量均匀地转发给后端的服务器;负载均衡可以提高系统的服务能力和高可用性。负载均衡分类常见的负载均衡技术有三种:DNS负载均衡:大概的原理是,当用户访问域名的时候,需要先通过DNS解析域名,找到对应的IP地址,在这个过程中,可以让DNS服务器,根据用户的地理位置,返回不同的IP,这样就可以实现负载均衡,同时也可以提升用户的访问速度。软件负载均衡:用软件来实现流量的分发,有基于传输层实现的负载均衡,比如LVS,也有基于应用层来实现的,比如Nginx;软件负载均衡实现起来很简单,只需要在服务器上部署并进行配置就可以实现;硬件负载均衡:用硬件来实现负载均衡,比如F5(F5 Network Big-IP),这是一台网络设备,性能很高,同时价格非常的贵。从另外一个角度对负载均衡进行分类,可以分成两种:服务端负载均衡:调用方只访问负载均衡的IP,不需要管后面有多少台服务器。客户端负载均衡:服务端部署多台服务器,客户端知道每台服务器的地址,并通过一定的路由规则,均衡地访问,比如Spring Cloud Ribbon,当然客户端的负载均衡,通常是需要服务注册发现的配合。常见的负载均衡调度算法轮循(Round Robin):将请求循环分配给有效的服务器;加权轮循(Weighted Round Robin):轮训的升级版,给后端的服务器分配不同的权限,根据权重进行循环分配;比如A、B服务器权重分别是100和50,那么请求会保持2:1的比例进行分配;最少连接数(Least Connection):分配的请求根据每台服务器当前所打开的连接数来进行分配;源IP哈希(Source IP Hash):对调用方的IP进行HASH运算,并根据这个计算结果分配服务器,这样的好处是同一个主机的请求,始终会被同一个服务器响应(但是不一定均衡)。我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。组件分离DNS负载均衡不同的web内容分布到不同的服务器上,并划分子域,利用DNS将请求自然转移到不同的服务器上。主要可以分为两大内容:1.动态内容,CPU、IO密集型2.静态内容,IO密集型通过在DNS中配置多个A记录,将请求转移到集群中不同的服务器,这有助于具有地域性问题的大型web站点上,DNS可以使用户就近访问相应的web服务器。像BIND这样的DNS服务软件提供丰富的调度策略。但是,如果集群中的主机出现故障的话,需要更新DNS缓存,这通常需要一定的时间。另外,客户端也可以通过设置host来绕开DNS调度。跨域共享cookie:将cookie的范围扩大到父域。}通过使客户端重定向,来分散和转移请求压力,比如一些下载服务通常都有几个镜像服务器。分布式缓存无法使用页面级别缓存时,需要考虑直接缓存数据,比如使用memcached作为缓存。此时,需要考虑并发写memcached的问题。 另外,当memcached横向规模扩大,服务器数量增加时,需要一种对应算法,能够使应用程序知道应该链接哪个memcached服务器(比如,取模运算)。分布式缓存能够自动重建缓存,不必担心down机。负载均衡负载均衡就是将请求分散,这涉及到应当如何设计调度策略,以让集群发挥最大的性能。当集群中的主机能力相当时应当尽量平均调度,能力不均时应当能者多劳。随着问题的复杂,要时刻关注调度的性能,不要让调度成为性能瓶颈。反向代理负载均衡反向代理服务器工作在,只是NAT工作在网络层。同样是负载均衡,反向代理服务器强调”转发”而不是”转移”,因为它不仅要转发客户端的请求,还要转发服务端的响应。可以用作反向代理服务器的软件有Nginx、lig,另外目前也有一些专业的代理转发设备能够工作在应用层,例如A10。使用代理转发要注意以下问题:由于反向代理的转发特性,使得代理本身很可能成为性能瓶颈。一般对于CPU密集型请求,使用代理比较合适,如果是IO密集型的话,这种集群方式很可能无法发挥最大性能在代理上要开启健康检查,及时发现集群中的故障机,从而调整转发策略,这通常比DNS方式实时性更好黏滞会话:对于启动session保存用户信息,或者后端服务器使用动态内容缓存的应用,必须将用户在一段会话中的的请求保持在同一台服务器上。代理服务器一般支持类似的配置。然而,尽量不要使应用过于本地化,比如可以使用cookie保存用户数据,或者分布式Session或分布式缓存。IP负载均衡字面上看,便是利用网络层进行请求转发,类似NAT网关。然而,使用网关转发在带宽上可能出现瓶颈,因为出口只有一个,所以出口的带宽要求较高。Linux中的Netfilter模块可以通过iptables的配置。比如:对外网端口8001的请求转发给内网某台服务器,而对外网端口8002的请求转发给内网另一台服务器。这种方式简单易行,但是无法对调度做太多配置。LVS-NAT同样是Linux中的在网络层进行转发的方式,与Netfilter不同,它支持一些动态调度算法,比如最小链接、带权重的最小链接、最短期望延迟等。直接路由直接路由是通过调度器修改数据包的目的MAC地址,转发请求数据包,但是响应数据包可以直接发送给外网的方式。这样做显而易见的好处就是无需担心网关瓶颈,但是实际的服务器和调度服务器都需要链接在WAN交换机上,并且拥有独立的外网IP地址。这种方式的工作原理略微复杂:首先每台服务器都需要设置一个IP别名,这个IP别名是面向客户端的一个虚拟IP,只有代理服务器对这个IP别名的ARP请求做出响应,这样客户端发给这个IP的请求包首先会到代理服务器。然后代理服务器将这个请求包的目的MAC地址填写为实际服务器的MAC地址(通过某种调度算法决定目的服务器),由于目标服务器也具有这个IP别名,因此,转发过来的数据包能够被实际的服务器接收并处理。最后由于数据包的源IP地址还是客户端请求的IP地址,因此,实际的服务器将通过交换机直接将响应包转发给客户端而无需通过代理服务器。Linux下可以通过LVS-DR实现直接路由方式IP隧道IP隧道的意思是,调度器将原始的IP数据包封装在新的IP数据包中,以实现调度,实际的服务器可以将响应数据包直接转发给用户端。共享文件系统对于一些简单的提供文件下载的服务(包括html中静态资源等),自然要考虑利用集群来减压,但是如何使这些资源在集群中的主机上同步呢。NFS一种方案是让这些主机从同一个地方取数据。比如采用NFS(Network File System),基于PRC。这种方式简单易行,但是由于NFS服务器本身的磁盘吞吐率,或者并发处理能力以及带宽等问题,往往很有局限性。冗余分发另一个方案就是在主机上冗余存储资源,这样主机无需访问共享文件系统,只需读取本地磁盘上的资源即可。但是这也带来了一个同步的问题,如何同步这些数据呢:主动分发式,还分为单级分发和多级分发,分发可以借助SCP、SFTP、单级分发:通过一次分发,就达到目的,这样的方案简单易行,但是性能瓶颈会出现在磁盘压力和网络带宽,难以扩展多级分发:通过多次分发,才达到目的地,这样的方案能够分散磁盘压力和网络带宽压力,而且容易扩展,坏处是成本高被动同步式容易理解,可以使用rsync,rsync同步时是根据最后更新时间进行判定是否需要同步的条件的,因此,如果一个文件夹中有的文件数量太多的话,rsync扫描的时间就很长了,可以通过给文件夹设置最后更新时间,并合理的规划文件目录,来加快rsync的扫描时间。即使不使用rsync,自己开发同步程序也可以借助这样的思想来提升性能。分布式文件系统分布式文件系统工作在用户进程层面上,它是一个管理文件的平台,内部维护冗余,检索,追踪、调度等工作,通常包含一个物理层面的组织结构和逻辑层面的组织结构。物理层面的组织结构由分布式文件系统自行维护,逻辑层面的组织结构面向用户。其中”追踪器”起到了关键的作用。MogileFS就是一个开源分布式文件系统,用Perl编写,包含追踪器、存储节点、管理工具,它使用MySQL分布式文件系统的所有信息、使用WebDAV实现文件复制。其他著名的还有Hadoop。每个文件由一个key定义,需要读取文件时,指定一个key,追踪器会返回一个实际的路径,在访问这个地址即可获得文件。甚至可以将这个key对应的path用分布式缓存缓存起来,这样可以减少追踪器的查询开销,但这样也会失去分布式文件系统的调度策略的优越性。另外,可以利用支持reproxy的反向代理服务器(比如:Perlbal)让路径重定向的工作由反向代理服务器完成。数据库扩展1.主从复制,读写分离这种方式是指利用数据库的复制或镜像功能,同时在多台数据库上保存相同的数据,并且将读操作和写操作分开,写操作集中在一台主数据库上,读操作集中在多台从数据库上,对于读取比写更多的站点适合使用这种方式。如果不想在应用程序层面维护这种分离映射,那么可以使用数据库反向代理来自动完成对读写的分离。2.垂直分区对于不需要进行联合查询的数据表可以分散到不同的数据库服务器上,这称为垂直分区;当然每个分区自身也可以使用读写分离。3.水平分区将同一个表的记录拆分到不同的表甚至是服务器上,称为水平分区,这往往需要一个稳定的算法来保证读取时能正确从不同的服务器上取得数据,比如简单的对ID取模、范围划分、亦或者是保存映射关系。 也可以使用类似代理的产品spock。缓存构建高性能web站点时,抛开基础架构(数据库分区的问题也包括在基础架构中了),在应用程序、编码层面主要要考虑的问题就是缓存的设计,合理的缓存设计可以使提供动态网页服务的网站性能大幅度提高。当然,在架构阶段设计缓存解决方案,绝非简单的技术问题,需要从业务出发,再结合各种技术。下面按照一次}1.客户端缓存可以利用客户端浏览器的缓存机制,来减少浏览器对服务端的请求次数(当然在服务端进行图片等资源合并,并结合css图片定位技术,也可以减少的缓存协商,可以设计出灵活的客户端缓存方案。在}Last-Modified:动态页面通过主动推送该值,暗示浏览器在下次请求同一个url的时候,优先使用If-Modified-Since值与服务端进行缓存协商,如果缓存没有过期,那么服务端可以不用重新计算动态网页,通过返回304通知浏览器。网站的静态资源往往使用这种方法。但是该方法有一个缺点:有时,文件的最后更改时间虽然改了,但是内容却没有变,这样无法充分发挥浏览器缓存的能力。ETag:Web服务器为每个url生成一个散列值,增加在标记中,浏览器会优先使用If-None-Match加上这个散列值来协商缓存过期。通过对静态文件的内容进行md5变换,可以生成散列值,这样可以弥补Last-Modified的不足。但是随之带来的是服务端md5变换的计算开销。Expires:上述两种方式,虽然可以使服务端多少避免了反复的动态网页解析和计算,但浏览器还是必须通过头中添加Expires标记可以明确的告知浏览器过期形式,浏览器会彻底减少请求的次数。2.反向代理缓存在web服务器前端,还有反向代理服务器缓存。反向代理服务器本质上就是代理服务器,只是将外网的请求转发给内网的web服务器处理,他们都工作在应用层,能够理解缓存、缓存的能力,而且还具备一定程度上的安全性。一切、轻量级的varnish、甚至是Nginx这样的web服务器软件,都可以胜任反向代理服务。上述的代理服务器软件产品,通过各种配置可以缓存基于响应。3.Web服务器缓存Web服务器有可能支持基于url的缓存(基于key-value对),这类似反向代理缓存。缓存通常可以通过配置存储在内存或磁盘上,在缓存有效期的问题上,通常是基于}动态程序会可能变得依赖于特定的web服务器 注意编写面向 服务器还具有缓存文件描述符(类似句柄)的能力,这样可以减少文件的open操作,同样是一种减少系统调用的措施,这对于一些小文件有些效果,因为文件越小花在open上的开销将越来越占有重要的比例。4.应用程序缓存应用程序本身可以对动态内容进行缓存,这可以体现在三个层面:动态脚本缓存:每次脚本解析都需要消耗一定的时间,为了加快这个速度,一些服务器端脚本语言都支持动态脚本的预编译,比如我们熟悉的ASP.NET、JSP都有所谓的中间语言,解析这些中间语言会快很多。动态脚本框架支持的缓存:一些动态脚本框架支持缓存,同样在选型的时候要关注一下这些框架的缓存机制和原理,比如缓存如何存放,过期如何设置,是否支持局部缓存等。应用程序自身实现缓存:应用程序根据特定的业务需求独立设计缓存。在缓存设计的具体技术上有以下几点:缓存在内存,这种方式的优点就是减少了磁盘的读写,但是内存有限,单机不易扩展。缓存在分布式缓存,这种方式的优点是减少了磁盘读写,并提高了可靠性和扩展性,但是由于需要网络IO,性能稍逊于单机缓存。局部页面缓存,对于一些页面无法完整缓存的,可以考虑局部缓存。静态化,将网站静态化可以极大的提高性能,因为用户的请求不需要动态脚本处理。服务器系统能力的制约因素:这部分内容对于所有的服务器(无论是代理服务器、web服务器还是其他),都具有普遍适用的意义。多进程、多线程的选择和调度:进程切换和线程切换都需要一定的系统开销,通常使用多线程模型的web服务器软件比使用多进程,具备更优的性能。系统调用:一些需要从用户模式切换到内核模式的函数调用可以称为系统调用,比如:打开文件。系统调用会有一定程度上的开销,减少系统调用是可以加快处理速度的程序设计细节。TCP链接保持:可以通过保持TCP链接来减少服务端和客户端之间的创建和关闭TCP链接的操作。:Keep-Alive就有这样的功能IO模型:由于CPU的速度远远比IO快,IO延迟往往成为性能瓶颈,因此,IO模型十分重要。各种IO模型:PIO:CPU直接干预磁盘和内存的数据交互,即无论是数据从内存到磁盘还是磁盘到内存都要经过CPU寄存器。这样的模型,可想而知,CPU有很多时间都需要等待慢速设备。DMA(Direct Memory Access):CPU通过向DMA控制器发送指令来控制处理数据,数据处理完之后通知CPU,这可以很大程度上释放CPU资源。同步阻塞I/O:对于进程来说,一些系统调用为了同步IO,会不同程度上阻塞进程,比如accept、send、read等。同步非阻塞I/O:对于进程来说,一些系统调用可以在调用完之后立即返回,告知进程IO是否就绪,避免阻塞进程。多路I/O就绪通知:对于同步非阻塞I/O的方式,进程仍然需要轮询文件描述符(句柄)来得知哪些IO就绪了,而多路I/O就绪通知将这个过程改成回调通知。内存映射:将文件与内存的某块地址空间相映射,这样可以想写内存一样写文件。当然这种方式本质上跟写文件没有什么区别。直接I/O:在用户进程地址空间和磁盘中间通常都会有操作系统管辖的内核缓冲区,当写入文件时,一般是写入这个缓冲区,然后由一些延迟策略来写入磁盘。这样做可以提高写效率。但是对于诸如数据库这样的应用来说,往往希望自己管理读写缓存,避免内核缓冲区的无畏内存浪费。Linux的open函数支持O_DIRECT参数来进行直接IO。sendfile:如果web服务器想发送一个文件,将会经历如下过程:打开文件,从磁盘中读取文件内容(这通常涉及到内核缓冲区数据复制到用户进程),然后进程通过socket发送文件内容(这通常设计到用户进程数据复制到网卡内核缓冲区),可以看到重复的数据复制是可以避免的。sendfile可以支持直接从文件内核缓冲区复制到网卡内核缓冲区。