本节书摘来自华章出版社《高并发Oracle数据库系统的架构与设计》一书中的第1章,第1.1节,作者 侯松,更多章节内容可以访问云栖社区“华章计算机”公众号查看
高并发这个概念并不新鲜,可以说有数据库的地方都有可能面临高并发的问题。在数据库里,高并发问题主要集中在两个方面:读的高并发、写的高并发,两者看起来都不是很复杂,然而实际情况往往是读和写会交织在一起,并同时呈现出高并发的问题。
这个时候,相信很多读者都会提出一个观点:做读写分离嘛。是的,这是一个不错的主意,但只是一个治标不治本的主意。业务系统的耦合度很高,是不可能实现业务层级的读写分离的。在架构设计的过程中,不能驻足于技术层面,还是需要渗透到业务层面去的。不论是业务驱动技术,还是技术驱动业务,两者都是不能分离开考虑的,比较好的做法应该是,在两者之间形成一种平衡,当然这是需要架构师的分析能力和沟通能力来加以驱动的。
应用架构师:“哥们!还记得上半年让你们帮忙做的一次数据库容量测试吗?”
数据库架构师:“当然!我们可是费了很大的工夫才完成的。”
应用架构师:“当时不是说我们在现有的硬件条件下,数据库的容量足够承受当时4倍业务压力吗?可是下半年我们的业务量才增长了0.5倍,怎么就不行了呢?”
数据库架构师:“从系统资源利用率的报告来看,CPU、内存、I/O、网络上都没有太大的压力。但是,在业务高峰时段,CPU出现短暂冲高的现象。”
应用架构师:“没错!在应用端可以看到出现用户阻塞,中间件上的连接持续增加,没有得到及时释放。”
数据库架构师:“嗯,那是数据库未能及时响应造成的。CPU冲高,通过监控,我们发现很多并发的会话在争用一些资源,比如数据块、索引块、Latch和Mutex。表现出很多等待事件的冲高。”
应用架构师:“我想我们遇到高并发争用的麻烦了。”
数据库架构师:“是的。当初这套系统的设计,预期到现在这么大的业务压力了吗?”
应用架构师:“谁也不会有这种先见之明吧?当初只是一种业务的尝试而已,谁能想到市场的反应会那么好!从数据库层面来看,有什么好办法吗?毕竟现在的问题出在数据库上。”
数据库架构师:“办法是有的,针对性地一一解决掉。但是,这总归是治标不治本的办法。就像治水,现在压力我们堵住了,如果压力再大一些呢?我需要你的帮助。”
应用架构师:“你是说业务架构的变更吗?小变化没有问题,但是要像互联网公司那样大改,肯定是不行的,我们接受不了这么大的变化。”
数据库架构师:“是的,变革对我们来说,成本太大,小帆船掉头容易,航母掉头可能就要出事情了。”
应用架构师:“我们最近在开发消息队列,能一定程度上缓解用户的高并发压力。但这是以牺牲用户体验作为代价的,终归不是太好的办法。”
数据库架构师:“我想我们可以学习大禹治水,堵不上,就疏通。先将一部分业务压力分离出去,在子数据库和主数据库之间即时同步必要的数据,同时适当冗余数据到子数据库,减少数据库之间的交互。”
应用架构师:“是个好办法,我们现在不就是这么在做的吗?问题不还是在那里吗?”
数据库架构师:“我想是的。因为业务热点过于集中,在数据库上这部分业务数据耦合度又非常高,没有办法做到有效拆分。”
应用架构师:“这不奇怪,我们的业务逻辑的复杂程度不是互联网应用可以比拟的,没办法像他们那样去充分地解耦。但是,我们是否可以学习他们使用廉价MySQL数据库代替Oracle数据库,这样业务分离的成本就低了很多。”
数据库架构师:“你确定这样的成本会低吗?Oracle数据库的开发人员真的会开发MySQL吗?我们的业务逻辑是很难在MySQL数据库上实现的,现在Oracle数据库帮助我们完成了大部分的数据耦合,如果使用MySQL,这些都将要在应用端完成,开发成本将会增加。另外,Oracle有强大的优化器机制,开发者写得不算太好的SQL,它也能包容,MySQL则不然了,SQL写得不好,马上给你颜色看,因为它的优化机制不能跟Oracle相提并论。与Oracle相比,MySQL只能作为一个数据容量来看待。”
应用架构师:“你说的这些我也明白,但是我们的数据库是应该架构扩展了吧?”
数据库架构师:“当然。虽然我们不能做到充分的数据解耦,但是一点一点地解还是可以的吧。我们现在的问题是解决高并发问题,而高并发集中的那部分业务就是我们的目标。”
应用架构师:“那部分业务很难弄哦。读写比例为5∶1,写操作占比还是蛮高的,而且都交织在一起的。最大的问题是要保证较快的响应速度,否则高并发压力就会积压。”
数据库架构师:“内存数据库!将其作为Oracle数据库的前置缓存数据库来加快响应速度,如果保证了快速响应,高并发压力也就解决了。眼下Oracle和SAP都在内存数据库上大做文章呢。”
应用架构师:“他们都是在搞OLAP的内存数据库吧,我们的可是OLTP。”
数据库架构师:“Oracle的TimesTen就是为了解决OLTP的并发问题而研发的哦。关键是看我们的应用是否适应得了。”
应用架构师:“嗯,是多样化的数据库架构了。”
数据库架构师:“是的,就像一套数据库生态体系,没有必要特别待见谁,也没有必要特别排斥谁,关键是看应用的需要。不过,我们也需要反思一个问题,就是当初Oracle的设计阶段没有预见性,应该从Oracle内部设计先把握好,加强其处理并发的能力。是谓:‘先修内政而后纵横。’”
看过冗长的对话,我们来总结一下吧,问题到底出在哪里?
Oracle数据库架构设计之初,粗放设计,没有充分把握细节;
业务数据耦合度过高,无法充分解耦,革命性的变化成本太高,不能接受;
业务逻辑比较厚重,灵活性不高;
可以接受架构创新。
以上问题,相信很多架构师和数据库管理员们都会面临。更多时候,我们都是无力去推动业务的,让业务适应技术,一直都是技术人员美好的愿望,却鲜有实现。现实一点地来看,我们只能在一定程度上去引导业务,但不能完全让技术去适应业务,两者需要达到一种平衡。
立足于大多数的传统行业,来看一看应用的现状吧。业务逻辑都是经年累月沉淀下来的,要想做出革命性的变化确实很难,除非行业革命。谁能想象一下,让银行去拆分核心逻辑呢?业务看似刁难的要求,也蕴藏着行业的特点,架构师是需要充分认识到这一点的。
如图1-1所示,理想情况下的应用系统架构中的子系统应该是相对比较独立的,子系统之间关联较少,而且相互关联的子系统数量相对较少。实际情况往往是大相径庭的,子系统之间存在很高的耦合性。子系统内读写错综复杂,基本上不可能实现读写分离。面对这样的现实,出于成本和风险的考虑,很难做到子系统的解耦,理想情况也只能是理想了。
业务子系统与数据库的对应关系,如图1-2所示。在一套完整的数据库生态体系中,子系统和数据库也是无法独立开的。理想情况是若干子系统分布在一个数据库中,数据库基本上是自包含的。现实仍然是残酷的,往往是子系统和数据库出现多对多的关系。
那么,数据库架构设计就需要反映这样的业务架构,如图1-3所示。对于某一系列的业务应用来说,是不可能通过单个数据库来实现的。需要的是一个数据库群,其中包含核心库、业务应用库,以及各种功能的库,根据重要性做层级划分。数据库之间实现即时的数据同步,构成一套完整的数据库生态体系。
做到这些是不是就解决问题了呢?当然没有,如果解决了,也不会有以上那段对话。但是,这种架构的演化方向是正确的,将错综复杂的业务分为治之,如果某些业务上出现了很高的并发压力,也不会影响到其他业务的应用,还可以将影响面控制在最小范围内。
虽然本次在架构建模阶段没有充分考虑到Oracle数据库的细节问题,但是也可以作为一次经验教训,为下次的建模工作提供指导。可喜的是,我们也不必坐以待毙,架构的创新始终都是受欢迎的,因为这意味着数据库的并发处理能力的提升。
从技术层面来看待以上的问题,我们可以去做好两件事情:
Oracle数据库架构设计工作细化;
以Oracle数据库为中心,开展架构纵横扩展。
对于现在的企业级应用系统来说,数据库一般不会成为一套系统的瓶颈所在。数据库出现高并发问题往往都是热点业务集中争用造成的结果。为什么这么说呢?因为现在的数据库应用中,不论是Oracle数据库,还是MySQL数据库,抑或其他新型数据库,它们都不是一个人在战斗。
如图1-4所示,在一套比较完整的应用系统架构体系中,一般可以分为四个大层级:
应用层:直接服务于最终用户的,完成用户行为的交互。
网络层:后台处理的第一个层级,实现网络路由,并通过网络负载均衡器实现第一次负载均衡,使高并发压力第一次得到分流。
中间件层:就是通常说的B/S架构的中间服务器层,其接收网络层来的用户连接,并实现第二次负载均衡,所不一样的是,网络层是通过硬件实现负载均衡,而中间件层是通过软件实现的。同时,其按照一定的逻辑配置连接数据源。
数据路由:隶属于中间件层,是数据库层的一个前栈,实现分布式数据存储的路由。一般来说,若数据库使用分布式存储,则这个组件都是不可少的。
数据库层:这是我们最关心的,也是最底层的结构,可分为核心数据库层和前置数据库层。
核心数据库层:传统意义上的数据库群所在的区域,我们按照不同的功能应用,区分不同的数据库存储,包括核心库、子系统库、灾备库(可细分为远程灾备和本地灾备)。如果业务扩展,则可以通过ADG库和T-1交易库实现部分业务的分离,这两个概念我们会在“纵横篇”详细介绍。
前置数据库层:这个层级可以部署在核心数据库层的前端,也可以平行部署。其另一种叫法是“数据库中间层”。可以部署一些内存数据库,分离高并发业务到这个区域,也可以部署一些开源的数据库,分离边缘化的应用于其中。
可以看到,一个完整的架构远比我们想象得要复杂,云的概念也是基于这个架构逐渐衍生出来的。就拿数据库层来说吧,我们平滑地实现数据存储的横向和纵向的扩展,并对上一层级是透明的,那么我们就实现了数据库的池化,也就是说对外服务的数据库可以视为一个,基本上实现了数据库云架构。
从以上架构来看,高并发的压力经过了网络层和中间件层的过滤,到达最底层的数据库层,基本上都不会有压力了,应用层、网络层、中间件层都可以视为数据库的保护层。当我们进行应用系统压力测试的时候,绝大多数情况下,数据库都是没有太大压力的,最容易出现问题的往往是中间件层,换而言之,在数据库被压垮之前中间件层已经被压垮了。这也提醒我们只做系统应用压力测试是不够的,我们还需要做数据库的压力测试,找到数据库层的瓶颈所在。
这样是不是可以就此高枕无忧了呢?当然不能,数据库出现高并发压力在实际应用中还是比较常见的。难道我们前面说的不对?不是的,可以看到不论是网络层,还是中间件层,都是在分流压力,压力并没有凭空消失,这些用户会话要访问的数据分布是无法控制的,如果分布过于集中,那么数据库会在某一个点上出现高并发争用,也就是热点争用,如上述谈话的背景一样。
面对高并发压力,我们现在已经很清楚自己要做什么了吧?就是一定程度上实现数据访问的分流工作,也就是通常所说的纵横扩展。另一方面来看,任何的扩展都是有一个核心点的,就是我们的Oracle数据库,扩展工作在一定程度上是对其核心地位的弱化,但是核心仍然是核心,在扩展之前,必须做好Oracle核心库的设计。