数据库系统中的几种架构及处理方式
来具体说说数据库集群吧
集群主要分成三大类 (高可用集群, 负载均衡集群,科学计算集群)
高可用集群( HighCluster)
负载均衡集群(Load Balance Cluster)
科学计算集群(High Performance Computing Cluster)
1、高可用集群(HighCluster)
常见的就是2个节点做成的HA集群,有很多通俗的不科学的名称,比如”双机热备”, “双机互备”, “双机”。高可用集群解决的是保障用户的应用程序持续对外提供服务的能力。 (请注意高可用集群既不是用来保护业务数据的,保护的是用户的业务程序对外不间断提供服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程度)。
2、负载均衡集群(Load Balance Cluster)
负载均衡系统:集群中所有的节点都处于活动状态,它们分摊系统的工作负载。一般Web服务器集群、数据库集群和应用服务器集群都属于这种类型。
负载均衡集群一般用于相应网络请求的网页服务器,数据库服务器。这种集群可以在接到请求时,检查接受请求较少,不繁忙的服务器,并把请求转到这些服务器上。从检查其他服务器状态这一点上看,负载均衡和容错集群很接近,不同之处是数量上更多。
3、科学计算集群(High Performance Computing Cluster)
高性能计算(High Perfermance Computing)集群,简称HPC集群。这类集群致力于提供单个计算机所不能提供的强大的计算能力。
高性能计算分类:
31、高吞吐计算(High-throughput Computing)
有一类高性能计算,可以把它分成若干可以并行的子任务,而且各个子任务彼此间没有什么关联。象在家搜寻外星人( SETI@HOME _ Search forat Home )就是这一类型应用。
这一项目是利用Internet上的闲置的计算资源来搜寻外星人。SETI项目的服务器将一组数据和数据模式发给Internet上参加SETI的计算节点,计算节点在给定的数据上用给定的模式进行搜索,然后将搜索的结果发给服务器。服务器负责将从各个计算节点返回的数据汇集成完整的 数据。因为这种类型应用的一个共同特征是在海量数据上搜索某些模式,所以把这类计算称为高吞吐计算。
所谓的Internet计算都属于这一类。按照 Flynn的分类,高吞吐计算属于SIMD(Single Instruction/Multiple Data)的范畴。
32、分布计算(Distributed Computing)
另一类计算刚好和高吞吐计算相反,它们虽然可以给分成若干并行的子任务,但是子任务间联系很紧密,需要大量的数据交换。按照Flynn的分类,分布式的高性能计算属于MIMD(Multiple Instruction/Multiple Data)的范畴。
下面说说这几种集群的应用场景:
高可用集群这里不多作说明。
想Dubbo是比较偏向于负载均衡集群,用过的猿友应该知道(不知道的可以自行了解一下),Dubbo同一个服务是可以有多个提供者的,当一个消费者过来,它要消费那个提供者,这里是有负载均衡机制在里面的。
搜索引擎比较偏向于科学计算集群的分布计算。
而到这里,可能不少猿友都知道,集群的一些术语:集群容错、负载均衡。
我们以Dubbo为例:
集群容错(bboio/UserGuide-zhhtm#UserGuide-zh-%E9%9B%86%E7%BE%A4%E5%AE%B9%E9%94%99)
Dubbo提供了这些容错策略:
集群容错模式:
可以自行扩展集群容错策略,参见:集群扩展
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。(缺省)
通常用于读操作,但重试会带来更长延迟。
可通过retries="2"来设置重试次数(不含第一次)。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。
通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。
通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。
通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。
通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
可通过forks="2"来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。(210开始支持)
通常用于通知所有提供者更新缓存或日志等本地资源信息。
负载均衡(bboio/UserGuide-zhhtm#UserGuide-zh-%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1)
Dubbo提供了这些负载均衡策略:
Random LoadBalance
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
LoadBalance
一致性Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
算法参见:enwikipediaorg/wiki/Consistent_hashing。
缺省只对第一个参数Hash,如果要修改,请配置
缺省用160份虚拟节点,如果要修改,请配置
Dubbo是 Alibaba 开源的分布式服务框架远程调用框架,在网络间传输数据,就需要通信协议和序列化。
Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的,默认也是用的dubbo协议。
先介绍几种常见的协议:
缺省协议,使用基于mina117+hessian321的tbremoting交互。
连接个数:单连接
连接方式:长连接
传输协议:TCP
传输方式:NIO异步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用
1、dubbo默认采用dubbo协议,dubbo协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况
2、他不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
配置如下:
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name=“dubbo” port=“9090” server=“netty” client=“netty” codec=“dubbo”
serialization=“hessian2” charset=“UTF-8” threadpool=“fixed” threads=“100” queues=“0” iothreads=“9”
buffer=“8192” accepts=“1000” payload=“8388608” />
3、Dubbo协议缺省每服务每提供者每消费者使用单一长连接,如果数据量较大,可以使用多个连接。
<dubbo:protocol name="dubbo" connections="2" />
4、为防止被大量连接撑挂,可在服务提供方限制大接收连接数,以实现服务提供方自我保护
<dubbo:protocol name="dubbo" accepts="1000" />
Java标准的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:TCP
传输方式:同步传输
序列化:Java标准二进制序列化
适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。
适用场景:常规远程服务方法调用,与原生RMI服务互操作
RMI协议采用JDK标准的javarmi实现,采用阻塞式短连接和JDK标准序列化方式 。
基于Hessian的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:表单序列化
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。
1、Hessian协议用于集成Hessian的服务,Hessian底层采用Http通讯,采用Servlet暴露服务,Dubbo缺省内嵌Jetty作为服务器实现。
2、Hessian是Caucho开源的一个RPC框架: http://hessiancauchocom ,其通讯效率高于WebService和Java自带的序列化。
基于http表单的远程调用协议。参见:[HTTP协议使用说明]
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:表单序列化
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。
基于WebService的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:SOAP文本序列化
适用场景:系统集成,跨语言调用
序列化是将一个对象变成一个二进制流就是序列化, 反序列化是将二进制流转换成对象
为什么要序列化?
Dubbo序列化支持java、compactedjava、nativejava、fastjson、dubbo、fst、hessian2、kryo,其中默认hessian2。其中java、compactedjava、nativejava属于原生java的序列化。
hessian2序列化:hessian是一种跨语言的高效二进制序列化方式。但这里实际不是原生的hessian2序列化,而是阿里修改过的,它是dubbo RPC默认启用的序列化方式。
json序列化:目前有两种实现,一种是采用的阿里的fastjson库,另一种是采用dubbo中自己实现的简单json库,但其实现都不是特别成熟,而且json这种文本序列化性能一般不如上面两种二进制序列化。
java序列化:主要是采用JDK自带的Java序列化实现,性能很不理想。
他俩其实没什么大区别,只不过dubbo可以和Spring框架无缝集成。
1、Web service是一种服务导向架构的技术,通过标准的Web协议提供服务,目的是保证不同平台的应用服务可以互操作。根据W3C的定义,Web服务(Web service)应当是一个软件系统,用以支持网络间不同机器的互动操作。
网络服务通常是许多应用程序接口(API)所组成的,它们透过网络,例如Internet的远程服务器端,执行客户所提交服务的请求。无论定义还是实现,WEB服务过程中会由服务器提供一个机器可读的描述以辨识服务器所提供的WEB服务。
另外,虽然WSDL不是SOAP服务端点的必要条件,但目前基于Java的主流WEB服务开发框架往往需要WSDL实现客户端的源代码生成。一些工业标准化组织就在WEB服务定义中强制包含SOAP和WSDL。
2、Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC 实现服务的输 出和输入功能,可以和 Spring框架无缝集成。
程序员们都希望能通过自己的努力学习,技术提升,拿到更好的收入,技术提升和高收入虽然不是轻易就能实现的,但总是有章可循。
一个成熟的大型网站(如淘宝、京东等)的系统架构并不是开始设计就具备完整的高性能、高可用、安全等特性,它总是随着用户量的增加,业务功能的扩展逐渐演变完善的,在这个过程中,开发模式、技术架构、设计思想也发生了很大的变化,就连技术人员也从几个人发展到一个部门甚至一条产品线。所以成熟的系统架构是随业务扩展而完善出来的,并不是一蹴而就;不同业务特征的系统,会有各自的侧重点,例如淘宝,要解决海量的商品信息的搜索、下单、支付,例如腾讯,要解决数亿的用户实时消息传输,百度它要处理海量的搜索请求,他们都有各自的业务特性,系统架构也有所不同。尽管如此我们也可以从这些不同的网站背景下,找出其中共用的技术,这些技术和手段可以广泛运行在大型网站系统的架构中,下面就通过介绍大型网站系统的演化过程,来认识这些技术和手段。
一、最开始的网站架构
最初的架构,应用程序、数据库、文件都部署在一台服务器上,如图:
二、应用、数据、文件分离
随着业务的扩展,一台服务器已经不能满足性能需求,故将应用程序、数据库、文件各自部署在独立的服务器上,并且根据服务器的用途配置不同的硬件,达到最佳的性能效果。
三、利用缓存改善网站性能
在硬件优化性能的同时,同时也通过软件进行性能优化,在大部分的网站系统中,都会利用缓存技术改善系统的性能,使用缓存主要源于热点数据的存在,大部分网站访问都遵循28原则(即80%的访问请求,最终落在20%的数据上),所以我们可以对热点数据进行缓存,减少这些数据的访问路径,提高用户体验。
缓存实现常见的方式是本地缓存、分布式缓存。当然还有CDN、反向代理等,这个后面再讲。本地缓存,顾名思义是将数据缓存在应用服务器本地,可以存在内存中,也可以存在文件,OSCache就是常用的本地缓存组件。本地缓存的特点是速度快,但因为本地空间有限所以缓存数据量也有限。分布式缓存的特点是,可以缓存海量的数据,并且扩展非常容易,在门户类网站中常常被使用,速度按理没有本地缓存快,常用的分布式缓存是Memcached、Redis。
四、使用集群改善应用服务器性能
应用服务器作为网站的入口,会承担大量的请求,我们往往通过应用服务器集群来分担请求数。应用服务器前面部署负载均衡服务器调度用户请求,根据分发策略将请求分发到多个应用服务器节点。
常用的负载均衡技术硬件的有F5,价格比较贵,软件的有LVS、Nginx、HAProxy。LVS是四层负载均衡,根据目标地址和端口选择内部服务器,Nginx是七层负载均衡和HAProxy支持四层、七层负载均衡,可以根据报文内容选择内部服务器,因此LVS分发路径优于Nginx和HAProxy,性能要高些,而Nginx和HAProxy则更具配置性,如可以用来做动静分离(根据请求报文特征,选择静态资源服务器还是应用服务器)。
五、数据库读写分离和分库分表
随着用户量的增加,数据库成为最大的瓶颈,改善数据库性能常用的手段是进行读写分离以及分表,读写分离顾名思义就是将数据库分为读库和写库,通过主备功能实现数据同步。分库分表则分为水平切分和垂直切分,水平切换则是对一个数据库特大的表进行拆分,例如用户表。垂直切分则是根据业务不同来切换,如用户业务、商品业务相关的表放在不同的数据库中。
六、使用CDN和反向代理提高网站性能
假如我们的服务器都部署在成都的机房,对于四川的用户来说访问是较快的,而对于北京的用户访问是较慢的,这是由于四川和北京分别属于电信和联通的不同发达地区,北京用户访问需要通过互联路由器经过较长的路径才能访问到成都的服务器,返回路径也一样,所以数据传输时间比较长。对于这种情况,常常使用CDN解决,CDN将数据内容缓存到运营商的机房,用户访问时先从最近的运营商获取数据,这样大大减少了网络访问的路径。比较专业的CDN运营商有蓝汛、网宿。
而反向代理,则是部署在网站的机房,当用户请求达到时首先访问反向代理服务器,反向代理服务器将缓存的数据返回给用户,如果没有没有缓存数据才会继续走应用服务器获取,也减少了获取数据的成本。反向代理有Squid,Nginx。
七、使用分布式文件系统
用户一天天增加,业务量越来越大,产生的文件越来越多,单台的文件服务器已经不能满足需求。需要分布式的文件系统支撑。常用的分布式文件系统有NFS。
八、使用NoSql和搜索引擎
对于海量数据的查询,我们使用nosql数据库加上搜索引擎可以达到更好的性能。并不是所有的数据都要放在关系型数据中。常用的NOSQL有mongodb和redis,搜索引擎有lucene。
九、将应用服务器进行业务拆分
随着业务进一步扩展,应用程序变得非常臃肿,这时我们需要将应用程序进行业务拆分,如百度分为新闻、网页、等业务。每个业务应用负责相对独立的业务运作。业务之间通过消息进行通信或者同享数据库来实现。
十、搭建分布式服务
这时我们发现各个业务应用都会使用到一些基本的业务服务,例如用户服务、订单服务、支付服务、安全服务,这些服务是支撑各业务应用的基本要素。我们将这些服务抽取出来利用分部式服务框架搭建分布式服务。淘宝的Dubbo是一个不错的选择。
大型网站的架构是根据业务需求不断完善的,根据不同的业务特征会做特定的设计和考虑,本文只是讲述一个常规大型网站会涉及的一些技术和手段。
如果你还有这些疑问,成熟的网站架构师需要学什么核心技能?Java程序员如何晋升为互联网架构师?Java语言在架构搭建中扮演什么角色?怎样成为年收入几十万的架构师?欢迎来电来访昌平北大青鸟java培训。
在前面的一篇中分析了Dubbo是如何降级的,除了降级,有时限流也是一种很有效的解决高并发的性能问题,那在本篇中开始分析Dubbo是如何限流的。我们知道限流主要是通过控制连接数来实现的,防止某一片段内请求处理过大,导致重要服务的失效。
服务端连接控制
限制当前提供者在使用dubbo协议最多接受10个消费者链接
或者
并发控制
限制 comfooBarService 的每个方法,服务端并发执行(或占用线程池线程数)不能超过10个:
限制 comfooBarService 的 sayHello 方法,服务器并发执行(或占用线程池线程数)不能超过10个。
actives限流
该限流方式与前两种不同,其可以设置在提供端,也可以设置在消费者端。可以设置为接口级别,也可以设置为方法级别。
根据消费者与提供者建立的连接类型,其意义也不同。
长连接 : 表示当前的长连接最多可以处理的请求个数。与长连接的数量没有问题。
短连接 :表示当前服务可以同时处理的短连接数量。
类级别
方法级别
connections限流
可以设置在提供端,也可以设置在消费者端。限定连接的个数。对于短连接,和actives相同。但对于长连接,表示长连接的个数。
一般情况下,会使connections与actives联用,让connections限制长连接的个数,让actives限制长连接中可以处理的请求个数。
限制客户端服务使用连接不能超过10个
或
如果 <dubbo:service> 和 <dubbo:reference> 都配置了connections, <dubbo:reference> 优先。
延迟连接
延迟连接仅可以设置在消费者端,并且不能设置为方法级别。仅作用于Dubbo服务暴露协议。将长连接的建立推迟到消费者真正调用提供者时。 可以减少长连接的数量。
我们已经讲解了如何设置控制链接数的,那么它们底层是如何实现的呢?
实际上上面的逻辑都是一个个Filter,所有的Filter会连接成一个过滤器链,每次请求都会经过整个链路中的每一个Filter。那它是在什么时候构造成一个过滤器链的呢。
在服务暴露的时候会调用 buildInvokerChain , 将真正执行的 invoker 放到过滤链的尾部,再执行 protocolexpert(buildInvokerChain(invoker, )) 方法来进行服务暴露。
在服务引用的时候会调用 protocolrefer() 方法先生成 Invoker ,再调用 buildInvokerChain(protocolrefer(type, url), ) 来生成消费类型的调用链。
ExecuteLimitFilter
它用于限制每个服务中每个方法的最大并发数,有接口级别和方法级别的配置方式。
其基本原理:在框架中使用一个ConcurrentMap缓存了并发数的计数器,为每个请求URL生成一个IdentityString,并以此为key;再将每个IdentityString生成一个RpcStatus对象,将此作为value。RpcStatus对象用于记录对应的并发数。在调用开始之前,会通过URL获得RpcStatus对象,把对象中的并发数计数器原子+1,在finally中再将原子减1。只要在计数器+1的时候,发现当前计数器比设置的并发数大时,就会抛出异常。
TpsLimitFilter
TpsLimitFilter的限流是基于令牌的,即一段时间内只分配N个令牌,每次请求都会消耗一个令牌,耗完为止,后面再来的请求都会被拒绝。
具体的逻辑是在 DefaultTPSLimiter#isAllowable ,会用这个方法判断是否触发限流。
在DefaultTPSLimiter内部用一个ConcurrentHashMap缓存每个接口的令牌数,key是interface+group+version,value是一个StatItem对象,它包装了令牌刷新时间间隔、每次发放的令牌数等。首先判断当前时间减去上次发放令牌的时间是否超过了时间间隔,超过了就重新发放令牌,之前剩余的令牌会被直接覆盖掉。然后,通过CAS的方式减去1令牌,减掉后小于0就会触发限流。
ActiveLimitFilter
和服务提供者的 ExecuteLimitFilter 相似,它是消费者端的过滤器,限制的是客户端的并发量。
但是它与 ExecuteLimitFilter 有所不同,它不会直接抛出异常。而是当到达阈值的时候,会先加锁抢占当前接口的RpcStatus对象,然后通过wait方法进行等待,等待是有时间的,因为请求是有 timeout 属性的。然后如果某个Invoker在调用结束后,并发把计数器减-1并触发一个notify,此时会有一个在wait状态的线程被唤醒并继续执行,判断现在是否超时,如果超时则抛出异常。如果当前并发数仍然超出阈值,则继续执行wait方法;如果没有超出阈值在,则跳出循环,CAS+1,并调用invoke方法,调用结束后CAS-1,最后通过notify唤醒另外一个线程。
参考文章:
Dubbo之限流TpsLimitFilter源码分析
Dubbo服务限流
Dubbo源码分析----过滤器之ActiveLimitFilter
1、查看当前hostname
hostname
2、修改/etc/hosts文件
vim /etc/hosts
将hostname对应的ip地址改为外网地址
3、重启jar包即可
注修改/etc/hosts文件 记得将localhost新增为127001 本地ip地址,防止tomcat启动不起来(orgapachecatalinacoreStandardServerawait 无法在地址[localhost]和端口[8005]上创建服务器关闭套接字(基本端口[8005]和偏移量[0])javanetBindException: 无法指定被请求的地址 (Bind failed))
0条评论