像我这样的菜鸟总是有各种各样的问题。一开始都是问JDKAPI、NIO、JVM……图片来自Pexels。工作了几年,服务的可用性,也出现了新的扩展性问题,什么问题?其实就是一个共同的话题:服务扩展的问题。服务演进的正常路径让我们从头开始。Monolithicapplication每个初创公司基本上都是从类似SSM和SSH的结构构建的。没什么可谈的。基本上每个程序员都经历过。RPC应用当业务越来越大时,我们需要对服务进行横向扩展。扩展很简单,只要服务无状态即可,如下图:当业务越来越大的时候,我们的服务关系错综复杂。,有很多服务访问是不需要连接DB的,只需要连接缓存,这样就可以分离出来,减少DB宝贵的连接。如下图所示:相信大部分公司都处于这个阶段。Dubbo就是为了解决这个问题而诞生的。分库分表如果你公司的产品很火爆,业务持续高速发展,数据越来越多,SQL操作越来越慢,那么数据库就会成为瓶颈。那你肯定会想到分库分表,不管是通过IDHash还是Range,如下图:现在应该没问题了。不管你有多少用户,多高的并发,我只要无限扩展数据库和应用,就可以了。这也是本文的标题。分库分表能否解决无限扩容?其实像上面这样的架构是解决不了的。其实这个问题有点类似于RPC的问题:数据库连接太多!通常,由于我们的RPC应用程序访问数据库是使用中间件的,应用程序实际上并不知道访问哪个数据库,而访问数据库的规则是由中间件软件决定的,比如ShardingJDBC。这样一来,这个应用就必须连接所有的数据库,就像我们上面的架构图一样,一个RPC应用需要连接3个MySQL。如果有30个RPC应用,每个RPC的数据库连接池大小为8,每个MySQL需要维护240个连接。我们知道MySQL的默认连接数是100,最大连接数是16384。也就是说,假设每个应用的连接池大小是8,那么超过2048个应用就无法继续下去了连接起来,就无法继续扩大。请注意,2048并不像看起来那么大,因为每个物理库有许多逻辑库,而且微服务运动如火如荼。你可能会说我前面加个Proxy就可以解决连接数的问题了。事实上,代理的性能也会成为一个问题。为什么?proxy的连接数不能超过16384,如果并发超过16384,就会变成163840,那么Proxy也解决不了问题。我们应该做什么?我们再看一下上面的架构图:我们发现问题出在“每一个RPC应用都要连接所有的库”,导致在扩展应用的同时增加了每个数据库的连接数。即使增加数据库,也解决不了连接数的问题。那我们该怎么办呢?unitization,unitization,听上去很高端,通常在一些XXX会议上,分享“两地三中心左右”、“三地五中心”、“异地多活动”等牛逼的名词有时,unitization也会一起出现。这里不讨论牛逼,只说“数据库连接数过多”的问题。其实思路很简单:我们不让应用连接所有的数据库。假设我们根据Range分成10个库,现在有10个应用,我们让每个应用只连接一个库,当应用数量增加到20个,连接到数据库不够的时候,我们分10个库变成20个库。这样无论你扩展多少应用,都可以解决数据库连接数过多的问题。注意:这样做的前提是你必须保证访问你应用的Request请求的数据库必须在这个应用中。换句话说,当用户从DNS进来的时候,他们知道他们是要去应用的,所以规则是在DNS之前设置的。虽然这有点夸张,但他们在进入应用程序之前必须知道要去哪个图书馆。所以,这通常需要一个规则,比如配置中心通过用户IDHash广播的一个Hash规则。这样所有的组件都可以保持一致的规则,从而正确访问数据库,如下图所示:到这里,我们终于解决了无限扩展的问题。最后,本文从单体应用开始,逐步描述一个普通后台的演进过程,知道分库分表并不能解决“无限扩展”的问题。只有单元化才能解决这个问题,单元化带来了更多的复杂性。但是好处是不言而喻的,单元化带来了更多的想法。单元化解决了无限扩展的问题,但是我们没有考虑单点的问题,也就是服务的可用性。要知道,我们这里的数据库都是单点的。这是另外一个话题——多住异地,下次再说吧。
