# Java Web架构变迁

参考《淘宝技术这十年》,《淘宝十年架构变迁》,对JavaWeb的相关架构进行学习。

# 单机架构 推荐

# 架构图


# 架构说明

    1)浏览器首先会判断当前要访问的域名及解析后的ip地址是否在缓存,如不在缓存,则访问DNS解析服务器,同时将其放入缓存。如在缓存中,则直接使用解析后的ip地址。
    2)解析到对应的ip地址后,浏览器请求后端Tomcat服务器获取前端静态资源(JSP,HTML,CSS,JS等),然后解析静态资源,在解析静态资源的过程中,会请求静态资源里的后端接口。
    3)浏览器访问后端接口,如接口涉及数据库的读写操作,Tomcat会请求MySQL服务。

# 优缺点

# 优点

开发,部署十分简单,几乎不存在运维成本。

# 缺点

随着用户数的增长,Web服务器(Tomcat)和数据库(MySQL)之间竞争资源,单机性能不足以支撑业务。

# 第一次演变-Tomcat与数据库分开部署

为了解决用户增长导致的单机架构Web服务器与数据库竞争资源的问题,我们考虑使用更多的主机资源,在新的主机资源上部署MySQL服务器。

# 架构图


# 架构说明

将数据库和Web服务器进行分离,显著提升了两者各自的性能。

# 优缺点

# 优点

开发,部署十分简单,几乎不存在运维成本。

# 缺点

随着用户数的增长,并发读写数据库成为了新的性能瓶颈。

# 第二次演变-引入本地缓存和分布式缓存

为了解决数据库读写的瓶颈问题,引入了本地缓存(使用memcached)以及分布式缓存(Redis)

# 架构图


# 架构说明

    1)在Tomcat同服务器上或同JVM中增加本地缓存(使用memcached作为本地缓存,本地缓存也叫进程内缓存),并在外部增加分布式缓存(Redis集群),缓存热门商品信息或热门商品的html页面等。通过缓存能把绝大多数请求在读写数据库前拦截掉,大大降低数据库压力。
    2)在这个缓存架构中,缓存只会存在本地缓存或分布式缓存其中之一,并不会同时存在于本地缓存和分布式缓存中。

# 优缺点

# 优点

解决了数据库的读写瓶颈问题,开发,部署相对简单,运维成本不大。

# 缺点

    1)引入了本地缓存及分布式缓存之后,就会涉及缓存一致性、缓存穿透/击穿、缓存雪崩、热点数据集中失效等问题,这些问题都需要处理。
    2)缓存抗住了大部分的访问请求,随着用户数的增长,并发压力主要落在单机的Tomcat上,响应逐渐变慢。

SpringBoot中的本地缓存

1.SpringBoot中默认使用的本地缓存方案是什么?
SpringBoot默认的进程内缓存是SpringCache+Caffeine,也即是说使用的本地缓存是Caffeine。

2.如何解决本地缓存和数据库一致性问题?
8种方案,保证缓存和数据库的最终一致性 (opens new window)

3.Caffeine如何处理缓存一致性问题?
通过设置缓存过期时间,以及回写缓存(在数据写操作完成后,再异步写入缓存中)的策略来解决缓存一致性问题。

4.什么是分布式缓存的延迟双删策略?
延迟双删,即先删除缓存,再更新数据库,然后再让异步线程延迟一段时间(一般1s)后,再次删除缓存的策略,该策略可用于解决缓存一致性问题。分布式缓存数据库一致性问题 (opens new window)

5.本地缓存如何自己实现?
如果自己实现本地缓存,使用ConcurrentHashMap即可,在更新缓存的时候使用延迟双删策略,只不过要注意,需要有策略去清理缓存(可以简单的给缓存设置一个失效时间,定时任务操作ConcurrentHashMap清理失效缓存)。

参考资料:spring boot:使用spring cache+caffeine做进程内缓存(本地缓存)(spring boot 2.3.1) (opens new window)

缓存穿透、缓存击穿、缓存雪崩

1.缓存穿透指的是什么?如何避免缓存穿透?
缓存穿透指的是恶意用户或攻击者通过请求不存在于缓存和后端存储中的数据来使得所有请求都落到后端存储上,导致系统瘫痪。解决方案通常包括使用布隆过滤器或者黑白名单等方式来过滤掉无效请求,以及在应用程序中加入缓存预热等机制。

2.缓存击穿指的是什么?如何避免?
缓存击穿指的是在高并发访问下,某个热点数据失效后,大量请求同时涌入后端存储,导致后端存储负载增大、响应时间变慢,甚至瘫痪。解决方案通常包括使用互斥锁或者分布式锁来对并发请求进行控制,避免对同一资源的并发读写竞争,另外也可以使用热点数据预加载等机制来提前将热点数据加入缓存,在其失效时快速刷新缓存。

3.缓存雪崩指的是什么?如何避免?
缓存雪崩指的是因为某些原因导致缓存中大量的数据同时失效或过期,导致后续请求都落到后端存储上,从而引起系统负载暴增、性能下降甚至瘫痪。解决方案通常包括使用分布式缓存部署、设置不同的过期时间、应用程序限流等措施来避免缓存失效时间集中在同一时间段,以及使用缓存预热和自动刷新机制等手段来减轻缓存压力。

参考资料:缓存失效的三大祸害:穿透、击穿、雪崩及应对策略详解 (opens new window)

布隆过滤器

1.布隆过滤器是什么,可以解决什么问题?
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。
布隆过滤器可用于解决缓存穿透问题,可以在google提供的guava工具包中找到布隆过滤器。

参考资料:【高并发三剑客(缓存篇)】- 4. 布隆过滤器原理与实战 (opens new window)

# 第三次演变-引入反向代理实现负载均衡

为了解决单机Tomcat的问题,我们考虑使用多台服务器分别部署Tomcat服务,再经由Nginx转发请求负载到Tomcat服务。

# 架构图


# 架构说明

    1)在多台服务器上分别部署Tomcat,使用反向代理软件(Nginx)把请求均匀分发到每个Tomcat中。此处假设Tomcat最多支持100个并发,Nginx最多支持50000个并发,那么理论上Nginx把请求分发到500个Tomcat上,就能抗住50000个并发。
    2)Nginx是工作在网络第七层的反向代理软件,主要支持http协议,还会涉及session共享(一般使用Nginx的session绑定,确保一个ip的请求通过hash算法负载到下方同一台Tomcat服务)、文件上传下载共享的问题(多台Tomcat使用NAS盘共享文件)。

# 优缺点

# 优点

这个架构解决了Tomcat的单机瓶颈问题,但是相应的,就不能使用本地缓存了,只能使用Redis做分布式缓存(感觉可以使用Nginx+Openresty,用Nginx做本地缓存)。

# 缺点

    1)Nginx是单节点部署,可能有宕机风险(可使用Nginx+KeepAlived+虚拟IP的Nginx热备方案解决Nginx单机部署问题)。
    2)反向代理使应用服务器可支持的并发量大大增加,但并发量的增长也意味着更多请求穿透到数据库,单机的数据库最终成为瓶颈

# 第四次演变-数据库读写分离

在Nginx+多Tomcat集群的情况下,引入分布式缓存已经没办法解决单数据库的压力,我们考虑部署多个数据库节点,对数据库做读写分离。

# 架构图


# 架构说明

    1)其实架构演变到这里,单一数据库成了瓶颈,且依靠其他方案无法突破该瓶颈,作为数据库厂商,就必然要提供一些解决数据库瓶颈的方案,Mysql提供的方案是主从同步集群方案以及MysqlRouter读写分离方案。
    2)把数据库划分为读库和写库,读库可以有多个,通过同步机制把写库的数据同步到读库,对于需要查询最新写入数据场景,可通过在缓存中多写一份,通过缓存获得最新数据。
    3)这里涉及到的技术是MySQL集群的搭建,MysqlRouter中间件的配置。数据同步,数据一致性的问题由MySQL集群自行解决。

# 优缺点

# 优点

MySQL做了读写分离后,单一数据库的瓶颈问题就解决了,一般非微服务架构到了这一步就已经足够支持很大的业务量了

# 缺点

    1)Nginx是单节点部署,可能有宕机风险(可使用Nginx+KeepAlived+虚拟IP的Nginx热备方案解决Nginx单机部署问题)。
    2)业务逐渐变多,不同业务之间的访问量差距较大,不同业务直接竞争数据库,相互影响性能

分布式环境下还能用本地缓存吗?

可以是可以,但是用了本地缓存,还用分布式缓存,还有数据写DB操作,我的理解是同一个缓存不应同时存在于本地缓存及分布式缓存,且多个本地缓存之间如何保持同步也是个问题?
结论就是分布式环境下不推荐用本地缓存,除非在具体的业务场景下访问mysql分布式缓存的网络连接成为瓶颈。

参考资料:分布式本地缓存好用吗? (opens new window)本地缓存与分布式缓存的优缺点、适用场景与实现分析 (opens new window)

Mysql一主两从集群如何搭建?

MySQL主从集群的搭建,推荐使用MySQL自己的集群方案,我所在的公司DBA部署的方案是采用MGR方式实现。

参考资料:Mysql MGR搭建 (opens new window)

Mysql读写分离中间件用哪个?

我所在的公司,Mysql读写分离中间件用的是Mysql自己提供的MysqlRouter,技术选型及中间件的运行维护工作由DBA负责。
MysqlRouter会暴露两个访问数据库的连接串,也即数据源,写数据源操作的是主库,读数据源操作的是两个从库,内部会轮询两个从库之一,读写操作的判断交给业务系统自己确定。

参考资料:死磕数据库系列(二十九):MySQL Router 实现数据库读写分离配置实践 (opens new window)

业务系统如何做读写分离?

1.作为业务系统,MysqlRouter仅暴露两个数据源,一个用于读,另一个用于写,我们需要自行判断读写操作,使用不同的数据源。
2.目前我负责的系统,所有的服务都连接到MysqlRouter主库的数据源,读写操作均操作主库。

3.因在业务系统中,我们并不直接操作数据源,而是使用相关jar包,如druid,读写分离这块还需要了解druid如何实现。

参考资料:mybaits+druid+aop 实现读写分离(支持自定义注解读数据切换主从库) (opens new window)

# 第五次演变-垂直分库

# 架构图


# 架构说明

    1)对于不同业务系统访问同一个数据库的问题,我们可以根据业务系统进行分库(也即垂直分库),将不同的表分配对应的业务系统所属的数据库中。

# 优缺点

# 优点

把不同业务的数据保存到不同的数据库中,使业务之间的资源竞争降低,对于访问量大的业务,可以部署更多的服务器来支撑。

# 缺点

    1)跨业务的表无法直接做关联分析,需要通过其他途径来解决。
    2)随着用户数的增长,单机的写库会逐渐会达到性能瓶颈。

什么是垂直分库?

垂直分库,指的是将单个数据库的表拆分到多个数据库中,一般在单体服务调整为微服务的时候,就需要对单体服务的数据库进行垂直分库,保证不同的服务使用不同的数据库(一定需要避免不同微服务使用相同数据库的情况)。

什么是水平分库?

水平分库指的是两个数据库里存放相同的数据表,业务系统根据读写操作的具体业务逻辑判断具体要读写的数据库是哪个,然后去操作对应的数据库表做读写操作。
水平分库仅见于大型的互联网应用及银行类应用,一般的微服务架构环境不需要做水平分库。

什么是水平分表?

水平分表指的是在一个数据库中,将同一个表水平拆分为多个,如订单order表,如单表数据过大,会拆分为order01以及order02表。
实际项目里我负责的系统在查询操作中会根据月份做水平分表,前端查询仅允许查询当月数据,不允许跨月查询。

什么是垂直分表?

垂直分表指的是将一个列比较多的表拆分为多个表,表与表之间根据主外键链接的过程就是垂直分表,一般会把单表中不常查询的字段单独存放在其他表中。

一般用什么中间件做水平分库及水平分表?

在java应用层面,一般推荐使用ShardingSphere做水平分库以及水平分表中间件。
分库分表之ShardingSphere (opens new window)
ShardingSphere分库分表实战之水平分库和水平分表 (opens new window)
微服务分库分表 (opens new window)

分布式ID如何实现?

可以通过雪花算法来实现分布式ID。

分布式锁如何实现?

可以通过MySQL,Redis等实现分布式锁。

分布式事务如何实现?

可以使用阿里开源的分布式事务中间件Seata。看了 5 种分布式事务方案,我司最终选择了 Seata,真香! (opens new window)
Seata详解(一) (opens new window)

其他概念

1.MySQL读写分离
2.分布式缓存及分布式锁(Redis)
3.MySQL垂直分库
4.MySQL水平分表,水平分库 (工具ShardingSphere)
5.分布式ID(雪花算法,可能有时钟回拨问题)
6.分布式事务(Seata)
answer:
垂直分库对应微服务拆分,读写分离,水平分库以及水平分表对应ShardingSphere,分布式事务对应Seata,需要做ShardingSphere以及Seata的整合
分布式缓存使用Redis,禁用本地缓存,缓存一致性使用双删逻辑,穿透使用布隆过滤器,击穿使用分布式锁机制,雪崩通过缓存过期时间随机数避免

# 第六次演变-水平分表

# 架构图


# 架构说明

    1)对于单表数据较多的情况,我们可以采用水平分表,水平分表的判断标准是单表数据量,一般达到千万的数量级,就必须要水平分表了(因为千万级的数据没办法通过索引进行优化,因此访问上会出现瓶颈)。

# 优缺点

# 优点

    1)比如针对评论数据,可按照商品ID进行hash,路由到对应的表中存储;针对支付记录,可按照小时创建表,每个小时表继续拆分为小表,使用用户ID或记录编号来路由数据。
    2)只要实时操作的表数据量足够小,请求能够足够均匀的分发到多台服务器上的小表,那数据库就能通过水平扩展的方式来提高性能。其中前面提到的Mycat也支持在大表拆分为小表情况下的访问控制。

# 缺点

    1)开发的复杂度很高。
    2)这种做法显著的增加了数据库运维的难度,对DBA的要求较高。数据库设计到这种结构时,已经可以称为分布式数据库,但是这只是一个逻辑的数据库整体,数据库里不同的组成部分是由不同的组件单独来实现的,如分库分表的管理和请求分发,由Mycat实现,SQL的解析由单机的数据库实现,读写分离可能由网关和消息队列来实现,查询结果的汇总可能由数据库接口层来实现等等,这种架构其实是MPP(大规模并行处理)架构的一类实现。
    3)数据库和Tomcat都能够水平扩展,可支撑的并发大幅提高,随着用户数的增长,最终单机的Nginx会成为瓶颈

分布式数据库

MySQL并没有对水平分表的直接支持,因此我们只能通过代码去实现,人为的去做水平分表动作,与之相对的,市面上也存在很多成熟的分布式数据库,这些库就原生支持水平分表以及水平分库操作。这类数据库里比较有代表性的一个是TiDB

# 第七次演变-使用LVS或F5对多个Nginx负载均衡

# 架构图


# 架构说明

    1)如果单一的Nginx成为瓶颈,我们能想到的是对Nginx进行负载,因此只能引入更为高性能的负载均衡器,推荐使用F5做硬件负载均衡。

# 优缺点

# 优点

    1)由于瓶颈在Nginx,因此无法通过两层的Nginx来实现多个Nginx的负载均衡。图中的LVS和F5是工作在网络第四层的负载均衡解决方案,其中LVS是软件,运行在操作系统内核态,可对TCP请求或更高层级的网络协议进行转发,因此支持的协议更丰富,并且性能也远高于Nginx,可假设单机的LVS可支持几十万个并发的请求转发;F5是一种负载均衡硬件,与LVS提供的能力类似,性能比LVS更高,但价格昂贵。
    2)由于LVS是单机版的软件,若LVS所在服务器宕机则会导致整个后端系统都无法访问,因此需要有备用节点。可使用keepalived软件模拟出虚拟IP,然后把虚拟IP绑定到多台LVS服务器上,浏览器访问虚拟IP时,会被路由器重定向到真实的LVS服务器,当主LVS服务器宕机时,keepalived软件会自动更新路由器中的路由表,把虚拟IP重定向到另外一台正常的LVS服务器,从而达到LVS服务器高可用的效果。
    3)此处需要注意的是,上图中从Nginx层到Tomcat层这样画并不代表全部Nginx都转发请求到全部的Tomcat,在实际使用时,可能会是几个Nginx下面接一部分的Tomcat,这些Nginx之间通过keepalived实现高可用,其他的Nginx接另外的Tomcat,这样可接入的Tomcat数量就能成倍的增加。

# 缺点

    1)由于LVS也是单机的,随着并发数增长到几十万时,LVS服务器最终会达到瓶颈,此时用户数达到千万甚至上亿级别,用户分布在不同的地区,与服务器机房距离不同,导致了访问的延迟会明显不同。

# 第八次演变-通过DNS轮询实现机房间的负载均衡

# 架构图


# 架构说明

    1)在解决了Nginx的瓶颈问题之后,单个机房的问题逐渐暴露出来成为瓶颈,因此我们的架构需要实现跨机房负载。

# 优缺点

# 优点

    1)在DNS服务器中可配置一个域名对应多个IP地址,每个IP地址对应到不同的机房里的虚拟IP。当用户访问www.taobao.com时,DNS服务器会使用轮询策略或其他策略,来选择某个IP供用户访问。此方式能实现机房间的负载均衡,至此,系统可做到机房级别的水平扩展,千万级到亿级的并发量都可通过增加机房来解决,系统入口处的请求并发量不再是问题。

# 缺点

    1)跨机房负载最需要解决的问题就是跨机房的数据同步,这里推荐使用分布式数据库同步系统otter(解决中美异地机房)。
    2)随着数据的丰富程度和业务的发展,检索、分析等需求越来越丰富,单单依靠数据库无法解决如此丰富的需求。

# 第九次演变-引入NoSQL数据库和搜索引擎等技术

# 架构图


# 架构说明

    1)当数据库中的数据多到一定规模时,数据库就不适用于复杂的查询了,往往只能满足普通查询的场景。对于统计报表场景,在数据量大时不一定能跑出结果,而且在跑复杂查询时会导致其他查询变慢,对于全文检索、可变数据结构等场景,数据库天生不适用。因此需要针对特定的场景,引入合适的解决方案。如对于海量文件存储,可通过分布式文件系统HDFS解决,对于key value类型的数据,可通过HBase和Redis等方案解决,对于全文检索场景,可通过搜索引擎如ElasticSearch解决,对于多维分析场景,可通过Kylin或Druid等方案解决。

# 优缺点

# 优点

    1)不再使用单一的传统SQL数据库,而是针对不同的场景使用不同的数据库做解决方案。

# 缺点

    1)引入更多组件同时会提高系统的复杂度,不同的组件保存的数据需要同步,需要考虑一致性的问题,需要有更多的运维手段来管理这些组件等。
    2)引入更多组件解决了丰富的需求,业务维度能够极大扩充,随之而来的是一个应用中包含了太多的业务代码,业务的升级迭代变得困难。

# 第十次演变-大应用拆分为小应用

# 架构图


# 架构说明

    1)按照业务板块来划分应用代码,使单个应用的职责更清晰,相互之间可以做到独立升级迭代。这时候应用之间可能会涉及到一些公共配置,可以通过分布式配置中心Zookeeper来解决。

# 优缺点

# 优点

    1)应用的职责更加明确,大应用拆分到小应用,更易扩展。

# 缺点

    1)不同应用之间存在共用的模块,由应用单独管理会导致相同代码存在多份,导致公共功能升级时全部应用代码都要跟着升级。

# 第十一次演变-复用的功能抽离成微服务

# 架构图


# 架构说明

    1)如用户管理、订单、支付、鉴权等功能在多个应用中都存在,那么可以把这些功能的代码单独抽取出来形成一个单独的服务来管理,这样的服务就是所谓的微服务,应用和服务之间通过HTTP、TCP或RPC请求等多种方式来访问公共服务,每个单独的服务都可以由单独的团队来管理。此外,可以通过Dubbo、SpringCloud等框架实现服务治理、限流、熔断、降级等功能,提高服务的稳定性和可用性。

# 优缺点

# 优点

    1)把公共功能拆分为微服务,更好的解耦应用。

# 缺点

    1)不同服务的接口访问方式不同,应用代码需要适配多种访问方式才能使用服务,此外,应用访问服务,服务之间也可能相互访问,调用链将会变得非常复杂,逻辑变得混乱。

# 第十二次演变-引入企业服务总线ESB屏蔽服务接口的访问差异

# 架构图


# 架构说明

    1)通过ESB统一进行访问协议转换,应用统一通过ESB来访问后端服务,服务与服务之间也通过ESB来相互调用,以此降低系统的耦合程度。这种单个应用拆分为多个应用,公共服务单独抽取出来来管理,并使用企业消息总线来解除服务之间耦合问题的架构,就是所谓的SOA(面向服务)架构,这种架构与微服务架构容易混淆,因为表现形式十分相似。个人理解,微服务架构更多是指把系统里的公共服务抽取出来单独运维管理的思想,而SOA架构则是指一种拆分服务并使服务接口访问变得统一的架构思想,SOA架构中包含了微服务的思想。

# 优缺点

# 优点

    1)引入企业服务总线来解决服务与服务之间的耦合问题。

# 缺点

    1)业务不断发展,应用和服务都会不断变多,应用和服务的部署变得复杂,同一台服务器上部署多个服务还要解决运行环境冲突的问题,此外,对于如大促这类需要动态扩缩容的场景,需要水平扩展服务的性能,就需要在新增的服务上准备运行环境,部署服务等,运维将变得十分困难。

# 第十三次演变-引入容器化技术实现运行环境隔离与动态服务管理

# 架构图


# 架构说明

    1)目前最流行的容器化技术是Docker,最流行的容器管理服务是Kubernetes(K8S),应用/服务可以打包为Docker镜像,通过K8S来动态分发和部署镜像。Docker镜像可理解为一个能运行你的应用/服务的最小的操作系统,里面放着应用/服务的运行代码,运行环境根据实际的需要设置好。把整个“操作系统”打包为一个镜像后,就可以分发到需要部署相关服务的机器上,直接启动Docker镜像就可以把服务起起来,使服务的部署和运维变得简单。
    2)在大促的之前,可以在现有的机器集群上划分出服务器来启动Docker镜像,增强服务的性能,大促过后就可以关闭镜像,对机器上的其他服务不造成影响。

# 优缺点

# 优点

    1)使用docker及docker容器编排技术(k8s),降低服务部署的运维成本。

# 缺点

    1)使用容器化技术后服务动态扩缩容问题得以解决,但是机器还是需要公司自身来管理,在非大促的时候,还是需要闲置着大量的机器资源来应对大促,机器自身成本和运维成本都极高,资源利用率低。

# 第十四次演变-以云平台承载系统

# 架构图


# 架构说明

    1)系统可部署到公有云上,利用公有云的海量机器资源,解决动态硬件资源的问题,在大促的时间段里,在云平台中临时申请更多的资源,结合Docker和K8S来快速部署服务,在大促结束后释放资源,真正做到按需付费,资源利用率大大提高,同时大大降低了运维成本。
    2)所谓的云平台,就是把海量机器资源,通过统一的资源管理,抽象为一个资源整体,在之上可按需动态申请硬件资源(如CPU、内存、网络等),并且之上提供通用的操作系统,提供常用的技术组件(如Hadoop技术栈,MPP数据库等)供用户使用,甚至提供开发好的应用,用户不需要关系应用内部使用了什么技术,就能够解决需求(如音视频转码服务、邮件服务、个人博客等)。

# 优缺点

# 优点

    1)使用云服务部署应用,降低服务部署的运维成本。

# 缺点

    1)暂未识别有什么缺点。

IaaS、PaaS、SaaS分别指什么?

IaaS:基础设施即服务。对应于上面所说的机器资源统一为资源整体,可动态申请硬件资源的层面。
PaaS:平台即服务。对应于上面所说的提供常用的技术组件方便系统的开发和维护。
SaaS:软件即服务。对应于上面所说的提供开发好的应用或服务,按功能或性能要求付费。

# 分布式系统中登录认证如何实现?

在分布式系统中,登录认证功能一般独立出来作为一个微服务,即登录认证服务,其他服务依赖登录认证服务的登录认证功能。登录认证的相关操作一般会在网关gateway中进行,一般情况下,有两种方案可以做登录认证,分别是jwt方案以及token+redis方案。

# jwt方案


# token+redis方案


# 水平分库及水平分表会产生什么问题?如何解决?

水平分库分表会产生分布式事务,跨节点关联查询,跨节点分页以及排序问题。

# 分布式事务

可使用seata组件的2pc方式来解决分布式事务问题。

# 跨节点关联查询

人为的将关联查询拆分成单个的查询,然后用代码去串联关联关系。

# 跨节点分页及排序

先对每个库都查询出总量的数据,然后汇总后再排序。在涉及分页的过程中,最大的问题是对每个表的查询结果进行归并,可以参考shardingjdbc的流式归并解决问题。21-Sharding-JDBC执行原理-结果归并 (opens new window)29-shardingsphere-实现原理-归并引擎-分页归并 (opens new window)

# 主键避重

各库之间同一水平分库分表环境,不允许主键重复,因此直接使用shardingjdbc自带的雪花算法生成主键即可。

# 公共表(广播表)问题

有一些表是公共表,需要在所有数据库里都存储,如果要对这类数据做更新,就需要对所有数据库都更新。

# 绑定表(关联表)问题

绑定表指的是分片规则一致的主表以及从表,例如t_order表以及t_order_item表,均按照order_id分片,绑定表之间的分区键完全相同,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

# 分布式Id生成策略

分布式Id的生成有两种主流的策略,分别是号段下发以及雪花算法。
我负责的系统里分布式Id的生成是根据ShardingJDBC自带的雪花算法来实现的,除此之外,也有各个厂商开源出来的中间件可供使用。比较典型的是美团的Leaf中间件,该中间件提供了号段下发策略以及雪花算法策略可供选择。

# 雪花算法

不细讲。

# 号段下发

每个请求Leaf的中间件都可以获取到一段分布式id,如第一次获取是[0,1000],中间件不关注业务系统是否使用这些id,第二次业务系统请求的时候,会下发[1000,2000]给业务系统使用。

# 分布式系统部署实施

一般分布式系统的部署以及实施会使用基于K8s(docker编排)+jenkins构成的devops平台来实施。我自己负责的系统使用docker部署,未使用docker编排相关技术,暂时也未接入公司流水线。

# 分布式系统监控

如果分布式系统使用了k8s部署实施,一般会配套使用相应的监控平台,可使用Prometheus+Grafana构建监控平台。我自己负责的系统使用的是公司统一的监控平台(腾讯蓝鲸)。

# 分布式日志分析

一般如分布式系统,涉及的服务链路过长,可使用ELK(ES+Logstash+Kibana)+Skywalking做分布式链路追踪。我自己负责的系统一般服务链路较短,没有引入分布式日志分析中间件。

# 参考资料

16 张图解 | 淘宝 10年架构演进 (opens new window)