系统架构-基础篇-(高性能基础建设说明与选型条件)

本文牵扯的面积可能会比较泛,或者说比较大,在这个层面很多人也有自己的见解,所以我这也仅仅是抛砖引玉,结合前面讲述的一些基础技术,从思想中阐述更为深入的架构思想基础,因为最好的架构思想是架构师结合实际情况思考出来最适合的架构,这里仅仅说明下一些常用的原理和思想,主要包含的内容有(内容很泛,所以都是简单阐述入门知识,具体后续深入探讨):

1、app切分集群组扩展

2、app集群组负载均衡

3、Memcached原理

4、db cache应用

5、db存储类型以及存储cache说明

6、存储条带思想

7、数据库集群

8、数据库分布式存储

9、数据库容灾备份以及监控

10、nosql思想

11、无锁分析

1、app切分集群组扩展

应用系统架构随着外部并发量的增加,必然导致的是app应用的压力逐渐增加,并且绝大部分app对于线程的分配能力都是有限的,但是app应用在扩展上是非常容易的,最基础的就是一种应用的垂直切割,其次是水平切割。

在了解app切割原理的基础上先来了解一个其他的概念就是,就是Internate的路由器如何路由你请求的一个URL,你发送的URL并不知道路由器发送到哪里去了,最终路由到远端的服务器(互联网本身就是一个云计算为基础的平台),到了远程后,它如何找到自己的应用呢,以及应用下具体的服务内容呢?就是通过URL后面部分的标识符号。也就是在云的最终技术也是各自管理各自的内容,而云之所谓称之为云是因为你无须关心你发送的URL是如何路由到远端的服务器的,又是如何通过哪些路由器返回回来的。这里不深入讨论云的概念,回到主题上是说远端的服务器每一个目标都有自己处理的对象,或者说不同的路径下或者不同的端口下都会有自己的处理服务。所以app系统切割的基本思想就是路径。

当一个系统业务十分复杂,应用并发量很大的情况下,必然导致的一个步骤就是业务分解,将一个大的系统拆分为多个小系统,不论是软件本身设计的可扩展性还是软件性能扩展性都会有很大的帮助,比如在各个子系统之间他们的业务的复杂性以及并发量都会有很大的区别,我们可以将这些小系统拆分到不同的集群节点上去,这些集群节点可以是由同一个主机发布出来的不同端口或者URL,或者是不同的主机发布出来的内容,并且三者可以根据实际情况调整使得成本、软件扩展性、性能扩展性达到较好的程度,总之将一个大系统拆分为多个小系统是第一个需要做的,也就是app应用拆分,这种并不难,但是拆分的依据一定要把控好,而且还有一个总体架构,不然软件最终会做的五花八门;在很多的应用下都会使用,只是在这种拆分,拆分后除上述的总体设计要做好外,还需要主意的一点就是系统通信问题,子系统拆分后应该是高内聚的,但是免不了需呀通信,否则就根本不算是一个系统的,而且即使不是同一个系统也有可能因为服务需求而需要去通信,所以在通信上需要多下功夫,在不同服务器以及语言之间通信最麻烦的事情就是字符集,也是需要主意的,不过不是本文的重点。

在上面拆分完成后,当某一个子系统的并发量非常大的时候,我就需要单独对某一个子系统进行拆分了,这种没的选,一般不太可能通过URL来控制(除非申请不同的VIP或者在同一个主机上用不同的虚拟目录来做,不过是不是有点挫),这种一般是通过在不同的服务端口(也称为运行节点,在同一个主机上多个节点肯定是不同的端口的),或者发布到不同的主机上来完成;这部分拆分app应用不会受到太大的限制;这个地方需要主意的是,当你在app内部做静态内存时,就无法做到当一个机器的内存修改后同时修改到其他内存中,除非你自己写程序要么定时刷新要么相互之间传送数据,但是这两种都会付出巨大的成本,如何解决呢,我们后面会说到的Memcached就是解决的方法。

上述两者完成后,新的问题出现了,就是子系统之间的通信,他们不再是单机对单机的通信,而是集群组对集群组的通信,所以子系统中间件必然有一些非一对一的通信机制就出现了,以及中途产生的同步通信和异步通信等机制,如IBM MQ、EJB、Webservice、HttpClient、HttpInvokie、RPC、Socket甚至于借助于数据库或者文件作为中间层等等都是通信机制的基础,应用非常特殊的公司会自己写自己的通信机制。

有了上述的集群,URL可以通过网络路由到具体的服务器,但是服务器下每一个集群节点不可能都去申请一个URL吧,而且客户也不会自己知道我第一次用URL1,下一次用URL2、再下一次用URL3来给你服务器做负载均衡吧,客户只知道用一个URL访问你,而且那么多的IP在互联网上也会占用非常大的资源,所以很多时候,一个大网站后台可能数万的主机,前端暴露的IP可能只有几个,这个可以成为VIP,他们之间有一个绑定关系,由这个VIP来负责域名的帮顶,而VIP一般会绑定在一个负载均衡器上面,由负载均衡器根据实际请求内容负载到具体的主机上面去,下面第二章就是我们要写的负载均衡基本原理。

2、app集群组负载均衡

所谓负载均衡就是负载均衡了,呵呵,也就是不让某太机器单独忙,也不让某台机器太闲,将请求进行分发,这就是负载均衡器设计的初衷了。

随着发展的变化,负载均衡器需要承担更大的作用

第一个需要做的就是请求解析,也就是很多不同的应可能由一个负载均衡器来完成;

进一步,同一个应用发布的不同的节点或者不同的端口,负载均衡器可以识别出来并达到分发负载,将并发负载到很多不同的节点上去运行;

再进一步,某个客户端请求第一次访问了某个节点后,当session未失效时,应当做到继续访问同一台主机,这样保证客户在多次交互中session内容是一致的,至少不会导致重新登陆等现象;

再进一步,在节点失败是,负载均衡器应当识别出来,并可以将访问切换到其他主机,在有必要的情况下需要做session复制。

负载均衡最基本的需要做到以上几点内容才算负载均衡。

负载均衡器一般需要的内容是全局的,但是它并不关注与细节,所以它主要做的事情是全局资源定位,监控,负载均衡,切换动作;一般会有一个单独的管理节点和单独的分发节点,但是每一门负载均衡的机制在设计层面都会有很大的区别,所以无需一概而论。

因为负载均衡器在所有应用的最前端,所以我们非常关注于它的性能,有很多基于高级语言编写的负载均衡器,甚至于你可以直接通过你的JSP、ASP、PHP等等做一个简单的控制跳转上的负载均衡,但是他们的性能就很低了,扩展性受到明显的限制,Linux内核才是负载均衡器的王道,终极方案,要深入研究和负载均衡的方案,请大家多多参详Linux内核。

目前市面上非常常用的负载均衡器是apache,它本身也可以作为WEB服务器来应用(它的一些模块就可以直接用于php),另外weblogic自带的proxy+domain+managed模式也是一种负载均衡方法,不过我做过几个版本效果不理想,主要原因还是主要是因为实现的基础是高级语言吧;而apache虽然性能不错,而且大家广受喜爱的一种东西,不过随着互联网并发量的上升,apache在很多极为高并发的系统中仍然受到扩展性的限制,于是乎ngnix出现了,它是目前高并发网站应用中最广泛或者说在大网站中用得最多的负载均衡器,国内的大网站基本都有它的影子,它是俄罗斯一位工程师编写,而且是免费的,性能极高,占用资源极少,并且支持cache以及代理,很多客户端访问的机制都可以配置化,安装和使用都非常简单(要深入研究就没那么简单),而且故障率非常低,为什么那么好,因为它的基础就是unux内核,没有别的,当然写代码一定要写得很好才行;当然国内并非没有这样的人才存在,而且要看公司是否给这类人才一个机会去完成这样一个东西,因为自己写的可能会更加适合于自己,其实国内也有很多对Unix内核研究很深入的顶尖高手。

3、Memcached原理

这一章本身就想在数据库后面说明的,不过由于只是简单介绍,而且后面应该几乎都是技术,所以就这这里说明了。

一般应用程序除了处理业务逻辑和一定的计算后,就是访问数据库,做数据库的存、取、事务操作,在OLAP会有更多的是在数据库端的计算,OLAP不是本文的重点,因为OLAP不会涉及并发量的问题,所以更多偏重于OLTP,而且是极高并发的系统。

当前端app并发达到一定程度,即将考虑的问题就是数据库的压力,数据库面对的更多的数据,虽然它在各方面做了非常大的优化,不过它毕竟是存大量锁机制和磁盘读写操作,来保证数据一致性和安全性,而这两者往往是影响性能的关键指标,但是我们很多时候又不得不用数据库,因为他可以提供给我们的东西实在是太多了。

在互联网应用中有个几乎所有网站都会拥有的一个共同特征那就是读取次数非常多,而写的次数相对比例较少(并不代表没有写操作),此时人们在设计上第一个想法是让数据库来完成主备或者镜像方式上的读写分离,不过始终会与数据库交互,而且扩展上会受到非常大的限制,在极高并发下,人们又对应用做了对页面输出html的方式,但是最终发现在实施过程中会受到很多限制(尤其是ajax交互),虽然有很多软件可以支持,此时很多人想到将数据载入到内存中,按照某种方式刷新内存即可,不过我们上面已经讨论,在集群下它很难做到每个被切割开的节点他们之间的静态内存是一致的,所以Memcached出现了。

Memcached我看网上写它是分布式的,这个大家最好不要乱理解,因为从基本的设计上讲,它只是将app和静态内存分开了,而并非真正意义上做到分布式(真正意义上的分布式应当自动将多个Memcached节点的访问如同访问一个节点一样简单),而一般Memcached的访问方式还是通过程序去控制的,而多个不同节点划分,也是通过人为的完成的,你可以认为你访问的Memcached是数据库一样的东西,因为它的访问方式类似于数据库,但是它如果命中肯定比访问数据库要快很多,而且可以大量减少读的压力,因为一个大网站百分之八九十以上的压力来源于读;一个好的Memcached设计会使得读命中率达到95%以上,而其成本只需要大内存,并具有极大的扩展性;根据实际系统的场景讲Memcached划分数据的方法指定,当命中是获取,当修改时先修改数据库,然后让对应的cached失效即可;主意解决如果它挂掉会产生什么问题,它的基础原理是一种Key-Value方式,但是通用的东西往往不是性能最佳的东西,所以你在有必要的情况下可以适当做下修改,淘宝网的tair开源技术就是一套自己完成的分布式缓存技术,也是很不错的选择。

4、db cache应用

上述已经描述到数据库访问会有大量的磁盘操作,这里我们说下oracle是如何缓解这些问题的,以至于它一直在数据库领域处于行业界得老大哥形象出现。

它首先由一个SGA的全局区域,内部的其他区域已经在前面的文章中说明,中间对于数据层面,最重要的就是databuffer了,这个databuffer是采用基于LRU算法为基础的方式来完成的所以只要有足够大的内存,在读远大于写的情况下命中率也会非常高(其实oracle做写操作也是写内存的,即使你commit命令oracle也不会做磁盘写,但是它会写日志,当达到一定并发量日志写也是不可估量的,而且脏块列表也会非常频繁的被刷新到磁盘上,也很容易出现瓶颈),data buffer这也是db cache最为核心的部分,当然还有些其他区域也有一定的cache思想。

一般来说,对于极为高并发的系统,数据库的cached逐渐受到限制,虽然oracle rac可以非常高效的扩展,但是其限制最多是64节点的整列结构,而且在这个过程中并非没有锁,尤其是在集群下的全局锁机制,这个开销也是很大的,但是我们很多时候访问很多数据并非需要锁,也就是这些数据是在这段时间内我们确定不会被修改或者说根本不会被修改甚至于说修改了一个简单脏数据的延迟读也是无所谓的,这类数据我们没有必要让他来和其他需要做绝对一致性的事情套在一起,该做事务的被阻塞了,可以间接做事务的也被阻塞了,所以在更多的层面我们希望的是app端做好cache,才是更好的方案,通常app的性能会占用整个系统性能指标的50%以上,而有20%在于数据库端,另外还有设计方案、存储等等其他的,以及SQL了。

在app设计cached后,数据库更多的是做修改,读显得更加少,所以在app设计cached后,数据库端的内存可以保留,也可以节约一些出来也可以。

5、db存储类型以及存储cache说明

存储就是指最终数据存放的位置,有些地方也叫做整列(因为很多时候它是多个磁盘通过RAID完成的),存储一般会有低端存储、中端存储、高端存储。

存储设备中最挫的就是本地硬盘了,一般都可以不认为他是独立的存储设备;但是最终你会发现它在是最好的,呵呵,在分布式的架构上,我们更加愿意选择廉价的成本设备,并自己架构主机来完成使得性能达到更高的程度;比如在一种顺序写非常多、随机读非常多的场景下,我们就更加愿意选择SSD硬盘来做存储,因为它的总体设计就非常适合这种情况。

低端存储一般只有一个控制器,坏掉全部坏掉,没有任何存储cached,存磁盘操作。

中端存储一般有2个控制器,可以做均衡负载,而且可以冗余保护,坏掉一个性能会降低50%,并且有一定的cache设备,有些时候也会分读cache和写cache,IBM DS 8000属于一种中端存储,不过它自称是高端存储设备,外部一般说他是伪高端设备。

高端存储,多个控制器相互冗余,坏掉一两个性能影响较小,具体影响要看存储成本和具体需求;EMC高端存储就是非常流行的选择,DMX3中还有一种读cache镜像和写cache镜像,在某些应用下性能更加提升;不过高端存储的成本极高,在必要的环境下才会使用,绝大部分企业会使用中端存储设备。

存储成本并非和性能或者说高可用性完全成正比,尤其是本身高可用性很好的情况下;所以在选择存储的时候再考虑当前应用下需要考虑的就是成本,主要是:数据存储容量、电费、网路带宽;以及一个存储在多少年后报废等一起计算。

存储的基本考量标准也是系统性能重点指标:IOPS、QPS、TPS、带宽容量、单个请求响应时间。

这些目前不做深入探讨,以后我们再说(因为涉及内容非常多,而且和磁盘管理方式有关系,如下面的条带就会对其影响),只做下简单介绍:

IOPS:磁盘阵列上每秒相应IO次数,这个IO次数不分读写,但是一般是OLTP系统中的小IO,一般用2K、4K这种来做测试(所以主意你在设计OLTP系统的数据库block时为什么要小,因为提取一条数据并不想用多次IO,而oracle提取数据的单位是block,MySQL和sqlserver是页);一般单个硬盘的IOPS会根据设计有关系,一个15k rpm 的IOPS一般是150个,但是并非绝对,可能会管理方式以及每个IO的大小有关系。

QPS和TPS是对IOPS的一个分解,其实本身没这个概念,不过可以做这个来看出一个系统的读写比例以及让系统以后如何设计来更好的工作。这两个分别代表的是每秒的查询次数、事务次数;可以通过一些内部SQL抓取等方法来实现。

IO带宽:当上述内容完成后,就需要考虑带宽了,当你的IOPS可以上去后,但是带宽上不去就悲剧了,那刚才的15k rpm来说,一般带宽是13M/s,这里单位注意是字节(B),这里假设有120块磁盘,那么也就是1560M/s,此时就需要通信上做一些支持,也就是要支持1G多的流量,需要光纤带宽8Gb(这里是网络上的大小,也就是二进制大小),那么最少使用4块2Gb的光纤卡;这种考虑基本在OLAP中比较多,而在OLTP系统中IO都是小IO,带宽按照小IO的大小乘以IOPS已经足够。

响应速度:这个因素就多了,除了上述的IOPS以及吞吐量以外,还和存储cache有关系,甚至于和锁都有关系,总之响应速度算是一个最终结果,影响因数上面每一种都会有,具体需要根据实际系统来协调,一般来说一个IO如果存磁盘操作最少需要10ms甚至于更多,而如果在cache中命中可能2ms左右就响应了,也就是从单个IO来说,cache命中比正常磁盘操作要快5倍,而平均IO一般保持在10ms是比较良好的,很多时候非cache的情况下平均IO一般会达到20ms以上

6、存储条带思想

大家不要被这个词汇所吓到,它就是RAID0的另一种说法,其实RAID有很多种,从RAID0~RAID7每一种都有自己的特征所在,而且还有组合的,企业常用的有:RAID 10、RAID5、RAID3这几种,本文不对磁盘阵列做详细阐述,而只是通过条带给带出来一些思想。

RAID0,也就是条带,它的思想源于负载均衡,和散列存储,最终在磁盘上的统一实现,并将其作为磁盘组为中心,给外部调用,而无需关心磁盘的内部细节。

它按照一定的数据顺序,将数据分布逐个分布在多个磁盘上,所以看起来就像“条带”一样,同时不论在读还是写的过程中,它都将IO负载到了不同的磁盘上,使得IO的总体性能几乎可以与磁盘数成正比,极大提高IO性能。

但是RAID0本身没有保护,也就是当磁盘坏掉,数据就丢了,找不回来,所以后来出现各种各样的RAID,根据不同的情况每一种RAID都会有自己的方式来处理,实现补充程度的冗余,还是那句话,发展到一定的冗余度将会导致成本直线上升,但是并不一定会带来收益的直线上升;RAID10就是通过50%冗余完成,也就是一对一冗余完成,同一个整列下所有的数据坏掉也可以找回来,除非两块磁盘是相互冗余的磁盘同时坏掉;而RAID5属于从RAID3、RAID4做一些算法改进和性能提升上来的,其原理都是奇、偶校验码原则,数据分布式按照条带思想,冗余N+1块磁盘,数据随机存放在N块磁盘上,剩余一块做校验位,相对减少磁头同步粒度,其中任意一块磁盘坏掉,均可恢复,但同一个RAID5阵列同时坏掉2块不行。

顺便提及下,ORACLE个只疯狗什么东西都想独霸,他的ASM就是拿出来和RAID竞争的,它的管理可以基于裸机,更加优于基于操作系统层的调用,而在裸设备的管理上又会有很多新的讲究。

7、数据库集群

数据库集群上,最初是通过一种操作系统机制HA完成,但是它在数据库层面存在很多缺陷,相对管理数据库来说还存在很多专业上的个性化,所以ORACLE在10g推出了ORACLE RAC(其实是9i,但是9i的集群做得很烂,所以可以认为是10g才有的);另外10g之前的集群需要第三方的cluster软件完成,10g后就有了oracle自己的CRS软件,并且是免费的,可以到官方下载。

数据库集群除正常的app拥有的(load banlance)负载均衡、(failover)失败切换,还有很多机制在内,包含主从关系、切换机制、以及分布式计算(网格计算(Grid)在ORACLE RAC中是一种最简单的实现方法,真正的网格计算是指在实际的网格环境下去管理网格下多个应用的数据库包括集群,他们是同一的,甚至于你无须关心网格下集群组之间的关系,就能非常清晰得去做操作了),这里的网格计算是指在一些大的统计下,在配置数据库参数时,将相应的INSTANCE参数设置为集群分组,并开启并行,在做一些大操作时就会实现多实例配合完成,也是通过心跳完成的。

数据库集群的负载均衡一般是通过app端完成,这部分可能是client端的TNS配置(此时前提是通过cluster完成使用同一个service_name对应多个SID),或者类似TNS配置在链接数据库的URL中,它内部一个重要参数就是LOAD_BALANCE等等,它可以设置为:(yes、on、true是等价的,不区分大小写,即开启负载均衡),相反,设置为(no、off、false)则为取消负载均衡,此时按照配置的远程主机IP或者域名的顺序逐个访问到一个可用的即可,此时一般会导致一台机器忙一台机器闲的情况,不过另一台机器如果只是用来做备机器,当一台挂掉后切换过去也是可以的,一般用RAC我们也会将该参数开启。

failover就是将数据库的SQL切换到另一个机器上,但是事务会被回滚,具体是否切换或者如何切换要看其它参数配置,首先FAILOVER参数和上面参数的参数值一样都是那样设置,当设置为开启状态就会进行失败切换,否则这个连接池的请求就会失败;而其它几个参数一般是在开启状态下有默认值的,自己也可以设置的哦,在FAILOVER_MODE配置中很多:

首先是TYPE参数的配置中一般有:session(失败时候,所有内容被中止,已经操作的事务被回滚,创建新的session到另一个可用实例上)、select(设置为该参数和上面差不多,不过切换时,开始被操作的事务虽然被回滚,但是如果是select语句不会被中断,会继续执行),none(不做任何操作,直接回滚,也不接管,用于测试,客户端会直接报错)

其次METHOD参数,这个参数一般是有:basic(在发生失败时候再在另一个实例上创建session回话节点)、preconnect(预先设立回话节点,有一定开销,但是切换速度很快速,在主从模式下推荐)而RETRIES分别代表重试次数(默认5)、DELAY代表每次重试时间片信息(默认1秒)、BACKUP(备份节点的网路服务名)

集群RAC由于设计更加专业于数据库应用,所以他比起HA更加适用于数据库,也是众多企业的选择,它配合data guard(有些是extend rac是包含了这两种功能)来完成备份,也有oracle的一直以来的终极备份方案rman来完成,不过前者更加偏重于容灾,还有些关于复制以及迁移等功能不是本文重点,不便多提及。

ORACLE RAC和相关的东西都是烧钱的东西,价格不菲,对各项硬件要求非常高,所以注意成本预算,如高速网络以及各个INSTANCE连接共享存储阵列的SAN交换机一般需要多个来冗余,心跳的交换机也需要冗余等等。

ORACLE RAC依赖于一个共享存储,做相应INSTANCE和数据库级别的管理,这也是数据库和实例的区别了,那么它的瓶颈就在后端了,所以后端很多时候会选择高端存储来完成;另外它还有很多全局资源管理使得它的很多发展在这些瓶颈上出现问题,如它的节点一般最多支持64节点,而随着节点数量的增加,成本会直线上升,至于性能是否能直线上升呢,你应该可以考虑下当前的各种瓶颈在哪里,也需要和实际情况结合才好说。

8、数据库容灾备份以及监控

接下来一个系统设计应该如何?需要做的就是容灾以及监控运行状况是否良好,对于app端一般不需要容灾,只需要监控,而其一般是通过监控内存、CPU、磁盘使用量(主要是日志和本地缓存文件);如果监控系统做得不好,那么我想很多DBA晚上睡不着(至于夜间做生产变更这类可以通过其他的自动化程序完成),系统的发展也会受到限制,我们需要一个伸缩性很强的系统就必然会走这一步。

而数据库容灾现在又很多方案,上面已经说了,现在比较多的就是使用dataguard备份到一个或多个备份机器上,dataguard上有多种配置机制,来实现各种常用的要求,关于磁盘管理可以使用ASM来管理,数据库也可以负责制过去,也可以异步通过程序度过去,也可以通过触发器+dblink过去等等都可以实现。关键看实际需求。

数据库的监控,这个oracle也提供了系列的监控软件(Statspace、AWR、logmgr等等系列),不过很多时候我们需要更加精确的参数需要自己去编码,否则就还是需要自己去查询很多自己做报表什么的,而且很不直观;长期需要监控的除了常用的IOPS、TPS、QPS以外,还需要关心很多如latch征用、sql parser(硬解析和软解析的各方面指标)、cache命中率、锁等待、内存指标变化、CPU指标变化、索引、磁盘碎片等等都需要得到全方位的监控

数据库的管理应当自动化,首先从监控下手,完全自动化管理和资源调配方面是一个理想,不过半自动化也是很容易的,就是在有问题或者在一定情况下有某种方式的通知,如短信息吧。这样DBA就不用成天盯着监控或者后台的某个字典表一直看了。

9、CDN思想基础

后面几个章节不是本文重点,简单阐述下即可,在高可用性网站设计中,即使前端应用增加了Memcached这类东西,不过始终不能很好的效果,要达到极佳的效果,因为很多时候跨网段的开销是非常大的,经过的路由器越多开销越大;其次很多时候,不愿意因为大文件输出(如视频下载)导致应用服务器宕机的事情,这是没有必要的,因为应用服务器更多关心的应该是业务处理。

CDN的出现就是为了解决这个问题,也就是网站加速器,他需要运营商的配合(具体细节请自己查阅资料),在很多地方建立站点,它需要做的事情就是托管DNS,通常DNS是解析域名成IP并访问对应IP内容,而CDN做了一层重写,就是通过域名解析得到的是一个CNAME,它按照提供CNAME会按照最短路径找到对应的CDN网点,接受数据,客户端的数据接受更加快速,并且可以实现冗余保护,另外它只是缓存在这里,可以认为是本地的一个私服,也就是需要跨网段的流量都切换到本地了,这里做一个极端的假设,就是跨网段的开销是2,本网段拖数据是1,有100个请求时,跨网段需要200的开销,而本地网段就只需要101个开销。

大文件下载,是通过缓存到本地的私服上,如视频下载就很多时候这段时间大家看的都是热播电影,就可以通过CDN来进行网站加速。

10、nosql思想

根据上面的描述,我们很多时候就不想做到百分百的数据安全,或者一致性吧,比如做一个网站的留言板,数据有一点偏差也无所谓,而且数据库的sql parser一般是很慢的,很容易达到极限,所以nosql的诞生就出现了,现在很多开源的nosql平台,它也是现有云存储的基础,apache的Hadoop以及谷歌的mapreduce后来做了一个Percolator,还有redis、mongodb等等,其实所谓nosql基础的原理就是没有sql,就想刚才说的Memcache一样,只是它有存储以及根据设计不同,会有一些会存在一些锁机制,并且只是面向对象;有基于行存储的、有基于列存储的他们是根据实际应用场景设计的一种类似于数据库的东西,它具有极高的扩展性和伸缩性,因为控制完全在于你本身的架构和设计,也是我们一直所崇尚的:最好的东西肯定是最优秀的人根据实际的场景所架构出来的。

不论是哪一门,nosql它首先抛开的是sql parser的一种,但是它没有了SQL的支持,在一些复杂操作上显得比较困难(这些就要看具体场景和nosql的设计了);我们在结合上述几种技术的基础上如何不将Cached、nosql、RDBMS、app几个结合起来,向后端移动,实现app调用完全无需关心很多调用的细节,那么这就是真正的云存储了,因为是在分布式存储基础上以及cache管理的基础上实现了对应用的透明调用。

如何设计待以后专门有文章来阐述,今天只是一个开头而已。

11、无锁分析

通过上面的文章内容,我们在很多时候很多不必要的信息没有必要使用RDBMS一样的锁和同步等等动作,所以所谓真正意义上的无锁或者几乎无锁,就是将很多内容抽象出来利用间接的方法来实现。

一般来说降低锁的粒度有以下几种方法:

a.使用hash、range、位图对数据进行提前分布,让其分框,根据实际情况而定,如果一个框只有一个线程在处理那么就几乎可以算是无锁了。

b.在一些特殊必要的应用中,使用特殊的方法来控制,变通的方法来控制,如队列中的对头和队尾算法,如果只有一个生产者和一个消费者可以让他们在一个定长数组下跑圈圈即可,后者永远追不上前者,而多生产者多消费者模式又该如何呢?比如多个线程做push操作,那么你只需要在多个线程以当前队头下标开始位置分配到不同的下标,几个线程就可以无锁操作了,那么如何分配到不同的下标呢?用Java的volatile,你可以认为它是锁的,不过它非常轻量级的锁,只是在对使用volatile变量修改和读取过程中强制从从新内存中获取,而不是寄存器,所以在计数器使用中,多个线程去同时修改这个变量并获取到的值都是不同的;pop也是如此,这些有一定的应用场景,栈也可以用变通的手段得到解决。

c.还有一些通过版本号码、向量复制、脏块列表等等思想来实现,都有一些应用场景和方法;以及java提供的乐观锁机制(适用于非常多线程调用同一段代码,而不是循环非常多次去调用同一段代码)。

还有很多其他的知识可以借鉴,曾经看到过非常复杂的图形算法,而且是多维度的,太复杂了,所以这里就不说明了。

根据上述N多知识可以看出很多知识都是相通的,无非就是分解、根据实际情况命中与解锁,让更快的地方替换最慢的地方,让复杂的管理变得更加简单。

另一种无锁是一种变通的手段,就是单线程写操作了,也就是完全无锁的一种机制,其实你会觉得它很慢,经过测试发现,如果你的操作全是或者基本是OLTP中的小IO单个线程的写已经可以达到非常快速度,这种非常适合于写不多,但读非常多的系统,也就是读写分离,写全部在内存中完成,但是需要写日志,读是从多个散列主机上获取,但是也会从这个内存中获取相应数据,内存中为最新修改后得数据列,他们之间会在对应字段上以内存为主进行返回,这个机器只要内存足够大(现在稍微好点的PC SERVER几十G的内存非常容易),就可以承受非常大的修改,这个数据只需要在业务量较小的时候合并到静态数据中即可;那么当业务进行扩大,单线程无法承受的时候应该如何呢?内存也写不下了,那么此时又需要对其进行切割分离了,在业务和逻辑表上做一定的标识符号,类似于上述说到的volatile一样的东西,而写操作也可以类似于读操作一样的分层,这就越来越像Memcache+app+RDBMS这种结构了,只是它在Memcached有日志记录和恢复,并对于应用来说透明化了这种分布式的调用,它将整个体系向后端移动和抽象出来使得app的编程更加简单和方便,也就是app无需关心数据的具体位置在哪里,以及写到哪里去了,缓存在哪里,他们如何同步的,这就逐步可以认为是云存储和计算了,另外其精巧的设计不得不说是非常优秀的。

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2016-09-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏lonelydawn的前端猿区

大白话谈 Git

一、Git是什么? 定义 Git 的定义 是 一款免费、开源的版本控制系统。 免费不必多说;开源则是指将源代码公布,并允许公众查看、修改代码。 如果我们将项目每...

33160
来自专栏后端技术探索

纯干货--秒杀系统架构分析与实战

(1)查询商品;(2)创建订单;(3)扣减库存;(4)更新订单;(5)付款;(6)卖家发货

38440
来自专栏大魏分享(微信公众号:david-share)

Istio如何同时实现Hytrix|Ribbon|Zuul|微服务安全的功能?:为微服务引入Istio服务网格(下)

78330
来自专栏刘望舒

知乎 Android 客户端组件化实践

知乎 Android 客户端最早使用的是最常见的单工程 MVC 架构,所有业务逻辑都放在了主工程 Module 里,网络层和一些公共代码分别被抽成了一个 Mod...

51440
来自专栏hotqin888的专栏

golang语言的办公工作流的包

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

29820
来自专栏服务端技术杂谈

.Net做大型互联网项目性能差?看看StackOverflow的架构是怎么样的?

小编: 在整个web开发世界里,java,.net,PHP是三足鼎立的状况,但是相对于java和php都有优秀的大型互联网架构解决方案,.net的响应架...

34250
来自专栏ImportSource

微服务下持久化观念转变

过去当我们开发一个企业应用的时候,我们经常首先会考虑的是“我们怎么和数据库交互”?最近的一两年来,人们慢慢的开始转变了,可能要问“我应该用哪种类型的数据库?是用...

308100
来自专栏JAVA高级架构

浅谈 MySQL 集群高可用架构

新年快乐 前言 高可用架构对于互联网服务基本是标配,无论是应用服务还是数据库服务都需要做到高可用。对于一个系统而言,可能包含很多模块,比如前端应用,缓存,数据库...

398150
来自专栏一名叫大蕉的程序员

企业神奇中间件-RPC No.96

13420
来自专栏高性能服务器开发

微信、陌陌等著名IM软件设计架构详解

https://blog.csdn.net/justinjing0612/article/details/38322353

48830

扫码关注云+社区

领取腾讯云代金券