万字长文之分库分表里无分库分表键如何查询【后端面试题 | 中间件 | 数据库 | MySQL | 分库分表 | 其他查询】
在很多业务里,分库分表键都是根据主要查询筛选出来的,那么不怎么重要的查询怎么解决呢?
比如电商场景下,订单都是按照买家ID来分库分表的,那么商家该怎么查找订单呢?或是买家找客服,客服要找到对应的订单,又该怎么找?
分库分表键的选择
选择进行分库分表的业务字段,有的时候会有多个字段,如何选择合适的字段呢?
关键点就是 根据查询来选择 。例如在订单里面,最常见的是按照买家来进行分库分表,理由是买家查询自己的订单是最主要的场景,这样收益最大。这个完全是业务驱动的,最常用的分库分表键有主键、外键、索引列;如果是范围分库分表,那么日期类型的列也很常用。
重试方案
设置一个重试方案要考虑3个方面的内容:
- 重试次数:无限次重试意义并不大
- 重试间隔:等间隔重试或指数退避重试。后者指的是重试间隔的时间在增长,一般是两倍增长,面试的时候可以设计一些更加灵活的重试,比如最开始按照两倍增长,再按照50%增长,最后保持最大重试间隔不断重试
- 是否允许跨进程重试:在进程A里触发了重试,但是重试一次后,是否可以在进程B上重试第二次?对应到分布式环境上,意味着是否可以在不同的机器上重试。
理论上说,重试是为了避开前一次失败的原因,比如因为偶发的网络抖动失败。设计指数退避的重试策略的原因也很简单,通过不断延长重试时间间隔,有更大的概率避开引发失败的因素。
面试准备
- 分库分表的主键生成策略
- 如果使用了后续提到的引入中间表、二次分库分表和使用其他中间件支持查询中的任何一个方案,就需要搞清楚数据同步的方案;换句话说,如果数据不一致,多久会发现,最终要多久才能达成一致。
简历里或面试里提到分库分表方案设计的时候,主动提起是如何解决这个问题的?
面试常见问题引导
- 问到了主键生成策略,那么你可以说主键生成会影响分库分表的中间表设计。
- 面试官问到了从其他维度怎么查询数据的问题。例如在订单这里问到了客服怎么查、运营怎么查等。
- 面试官问到了数据同步和数据一致性,你可以用这里面谈到的场景来展示你是如何解决这些问题的。
- 面试官问到了如何选择合适的分库分表键,那么你就可以强调非分库分表键的查询更加复杂,需要额外的支持。
基本思路
面试官都是直接问类似的问题,比如介绍了分库分表方案后,提到订单表是按照买家ID来进行分库分表的之后,会顺势问如果卖家要查询ID应该怎么办?
可以按照这个模板来介绍不同的方案
这一类没有按照分库分表键来筛选数据的查询,是需要一些额外的手段来支持的。目前来说,主流的方案是引入中间表、二次分库分表或是使用其他中间件。当然,广播作为一个兜底的解决方案,逼不得已的时候也可以使用。当然,如果自己的主键生成策略比较特殊的话,也能部分支持这一类查询。
接下来按照这些关键词一个一个地问
主键生成策略
有一种主键生成的策略是在主键里面带上分库分表的列,如果能够拿到主键,就应该知道去哪个数据库上的哪个数据表里查找。
比如:在订单ID里带上了买家ID,那么在根据订单ID来查询数据的时候,就可以通过订单ID来判断订单的数据在哪个库哪个表里。
这是一种很优雅的解决方案**,既不需要任何第三方工具的帮助,也不需要额外存储数据**。但是这个方案只能解决一部分问题,而且大多数时候主键都不是采用这种策略生成的,只能考虑其他方案了,比如引入中间表。
引入中间表
如果想支持按照卖家来搜索,可以引入一个中间表,记录了ID、卖家ID和买家ID三个数据。
当然也可以考虑把买家ID换成目标库和目标表,这样就省去了根据买家ID来定位目标库和目标表的步骤。
查询的基本步骤也很清晰:
- 先在中间表里根据卖家ID找到想要的订单ID和买家ID
- 再根据买家ID和订单号找到具体的订单数据
关键词就是中间表:
我们用了一个比较简单的方案,引入中间表来解决卖家查询的问题。中间表主要是根据卖家找到对应的订单,并且根据订单表中的买家ID来确定目标库、目标表,再去对应的数据表里把所有的数据都查询出来。
这个基本方案可以从两个角度刷亮点:
第一个角度是结合主键生成策略,优化中间表的设计
在设计订单主键的时候,将买家ID编码放到了订单ID里,中间表里就可以考虑删除买家ID列。
第二个角度是讨论中间表的缺陷,最大的缺陷是性能瓶颈
这个方案的一个重大缺陷是中间表的性能瓶颈。如果中间表的数据只插入,不存在更新的话,主要是读瓶颈,那么多加几个从库就可以解决;但是如果中间表的一些列是需要频繁被更新的,那么中间表本身就扛不住写压力,但是中间表是不能分库分表的,因为分库分表后不知道该查询哪张中间表。
中间表最让人害怕的就是写瓶颈,可以考虑提供一个解决方案:
一般来说,在设计中间表的时候就应该包含尽可能少的列,而且这些列的值应该尽可能不变,会频繁更新的列就不要放了。比如 订单ID这种ID列的基本不会变,状态这种经常变更的就不要放了。
中间表还有两个明显的缺陷:难以适应灵活多变的查询场景,还有数据一致性问题。
中间表还有一个缺陷就是表结构很固定,如果将来需要支持新的查询场景,必须要修改中间表的表结构,大多数情况下会增加新的列。另一方面,中间表本身往往是一个大表,大表改表结构是一个非常危险的事情,当然也可以考虑增加新的中间表,但是治标不治本,而且中间表越多越难维护,数据一致性越难保证。
进一步思考,中间表要想解决写瓶颈,是不是也可以分库分表?
二次分库分表
二次分库分表指复制出来一份数据,然后尝试再进行分库分表。所以你的系统里会有两份数据,分别按照不同的分库分表规则来存储。比如卖家需要查询订单,那么可以再一次按照卖家ID来进行分库分表。
原本订单表是按照买家ID来进行分库分表的,但是这种情况下,卖家查询订单很困难。比如卖家查询自己当日成交的订单量,就难以支持。而且卖家查询订单也不能算是一个低频行为,所以尝试把数据复制了一份出去,然后按照卖家ID分库分表。这种方案的主要缺陷就是数据一致性问题,以及数据复制一份需要很多的存储空间。
数据复制一份的问题解决起来也很简单:只需要复制关键表以及关键表的关键字段就可以了。部分表是不需要复制的,比如订单详情表完全不需要复制,在拿到订单ID之后再次查询订单详情表
即使复制表,也不是所有的字段都需要复制,一些BLOB、TEXT字段占用存储空间多,还不会出现在查询条件里,根本不需要复制。如果真的需要这些字段,可以拿主键和分库分表键二次查询。
这里的查询也分为了两部,但是要尽量做到大部分查询只查卖家库,只有少部分查询需要回归到买家库。
关键词是减轻存储压力
实际上,为了减轻数据复制带来的存储压力,我们可以考虑只复制一部分表,或者某个表的一部分字段。比如在同步的时候,就不需要同步订单详情表,而是拿到订单基本信息之后再去原本的买家库里面查询订单详情。
在这里可以进一步讨论两次查询引入的问题,以及可行的优化方案
在这种机制之下,如果有一个查询QPS比较高,但是又经常需要回原表查询,可以考虑两个优化方案:首先是在查询的SELECT部分去除一些用不上的列,避免回原表;如果这个措施不可以,就考虑把查询所需的列全部复制过去,避免回原表。第二种优化类似平时用覆盖索引来优化查询。
使用其他中间件
为了支持复杂多样的查询,可以尝试使用别的中间件,比如Elasticsearch。在引入Elasticsearch的时候也可以采用引入中间件方案中的一个优化措施,即只同步部分和搜索相关的字段。
为了减轻 Elasticsearch 的压力,我们选择了只同步部分字段。一些非常庞大的字段,比如说 TEXT 或者 BLOB 本身我们是不会同步过去的。
如果你选了同步部分数据到 Elasticsearch,那么你最终就会面临一个问题:总有一些业务的查询,你完全没办法支持。那这个时候你就只剩下最后一个手段了:广播。
广播
如果不能断定数据可能出现在哪一张表上,那么就直接把全部表上都查询一遍。
当卖家想要知道自己究竟卖了多少单的时候,就可以在所有的表上都问一遍,汇总之后就是卖家的所有订单
这种做法的缺陷:对数据库的压力太大。只有兜底的时候才使用。
我们还有一些兜底措施,也就是如果一个查询确实没办法使用前面那些方案的时候,那就可以考虑使用广播。也就是说直接把所有的请求发送到所有的候选节点里面,然后收集到的数据就是查询的结果。不过这种方式的缺陷就是对数据库压力很大,很多数据库上的表根本不可能有数据,但是都会收到请求,白白浪费资源。尤其是如果这些查询还会触发锁,那么性能就会更差。
引入中间表和二次分库分表
实际上可以理解为二次分库分表是中间表的升级加强版
- 中间表是性能瓶颈,害怕维护写频繁的字段;二次分库分表没有这种担忧
- 中间表本身的字段会很少,往往需要回归原表再次查询数据
- 二次分库分表成本要更高,因为需要复制更多的字段
一般来说:优先考虑使用中间表,其次考虑只复制部分数据的二次分库分表方案,逼得不得已再考虑全量复制数据的二次分库分表方案
数据同步问题
引入中间表、二次分库分表和使用其他中间件三个解决方案里,都面临同样一个问题:如何进行数据同步?
一般有两种数据同步的思路:
- 双写:在写入源数据表的时候,同时写到另一个地方。可以通过改造ORM或分库分表中间件达成。
- 利用 Canal 之类的框架监听 binlog,然后异步地把数据库同步到其他地方。
不管是双写,还是监控 binlog,都绕不开失败这个话题。那失败的时候怎么办呢?**无非就是各种重试,在重试都失败之后,就人手工介入处理。**在实践中,双写方案用得不多。高端一点的做法就是在重试失败之后,加上一个异步修复程序进一步尝试修复。如果修复程序本身也失败了,那确确实实就只能人手工介入了。这些内容之前我反复提到过,你需要记住。
亮点方案
在分库分表之后,为了充分满足不同情况下的查询需求,我们公司综合使用了三种方案:引入中间表、二次分库分表和 Elasticsearch。对于卖家查询来说,我们直接复制了一份数据,按照卖家 ID 分库分表。对于一些复杂的查询来说,就是利用 Elasticsearch。还有一些查询是通过建立中间表来满足,比如说商品 ID 和订单 ID 的映射关系。
数据同步方案是使用监听 binlog 的方案。买家库插入数据之后,就会同步一份到卖家库和 Elasticsearch 上。这个过程是有可能失败的,那么在失败之后会有重试机制,如果重试都失败了,那么就只能人手工介入处理了。
这个架构里的另一个问题是:卖家库的数据需要反向同步到买家库吗?
第一个回答是:如果允许卖家修改卖家库的数据,就需要反向同步,架构变成了下图。
我们是允许卖家直接修改数据的,所以实际上我们卖家库的修改也会同步到其他数据源。因为卖家和买家都可能同时修改各自的库。这里我举一个订单状态修改的例子。
如果买家发起取消订单,然后卖家那边要把状态修改成已发货。那么可能出现买家先修改,然后被卖家覆盖的情况,结果就是两边都是已发货;也有可能出现卖家先修改,然后被买家覆盖的情况,那么结果就是两边都是已取消。
所以类似的场景最好是采用分布式锁和双写方案。比如买家修改状态的时候,要先拿到分布式锁,然后同时修改买家库和卖家库。当然,要是覆盖数据也没关系,那么就还是可以继续采用 Canal 的同步方案。
所以综合来看,允许卖家直接修改卖家库是比较危险的事情,数据一致性问题更加严重。
这里提到了数据一致性问题更加严重,这也是为了引出第二个回答,就是除了买家库,其他库都是只读的。
也可以考虑只允许从买家库进去修改数据,也就是说,不允许直接修改卖家库的数据。
举个例子,如果卖家想要修改某个订单的数据,那么他需要在卖家库查到订单的信息,但是在修改的时候要拿着订单信息去买家库修改。
这种做法最大的优点就是简单,没有那么多数据同步和数据一致性方面的问题。缺点就是性能比较差,而且写压力始终都在买家库上。
相关文章:
万字长文之分库分表里无分库分表键如何查询【后端面试题 | 中间件 | 数据库 | MySQL | 分库分表 | 其他查询】
在很多业务里,分库分表键都是根据主要查询筛选出来的,那么不怎么重要的查询怎么解决呢? 比如电商场景下,订单都是按照买家ID来分库分表的,那么商家该怎么查找订单呢?或是买家找客服,客服要找到对…...
如何查看jvm资源占用情况
如何设置jar的内存 java -XX:MetaspaceSize256M -XX:MaxMetaspaceSize256M -XX:AlwaysPreTouch -XX:ReservedCodeCacheSize128m -XX:InitialCodeCacheSize128m -Xss512k -Xmx2g -Xms2g -XX:UseG1GC -XX:G1HeapRegionSize4M -jar your-application.jar以上配置为堆内存4G jar项…...
科研绘图系列:R语言TCGA分组饼图(multiple pie charts)
介绍 在诸如癌症基因组图谱(TCGA)等群体研究项目中,为了有效地表征和比较不同群体的属性分布,科研人员广泛采用饼图作为数据可视化的工具。饼图通过将一个完整的圆形划分为若干个扇形区域,每个扇形区域的面积大小直接对应其代表的属性在整体中的占比。这种图形化的展示方…...
ReadAgent,一款具有要点记忆的人工智能阅读代理
人工智能咨询培训老师叶梓 转载标明出处 现有的大模型(LLMs)在处理长文本时受限于固定的最大上下文长度,并且当输入文本越来越长时,性能往往会下降,即使在没有超出明确上下文窗口的情况下,LLMs 的性能也会随…...
构建智能:利用Gradle项目属性控制构建行为
构建智能:利用Gradle项目属性控制构建行为 Gradle作为一款强大的构建工具,提供了丰富的项目属性管理功能。通过项目属性,开发者可以灵活地控制构建行为,实现条件编译、动态配置和多环境构建等高级功能。本文将详细解释如何在Grad…...
如何通过smtp设置使ONLYOFFICE协作空间服务器可以发送注册邀请邮件
什么是ONLYOFFICE协作空间 ONLYOFFICE协作空间,是Ascensio System SIA公司出品的,基于Web的,开源的,跨平台的,在线文档编辑和协作的解决方案。在线Office包含了最基本的办公三件套:文档编辑器、幻灯片编辑…...
SQL labs靶场-SQL注入入门
靶场及环境配置参考 一,工具准备。 推荐下载火狐浏览器,并下载harkbar插件(v2)版本。hackbar使用教程在此不做过多描述。 补充:url栏内部信息会进行url编码。 二,SQL注入-less1。 1,判断传参…...
HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 单选题序号4
基础认证题库请移步:HarmonyOS应用开发者基础认证题库 注:有读者反馈,题库的代码块比较多,打开文章时会卡死。所以笔者将题库拆分,单选题20个为一组,多选题10个为一组,题库目录如下,…...
使用LSTM完成时间序列预测
c 在本教程中,我们将介绍一个简单的示例,旨在帮助初学者入门时间序列预测和 PyTorch 的使用。通过这个示例,你可以学习如何使用 LSTMCell 单元来处理时间序列数据。 我们将使用两个 LSTMCell 单元来学习从不同相位开始的正弦波信号。模型在…...
《数据结构:顺序实现二叉树》
文章目录 一、树1、树的结构与概念2、树相关术语 二、二叉树1、概念与结构2、满二叉树3、完全二叉树 三、顺序二叉树存储结构四、实现顺序结构二叉树1、堆的概念与结构2、堆的实现3、堆的排序 一、树 1、树的结构与概念 树是一种非线性的数据结构,它是由nÿ…...
【HarmonyOS】HarmonyOS NEXT学习日记:六、渲染控制、样式结构重用
【HarmonyOS】HarmonyOS NEXT学习日记:六、渲染控制、样式&结构重用 渲染控制包含了条件渲染和循环渲染,所谓条件渲染,即更具状态不同,选择性的渲染不同的组件。 而循环渲染则是用于列表之内的、多个重复元素组成的结构中。 …...
【防火墙】防火墙NAT、智能选路综合实验
实验拓扑 实验要求 7,办公区设备可以通过电信链路和移动链路上网(多对多的NAT,并且需要保留一个公网IP不能用来转换) 8,分公司设备可以通过总公司的移动链路和电信链路访问到Dmz区的http服务器 9,多出口环境基于带宽比例进行选路…...
VUE之---slot插槽
什么是插槽 slot 【插槽】, 是 Vue 的内容分发机制, 组件内部的模板引擎使用slot 元素作为承载分发内容的出口。slot 是子组件的一个模板标签元素, 而这一个标签元素是否显示, 以及怎么显示是由父组件决定的。 VUE中slot【插槽】…...
linux、windows、macos,命令终端清屏
文章目录 LinuxWindowsmacOS 在Linux、Windows和macOS的命令终端中,清屏的命令或方法各不相同。以下是针对这三种系统的清屏方法: Linux clear命令:这是最常用的清空终端屏幕的命令之一。在终端中输入clear命令后,屏幕上的所有内容…...
【RaspberryPi】树莓派Matlab/Simulink支持包安装与使用
官网支持与兼容性 Raspberry Pi Support from MATLAB - Hardware Support - MATLAB & Simulink Raspberry Pi Support from Simulink - Hardware Support - MATLAB & Simulink Matlab与树莓派兼容性 Simulink与树莓派兼容性 树莓派Matlab&Simulink RaspberryPi支…...
嵌入式人工智能(10-基于树莓派4B的DS1302实时时钟RTC)
1、实时时钟(Real Time Clock) RTC,全称为实时时钟(Real Time Clock),是一种能够提供实时时间信息的电子设备。RTC通常包括一个计时器和一个能够记录日期和时间的电池。它可以独立于主控芯片工作ÿ…...
C++ | Leetcode C++题解之第275题H指数II
题目: 题解: class Solution { public:int hIndex(vector<int>& citations) {int n citations.size();int left 0, right n - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > n - mid) {right m…...
编写DockerFile
将自己的项目或者环境通过Docker部署到服务器需要一下几个步骤: 打包项目或者环境 编写Dockerfile文件 运行Dockerfile文件,构建DockerImages镜像,将DockerImages存入DockerHub或者存入阿里云镜像仓库 服务器pull下DockerImages镜像&#…...
TCP并发服务器多线程
1.创建线程‐‐pthread_create int pthread_create( pthread_t *thread, // 线程 ID 无符号长整型 const pthread_attr_t *attr, // 线程属性, NULL void *(*start_routine)(void *), // 线程处理函数 void *arg); // 线程处理函数 参数: pthrea…...
技术速递|C# 13:探索最新的预览功能
作者:Kathleen Dollard 排版:Alan Wang C# 13 已初具雏形,其新特性侧重于灵活性、性能以及使您最喜欢的功能在日常中变得更容易使用。我们以公开的方式构建 C#,在今年的 Microsoft Build 大会上,我们会让您一睹 C# 13 …...
Python设计模式:巧用元类创建单例模式!
✨ 内容: 今天我们来探讨一个高级且实用的Python概念——元类(Metaclasses)。元类是创建类的类,它们可以用来控制类的行为。通过本次练习,我们将学习如何使用元类来实现单例模式,确保某个类在整个程序中只…...
构建自主可控的工业操作系统,筑牢我国工业安全堡垒
构建自主可控的工业操作系统,筑牢我国工业安全堡垒,鸿道(Intewell)操作系统为国家工业发展保驾护航。 7月19日,全球多地安装微软操作系统的电脑设备出现大规模宕机,导致“蓝屏”现象,严重影响了航空、铁路、医疗、金…...
WPF串口通讯程序
目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 using HardwareCommunications; using System.IO.Ports; using System.Windows;namespace PortTest {/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainW…...
汽车技术智能化程度不断提升,线束可靠性如何设计?
随着汽车技术的高速发展,汽车自动化、智能化程度的逐步提高,人们对汽车的安全性、舒适性、娱乐性等要求也不断提高,加上汽车节能减排法规的不断严峻,整车电气设备不断增加,作为连接汽车各种电器设备“神经网络”的整车…...
实现Nginx的反向代理和负载均衡
一、反向代理和负载均衡简介 1.1、反向代理 反向代理(reverse proxy)指:以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端。此时代理服务器对外就表现为一个反向代理服务器。 反向代…...
【算法】子集
难度:中等 题目: 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的 子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums [1,…...
Web前端:HTML篇(一)
HTML简介: 超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。 您可以使用 HTML 来建立自己的 WEB 站点,HTML 运行在浏览器上,由浏览器…...
ActiViz中的选择点vtkWorldPointPicker
文章目录 1. vtkWorldPointPicker简介2. 类的位置和继承关系3. 选择机制4. 返回的信息5. 选择的条件和参数6. 与屏幕空间选择器的比较7. 性能特征8. 应用场景9. 与其他vtk选择器的集成10. 完整示例总结1. vtkWorldPointPicker简介 vtkWorldPointPicker是Visualization Toolkit…...
如何开启或者关闭 Windows 安全登录?
什么是安全登录 什么是 Windows 安全登录呢?安全登录是 Windows 附加的一个组件,它可以在用户需要登录的之前先将登录界面隐藏,只有当用户按下 CtrlAltDelete 之后才出现登录屏幕,这样可以防止那些模拟登录界面的程序获取密码信息…...
【目标检测】Anaconda+PyTorch配置
前言 本文主要介绍在windows系统上的Anaconda、PyTorch关键步骤安装,为使用yolo所需的环境配置完善。同时也算是记录下我的配置流程,为以后用到的时候能笔记查阅。 Anaconda 软件安装 Anaconda官网:https://www.anaconda.com/ 另外&#…...
wordpress 关键词排名/深圳网络推广哪家
先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购、秒杀、特价之类的活动,而这样的活动有一个共同的特点就是访问量激增、上千甚至上万人抢购一个商品。然而,作为活动商品,库存肯定是很有限的,如何控制库存…...
相亲网站拉人做基金/贴吧aso优化贴吧
动态规划3--Help Jimmy 一、心得 二、题目 三、分析 Jimmy跳到一块板上后,可以有两种选择,向左走,或向右走。走到左端和走到右端所需的时间,是很容易算的。如果我们能知道,以左端为起点到达地面的最短时间,…...
物流信息网站cms/今天重要新闻
题目 思路 其实这道题就是用线段树去写,只是把线段树中结构体中的sumsumsum换成maxvmaxvmaxv,把维护一个和改成维护一个最大值。 线段树思路:https://blog.csdn.net/weixin_45798993/article/details/123705429?spm1001.2014.3001.5501 代码…...
怎么制造网站/重庆公司seo
void ExitProcess( UINT uExitCode ); ExitProcess是一个API函数,它会结束当前应用程序的执行,并设置它的退出代码。uExitCode是此程序的退出代码。虽然可以在程序的任何地方去调用ExitProcess,强制当前程序的执行立即结束。对于操作系统来说…...
德州极速网站建设百家号/怎样制作一个自己的网站
计算机应用技术的应用与发展随着科技水平的提高,计算机已经渐渐的融入到我们的生活中,并有着不可或缺的作用,增强计算机与网络应用技术创新的重要性是不容忽视的。下面YJBYS小编为大家搜索整理了关于计算机应用技术的应用与发展,供…...
wordpress激活码充值/枫树seo
多态 1、多态的体现: 父类的引用或者接口的引用指向了自己的子类对象。 Dog d new Dog();//Dog对象的类型是Dog类型。 Animal a new Dog();//Dog对象的类型右边是Dog类型,左边Animal类型。多态的利弊: 好处:提高了代码的扩展…...