美团面试:百亿级分片,如何设计基因算法?

news2024/11/18 17:42:40

尼恩说在前面

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的架构类/设计类的场景题:

1.说说分库分表的基因算法?

2.大厂常用的基因算法,是如何设计的?

3.百亿级分片,如何设计基因算法?

最近有小伙伴在面试美团,又遇到这一个问题。小伙伴支支吾吾的说了几句,卒。

所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V171版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,回复:领电子书

分库分表背景知识

问题1:为什么分库分表?

大家都知道,当一个表(比如订单表) 达到500万条或2GB时,需要考虑水平分表。

为啥? 读写并发高场景,单服务器单一数据库CPU、内存、网络IO压力大。

所以,需要分库,一个库拆成多个库。

同时,数据量大,单表存不下,需要分表,一张表拆分成多个表。

总之,分库分表的原因是:

  • 数据量大,选分表;

  • 并发高,选分库;

  • 海量存储+高并发,分库+分表。

具体实操,请参考尼恩的硬核架构视频

问题2:如何做数据库水平拆分?

分库和分表, 主要还是 对数据的水平拆分,对数据的垂直拆分的重要程度弱太多,所以这个不做介绍。

水平分片又称为横向拆分。

相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。

例如:根据主键分片,偶数主键的记录放入0库(或表),奇数主键的记录放入1库(或表),如下图所示。

在这里插入图片描述

水平分片从理论上突破了单机数据量处理的瓶颈,并且扩展相对自由,是数据分片的标准解决方案。

对数据的水平拆分 ,核心的设计是:

  • 1: 用哪个字段拆分表,
  • 2: 用什么路由策略寻找目标库表。

分片键的设计目标、建议

数据库水平拆分的字段叫分片键。分片键也称为 Sharding key

关于分片键的选择,我们需要选择具有共性的字段是最基本的要求,也是就尽量能覆盖绝大多数查询场景。

同时分片键也应具有足够庞大的基数以及唯一性,从而使 Shard 可灵活规划,具备较好的扩展性。

举个反例,如果选取布尔类型的字段为分片键,那么分片最多只能存在两份,这就陷入了非常尴尬的局面,基本失去了 Sharding 的意义。

如何做 Sharding key的设计呢?

  • 最常见的情况是:用表的单个字段做分片键,

  • 复杂情况是:可以用两个或多个字段组合成分片键。

Sharding key的设计目标:

合理选择 Sharding key,避免大多数的查询变成重量级操作,比如:

  • 跨库查询
  • 全表路由

40岁老架构师尼恩的建议是:

  • 合理选择 Sharding key, 尽一切可能减少 全表路由、跨库查询,
  • 从而使得大部分查询在 单库实现结果闭环,从而减少 多库之间大的数据合并和二次排序, 从而提升分库分表的吞吐量和性能。

分片键的设计建议:

  • 选择具有共性的字段作为分片键,即查询中高频出现的条件字段;
  • 分片字段应具有高度离散的特点,分片键的内容不能被更新;
  • 可均匀各分片的数据存储和读写压力,避免片内出现热点数据;
  • 尽量减少单次查询所涉及的分片数量,降低数据库压力;
  • 最后,不要更换分片键,更换分片键需重分布数据,代价较大。

分片键的设计原则

  • 选择查询频率最高的字段

    分片键要能覆盖绝大多数查询场景,它决定了数据查询的效率。

    正例:单号,id,时间字段

    反例:姓别、商品类别

  • 分片键不可以更新

    分片键如果更新了,按原来的路由算法会计算出不同的库表地址,旧的数据无法正确读取

  • 分片键不可以更换

    分片键更换,意味着数据要重新分布,代价昂贵。

  • 分片字段应有离散特性

    分片键越离散,越容易把数据均匀分布在不同库表。

分片键的设计方案

按分片键的查询可以直接定位到目标库表,那么不按分片键的查询,是否只能遍历所有库表了呢?

举例:

  • 电商领域有用户表和订单表。

  • 订单表按订单号分库分表,

  • 同时订单表有用户id字段。

假如查询某个用户(比如user-id=200)的订单,怎么查呢?

此时,如果无法预知这个用户的数据存在订单的哪个库表,那么,其实就需要走 全表路由, 把请求路由到 这个表的所有的数据分片。

全表路由 具体如下图所示:

在这里插入图片描述

前面讲到,Sharding key的设计目标:

合理选择 Sharding key,避免大多数的查询变成重量级操作,比如:

  • 跨库查询
  • 全表路由

合理选择 Sharding key, 尽一切可能减少 全表路由、跨库查询, 从而使得大部分查询在 单库实现结果闭环,从而减少 多库之间大的数据合并和二次排序, 从而提升分库分表的吞吐量和性能。

如何去掉这里的 全表路由,提升查询效率呢?

针对这种非分片键的查询,有几种设计思路提升查询效率:

1 索引法

索引法的思路是,把非分片键和分片键的映射关系保存起来,

查询数据时,先从这个映射关系查找分片键,再用分片键路由到目标库表。

  • 索引表

    额外建一张表保存订单号和用户id的映射关系。

在这里插入图片描述

优点:实现简单

缺点:

  • 查询数据多查一次索引表,性能低。

  • 索引表可能会很大,甚至索引表本身要分表。

缓存映射关系

尼恩的3高架构宇宙中,有一条亘古不变的天条: 性能不够,缓存来凑。

既然索引表性能低,那么 用Redis保存订单号和用户id的映射关系。

在这里插入图片描述

优点:查询速度比索引表快。

缺点:数据量大时,占用大量内存,缓存不断淘汰,命中率低,没有命中缓存还是得查索引表。

无论是用索引表还是用Redis,都无法在大数据量下有效查找分片键。

2 基因法

基因法的思路是,把非分片键到分片键的映射关系内嵌在非分片键字段,嵌入到非分片键的这部分内容就是基因。

基因法是大厂常常使用的方案,

比如,将买家 ID 融入到订单 ID 中,作为订单 ID 后缀。这样,指定买家的所有订单就会与其订单在同一分片内了,如下图所示。

在这里插入图片描述

再具体一点:

  • 假如订单表用订单号%16路由,分16库表。

  • 用户下单生成订单号时,订单号的最后4个bit位,通过位运算,设置为用户id的最后4bit位,那么,订单号的最后4个bit位就是订单号的用户基因。

此情此景,如果在 查询某个用户的订单,就不用全表路由了。

现在是单片路由,直接根据用户id的最后4bit位,路由到订单的目标库表。

在这里插入图片描述

3 基因法的理论基础

如果对一个10进制的数字按10取模,取模的结果只与这个数字最后1位有关:

199%10=9

19999%10=9

1234567899%10=9

同理,按100(10^2)取模,取模的结果只与这个数字最后2位有关:

199%100=99

19999%100=99

1234567899%100=99

同理,一个二进制的数字,按2^n取模,只与这个数字最后n位有关:

例:n=3,2^3=1000

10001111%(1000)=111, 即十进制的143%8=7

10011111%(1000)=111, 即十进制的159%8=7

因此,订单表用订单号%16分库分表,对16(2^4)取模的结果只和二进制订单号的最后4位有关,这4位决定了数据落在哪个库表上。

4 数字类型的分片键设计

假如订单号是雪花算法生成的long类型数字,要在雪花算法的64个bit位中预留4位,用uid的后4位填充。

在这里插入图片描述

5 字符串类型分片键设计

假如订单号是一个字符串,将uid后4bit位转为字符串后拼接在订单号后面即可。

按某个业务规则生成的订单号:ORDER20240101

带有uid基因的订单号:ORDER20240101-0,ORDER20240101-15

在这里插入图片描述

6 基因法的优缺点:

  • 优点:无论按照分片键还是按某个非分片键查数据,都可以直接定位到目标库表,性能比索引法高。

  • 缺点:需要提前规划好库表容量,不方便扩容。

扩展方案设计:多个非分片键的组合查询

基因法解决了单个非分片键的数据查询路由问题,减少了全表路由的出现。

但是,如果有多个非分片键查询,是否要在分片键中融入多个基因呢?

No。

分片键的设计不应过于复杂,况且,即使能融入多个基因,又如何支持多个非分片键组合条件查询呢?

数据库不支持任意字段任意组合的高性能查询,这不是数据库的长项,应该用ES、ClickHouse等其他中间件来解决这类问题。

具体方案,请参见尼恩的文章:

字节面试:百亿级存储,怎么设计?只是分库分表?

说在最后:有问题找老架构取经

分库分表问题是高频问题,面试的时候如果大家能对答如流,如数家珍,基本上 面试官会被你 震惊到、吸引到。

最终,让面试官爱到 “不能自已、口水直流”。offer, 也就来了。

在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典》V174,在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。

另外,如果没有面试机会,可以找尼恩来帮扶、领路。

  • 大龄男的最佳出路是 架构+ 管理
  • 大龄女的最佳出路是 DPM,

在这里插入图片描述

女程序员如何成为DPM,请参见:

DPM (双栖)陪跑,助力小白一步登天,升格 产品经理+研发经理

领跑模式,尼恩已经指导了大量的就业困难的小伙伴上岸。

前段时间,领跑一个40岁+就业困难小伙伴拿到了一个年薪100W的offer,小伙伴实现了 逆天改命

另外,尼恩也给一线企业提供 《DDD 的架构落地》企业内部培训,目前给不少企业做过内部的咨询和培训,效果非常好。

在这里插入图片描述

尼恩技术圣经系列PDF

  • 《NIO圣经:一次穿透NIO、Selector、Epoll底层原理》
  • 《Docker圣经:大白话说Docker底层原理,6W字实现Docker自由》
  • 《K8S学习圣经:大白话说K8S底层原理,14W字实现K8S自由》
  • 《SpringCloud Alibaba 学习圣经,10万字实现SpringCloud 自由》
  • 《大数据HBase学习圣经:一本书实现HBase学习自由》
  • 《大数据Flink学习圣经:一本书实现大数据Flink自由》
  • 《响应式圣经:10W字,实现Spring响应式编程自由》
  • 《Go学习圣经:Go语言实现高并发CRUD业务开发》

……完整版尼恩技术圣经PDF集群,请找尼恩领取

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1799429.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nginx 配置防护 缓慢的 HTTP拒绝服务攻击+点击劫持:X-Frame-Options未配置

一 安全团队检测网站 1 检测到目标主机可能存在缓慢的HTTP拒绝服务攻击 缓慢的HTTP拒绝服务攻击是一种专门针对于Web的应用层拒绝服务攻击,攻击者操纵网络,对目标Web服务器进行海量HTTP请求攻击,直到服务器带宽被打满,造成了拒绝服务。 慢…

Spring Security系列之PasswordEncoder

概述 任何一个登录系统的密码不能明文存储,万一发生数据库泄漏事故(不管是内部人员导出数据库数据还是被黑客攻击破解数据库实例节点拿到数据库数据等,又或者是其他情况造成的),将产生巨大的损失。因此明文密码在存储…

Scanpy(4)用与数据整合和批次处理

Scanpy包,用与数据整合和批次处理,包含批次效应的BBKNN算法和用于对比的ingest基础算法比较,及其原理简介。 1. 依赖: (1)数据集(全部需要挂VPN): PBMC:pbmc3k_processed()(需要下载);pbmc68k_reduced()(scanpy自带)Pancreas(需要下载)(2)Python包:Scanp…

后端进阶-分库分表

文章目录 为什么需要分库为什么需要分表 什么时候需要分库分表只需要分库只需要分表 分库分表解决方案垂直分库水平分库垂直分表水平分表 分库分表常用算法范围算法hash分片查表分片 分库分表模式客户端模式代理模式 今天跟着训练营学习了分库分表,整理了学习笔记。…

Skins

本主题解释如何将DevExpress主题/皮肤应用到应用程序中,如何允许用户在运行时在主题之间切换,如何自定义现有皮肤或创建自己的皮肤,等等。 WinForms订阅包括许多基本控件:按钮、复选框、表单、消息框、对话框、对话框等。 我们实现…

CodeMirror 创建标签计算编辑器

在日常开发中对于一些数据计算场景可能会遇到标签计算的需求&#xff0c;下面关于如何使用CodeMirror实现标签计算编辑功能。 1&#xff0c;结果图 2&#xff0c;主体代码逻辑 大家只需要复制粘贴主要codeMirror使用逻辑即可 <template><el-dialogref"dialogRe…

【电路笔记】-分贝

分贝 分贝是以 10 为底的对数比,用于表示电路中功率、电压或电流的增加或减少。 1、概述 一般来说,分贝是响度的度量。 在设计或使用放大器和滤波器电路时,计算中使用的一些数字可能非常大或非常小。 例如,如果我们将两个放大器级级联在一起,功率或电压增益分别为 20 和…

qmt量化交易策略小白学习笔记第18期【qmt编程之获取对应周期的北向南向数据--方式2:原生python】

qmt编程之获取对应周期的北向南向数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 获取对应周期的北向南向数据 提示 该数据通过get_market_data_ex接口获取获取历史数据前需要先用downl…

力扣303. 区域和检索 - 数组不可变

Problem: 303. 区域和检索 - 数组不可变 文章目录 题目描述思路复杂度Code 题目描述 思路 创建前缀和数组preSum&#xff0c;其中preSum[i]处元素值为nums[0] - nums[i - 1]处元素值得和&#xff0c;当调用sumRange函数时直接返回preSum[right 1] - preSum[left] 复杂度 函数…

通过U盘将第三方软件安装到各大品牌电视的方法

在本教程中&#xff0c;小武给大家整理了通过U盘的方式安装第三方软件到电视盒子上&#xff0c;可直接使用通用U盘的方式来进行安装。 如果您相应电视品牌按通用方式无法完成需求&#xff0c;下面为您也贴心整理了20款主流智能电视和电视盒子的U盘安装指南。这些步骤适用于小米…

MSP430单片机控制流水灯,Proteus仿真

作品功能 本项目利用MSP430单片机控制一个简单的流水灯&#xff0c;通过按键切换流水灯的模式。用户可以通过按键控制LED灯的方向&#xff0c;从左向右或从右向左依次点亮。 作品的硬件材料 MSP430单片机 具体型号&#xff1a;MSP430G2553 LED灯 数量&#xff1a;8个类型&…

一篇文章讲透排序算法之归并排序

0.前言 本篇文章将详细解释归并排序的原理&#xff0c;以及递归和非递归的代码原理。 一.概念 归并排序是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使…

[消息队列 Kafka] Kafka 架构组件及其特性(二)Producer原理

这边整理下Kafka三大主要组件Producer原理。 目录 一、Producer发送消息源码流程 二、ACK应答机制和ISR机制 1&#xff09;ACK应答机制 2&#xff09;ISR机制 三、消息的幂等性 四、Kafka生产者事务 一、Producer发送消息源码流程 Producer发送消息流程如上图。主要是用…

【Python】使用Gradio作为机器学习web服务器

在机器学习领域&#xff0c;模型的展示和验证是一个重要的环节。传统的模型展示方式往往需要复杂的Web开发知识&#xff0c;这对于许多机器学习研究者或数据科学家来说可能是一个挑战。然而&#xff0c;Gradio的出现为我们提供了一个简单而强大的解决方案&#xff0c;让我们能够…

ffmpeg视频编码原理和实战-(2)视频帧的创建和编码packet压缩

源文件&#xff1a; #include <iostream> using namespace std; extern "C" { //指定函数是c语言函数&#xff0c;函数名不包含重载标注 //引用ffmpeg头文件 #include <libavcodec/avcodec.h> } //预处理指令导入库 #pragma comment(lib,"avcodec.…

【Week-R2】使用LSTM实现火灾预测(tf版本)

【Week-R2】使用LSTM实现火灾预测&#xff08;tf版本&#xff09; 一、 前期准备1.1 设置GPU1.2 导入数据1.3 数据可视化 二、数据预处理(构建数据集)2.1 设置x、y2.2 归一化2.3 划分数据集 三、模型创建、编译、训练、得到训练结果3.1 构建模型3.2 编译模型3.3 训练模型3.4 模…

虚拟机Ubuntu 22.04上搭建GitLab操作步骤

GitLab是仓库管理系统&#xff0c;使用Git作为代码管理工具。GitLab提供了多个版本&#xff0c;包括社区版(Community Edition)和企业版(Enterprise Edition)。实际应用场景中要求CPU最小4核、内存最小8GB&#xff0c;非虚拟环境。 以下是在虚拟机中安装社区版步骤&#xff1a;…

C++青少年简明教程:C++函数

C青少年简明教程&#xff1a;C函数 C函数是一段可重复使用的代码&#xff0c;用于执行特定的任务&#xff0c;可以提高代码的可读性和可维护性。函数可以接受参数&#xff08;输入&#xff09;并返回一个值&#xff08;输出&#xff09;&#xff0c;也可以没有参数和返回值。 …

应用层——HTTP协议(自己实现一个http协议)——客户端(浏览器)的请求做反序列化和请求分析,然后创建http向响应结构

应用层&#xff1a;之前我们写的创建套接字&#xff0c;发送数据&#xff0c;序列化反序列化这些都是在写应用层 我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层 之前的网络计算机是我们自定义的协议&#xff1a;传输的数据最终是什么样的结…

Redis缓存(笔记二:Redis常用五大数据类型)

目录 1、Redis中String字符串 1.1 常用命令解释&#xff1a; 1.2 原子性 1.3 具有原子性的常用命令 1.4 String数据结构 1、Redis中String字符串 概念 String 是 Redis 最基本的类型&#xff0c;可以理解成与 Memcached 一模一样的类型&#xff0c;一个 key对应一个 value…