粉丝8.3万获赞79.2万

在加号开发中,不知道你们会不会写这种 c 口,使用多了法,他会存在 c 口注入问题,也就是说在前端传唱时去指定一些特别的参数,这样我们就可以去修改这条 c 口,因为他是直接去替换我们的参数,他不会像井号那样是个站位符, 这也是常见的面试题。然后我们来演示一下这个 c 口注入问题,在 gap 上面有这么一个工具叫 c 口注入问题,他可以帮我们去测试 c 口注入问题,并且他的新鲜数也是很高的。然后回到我们项目中, 嗯,我们在这里打开我的终端,首先你需要去下载 sic map 这个工具,嗯,然后通过这条命令去执行,这是我后端的一个接口,然后这个参数是随便查的,然后我们在这里去执行一下, 这里能获取到我们这个接口是否存在 secret 注入问题,如果说有问题的话,它这里会显示 我们的数据库版本。然后我们也可以去直接获取到我们数据库的账号密码,我们这里来先来获取数据库的一个账号,这里就会去拿到我们的一个入特以及其他的一些账号。如果说想要去查看密码的话,我们可以通过 password 这里就能解析出我们数据库的入土账号密码是入土,可以看到这个工具还是很强大的。然后我们来说一下如何去解决这个 sq 安全问题,我把鼠标放在这个上面,这里会提示我们这里存在 sic 注入问题,然后我们看一下这个, 他能帮我们去自动的去修改这个,这里就会看到我们修改出来的 c 口是这样的,他会帮我们的多了符号,改成我们相关的井号。我这里是使用的 i 调中的一个插件,这个插件是这个啊,通过安装完这个插件之后,他可以 帮我们去扫描家务项目中存在的安全问题,并且提供了一键修复功能。快去扫描一下你的家务项目吧,说不定是一大坨。警告,在入职第一天,建议你们不要去扫描公司的项目,不然的话你们可能当天就想离职了。


好,接下来我们看一下怎么在 spring 阿里巴巴 agent 的 framework 里面往 tool 去传递当前的上下文。 我们来说一个场景啊,比如说我们当前的用户进行了登录,然后通过大模型进行对话和调用了 tool, 那 么在这个 tool 当中呢,我想根据当前登录的用户来获取一些数据,比如说 usid 啊, 或者 username, 怎么获取呢?那听过之前徐老师讲的 siri 系列课程啊,大家应该知道,我是通过 inheritable siri local 来获取的。那我这里整理了一套 java 程序员学习 ai 的 完整学习路线图,加完整学习视频加配套代码笔记加配套的项目实战,从大模型选型到微调,再到 ai 开发 agent 的 框架,最后到项目实战,你像智能客服 reg 知识库, 首都小龙虾垂直 agent 的 workflow 流程开发,最后到部署。为了让大家更好的去面试呢,还整理了一套 java 家 ai 的 高频面试资料,通通无偿分享,需要的小伙伴留下 ai 就 行。但是在阿里巴巴 agent 的 workflow 当中可以做到吗?我们来测试一下。好吧,我先说结论啊, 在错方法当中是可以的,但是在流式请求 stream 是 不可以,来我们看一下。好吧,那么当然有同学啊,他遇到过这样的一个问题,呃,他在这个 react agent 的 病里面啊, 去设置那个啊, serata, 这里面是不能去设置的,因为你要知道这个 add 并的方法它是在什么时候运行的,它是在 spring boot 的 启动的时候运行的,而我们用户请求对话的时候, 请求对话大模型的时候,它又是另外一个县城啊,这肯定是不同的县城,你再怎么通过 siri 的 logo 或者 inheritable siri 肯定都不行,好吧,所以记住啊,不是在这个配置 react 并里面去配置, 我们要在对话的时候啊,再去配置,好不好?那么在这里啊,为了去模拟这个对话,我们用一个单元测试,当然你也可以自己写一个 control 了来去测试,好吧,我们用单元测试更方便一点来,比如说我在当前的 这个 tool 里面,好吧,我们存储当前的这个啊 user id, 好 吧,然后呢,我在这个 tool 里面啊,我就直接打印一下, 好吧,在实际的这个应用当中呢,我们肯定会根据当前的 user id 来获取对应的一些数据。完了之后呢,我们在这个用户对话的时候,我们进行缓存,我忘记把那个访问权限啊,给它改成 public static 来, 再回到刚刚的代码,我们去设置,比如我设置一个当前的登录人,假设是虚入,好吧, 那我们在这里呢,通过调用或方法,也就是同步的方式去请求我们来看一下能不能正常地获取到呃,这个 to 里面的 setlocal 的 值,好吧,那么这里的这个注意啊,这里的这个 react agent 我是 在上面 配置的一个并,对吧?所以我在这个单元测试里面呢,直接自动注入进来,呃所,呃,那么在上面呢,我已经 绑定了这个 tool, 好 吧,我只需要去请求一个查询天气,那么它就会去调用这个 tool 了。 ok, 那 么我们这里代代码去请求的也是查询,比如说北京的天气,对吧,它就会去调用对应的那个 tool, 我 们来看一下能不能正常获取到啊?来, 你看这里呢,就正常地输出了,说明呢,我们通过 tool 方法用 third 对吧? serverlocal 肯定是没有问题的,那么你用 incorridable serverlocal 肯定也是没有问题的。好吧,这个我就不去测了,但是如果我们换成 stream, 好 吧,我们换成 stream 的 话,这里你想一下它能获取到吗?我们之前测试 spring ai 当中,它是可以正常的。我们来看一下阿里巴巴 agent framework, 它能不能正常地获取到答案呢?获取不到, 好吧,因为我刚刚已经说了嘛,好吧,这种方式,无论你是 seruo 还是 incurable, 也就是这种子父现成的都不可以,你看这里获取不到,对吧?它输出为 non。 所以 我们完全可以得出一个结论, 在阿里巴巴 a 证的宏观里面,通过扩方法,它去执行大模型,然后再去调用,整个过程呢,它都是用的同一个现成,对不对? 那么我们用 stream, 很 明显,它在调用大模型和 for 的 过程当中呢,明显就不是同一个县城了,那么用这种方式呢,就 获取不到,它就丢失了。所以在这里呢,我建议大家,我们可以采用阿里巴巴 agent 的 from mark 单独提供的这个 runnable config 来进行传递。 来,我给大家演示一下。那么之前呢,我们通过这个 runnable 统 fig 给大家演示了不同的聊天记录, 进行隔离,这样的一个效果对不对?我们用的是什么?用的是 siri 的 id, 对 吧?比如说我在这个 siri 的 id 当中呢,去设置一个唯一的标识,我们通过这个就可以去隔离不同,你可以作为将用户 id 作为不同的一个呃分离的维度,也可以将比如说绘画的 id, 不 同的绘画窗口作为不同的唯一标识去隔离聊天记录,聊天记录, 好吧,然后我们在啊对话的时候啊,在对话的时候就需要把这个 group 给它传过去,这是第一步 传递 runnable 宏 big, 然后第二步我们需要在这个 word 当中把这个 function 接口啊给它改成 b i function。 为什么要改成 b i function 呢?因为 b i function 啊,它多了一个环形,我们就可以在这里呢 去接收一个叫做 tool context, 也就是工具的上下文,然后你就可以在下面的这个作方法,我们接收这个 tool context, 好 吧,也就是这个 b i 方式啊,它有三个范型,一个用来规定我们的 呃接收的数据的参数,第二个就是指定 to o config, 然后第三个参数指定这个方法的返回值, ok, 那 么通过这个 to o context, 那 么我们就可以呢 get context, 然后呢 去获取一个叫做这个 agent 的 config, 这个常量好不好,那么我们就可以呢给它转换成 runable config, 那 么进而呢, 我们就可以从这个 runnable config 里面去获取到那个 thread id, 好 吧,那么这里的这个 threadlocal 我 们就可以去掉了,因为这种方式它不起作用嘛。好吧,我注视一下这种方式,它在呃 string 方式里面呢不起作用, 当然我不知道它是故意为之,还是说啊,这是一个以后会改进的地方,我们这个就不往下面去深究了,只需要知道现在的版本呢,它这种方式不起作用, 我们可以通过这个 to contest 来进行完毕,好吧, ok, 来,我们再去请求一下看一下啊,刚刚那个代码,我需要把这个 server log 赋值给它去掉,好吧, 好,我们再运行看一下,所以记住这几步,第一步我们去申明一个 runnable config, 然后在呃调用 agent 的 时候呢,把它传进去,然后就可以在这个 tool 当中 通过我们的 tool context 来去获取。 ok, 我 们来看一下结果。哎,这里报错了 哦,我们这里获取的这个场量不对啊,好吧,我刚刚应该是是这个 config 的 场量,好吧,是这个 config 的 场量刚刚弄错了。来,我们再重新运行一下,来, 我们可以看到在这里呢,它就输出了一个 optional 类型的,里面就有虚数了,对不对?那么这样呢,我们就可以进行 tool 的 一个上下文的传递 啊,当然算到这里啊,其实我们还可以进行一个改进,假如说啊,现在我们隔离聊天记录用的不是用户的 id, 比如我们用的是, 对吧?绘画的 id, session 的 id, 我 随便说一个,好吧,我们假设就是这个就是 session id, 那 这个 sir 的 id 它被占用了, 那我怎么传递用户 id 呢?对吧?毕竟这个 server 的 id 它只能传一个,我不可能给它拼接上去吧,对吧,这也太蠢了。实际上它还提供了一个叫做啊 meta data, 好 吧,我们可以通过 add meta data 呢,来单独的去添加需要传递的这样的一个原数据,好吧,在这里你就可以呃去维护任意的 t y 里的一个数据了,好吧,比如说 use id, 那 么对应的,当然在那个 tool 当中,你也是需要 通过那个 meta data 来去获取,好吧? user id, ok, 好 吧,所以,呃,正常的方式呢,我们应该是通过 meta data 来进行传递会更加的合理,因为你也不知道不确定 这个用来隔离聊天记录的它会设置什么,对吧? ok, 那 这就是我们怎么通过这个 tool context 来传递 上下文。当然除了去设置一些原数据用户 id 以外,其实这个 tool context 里面啊,它还可以去获取我们 当前的这个聊天记录,比如说你从里面啊去获取这个 state, 好 吧,这个 state 呢,它属于阿里巴巴 graph 当中的一个概念, 里面它其实就存储了我们当前的一个啊聊天记录,你就可以在这个里面呢来进行获取。 ok, 我 这个笔记里面呢也都有,我就 不给大家啊去演示这个了,我直接把这个呢拿出来,好吧,我们可以调试,给您调试看一下里面的数据是什么样的。 好,来,你看这个 state 里面啊,它里面就包含了,你看包含了我们用户的提示词,对吧?还包含了大模型的响应提示词 啊,当然这里的大模型呢,是 cool cos, 也就是代表呢,它需要请求的是啊,错,然后里面就包含请求的错的名字,然后呢里面的参数北京,对吧? 所以如果你还想在 to 当中去获取一些例子的聊天记录,那可以通过这个常量,好吧,这个带了 state 的 这个常量呢来进行获取, ok, 好, 那这个关于工具的上下文传递,我就给大家讲到这里。

简历我先不看了啊,就是先问你一个最基础的问题啊,就是,呃,我们知道 h d 的 请求啊,它有很多类型,比如说 post, get 对 吧?然后以及 delete。 呃,那 post 跟 get 它们的区别在哪里?然后平时开发的时候你会怎么选?嗯, get 是 拿数据的, post 是 发数据的,然后 get 参数在 u r l 里面能看见, post 的 话藏起来的,别的我 我记不太清的。嗯,那照你这么说,那我用 post 我 去查数据,我就查不了了吗?那假如说我去查数据,我需要一个对象,那那怎么办呢?那 get 我 也能提交数据啊,你即使通过 u r l 给我对吧,我也是能提交的呀。如果你担心简历上的东西讲不出来,我已经把面试经常问到的一些技术站 场景图都整理在两百万字的面试文档了,里面针对每个知识点都有很详细的解答。带走 ok? 其实啊,这两个的本质呢,都是 http 请求的方法 层呢,都是走的 t c p 连接。呃,根本呢,没有什么功能上的一个本质区别啊,你想拿 get 提交数据,用 pos 查数据,在语法上面呢,也完全没有问题。 那为什么大家平时有一些默认的使用规范呢?主要有几个差异,第一个它的参数与安全性, get 的 参数直接是拼在 u i l 后面的,那么谁都能看见,而且啊,浏览器它对 u i l 的 长度是有限制的,一般是二到八 k。 每个浏览器啊,它们的限制呢,可能不 一样啊,所以它传不了很大的数据类型,也不能传像密码这种敏感的信息。那 pos 的 参数呢,是放在请求体里面的,它长度是没有限制的,相对来讲呢安全 很多。而第二个呢,就是缓存的特性,我们 get 请求浏览器啊会默认去用缓存,下次访问同一个地址直接去读缓存速度啊,会非常快,那么很适合像查询场景,比如说啊列表查详情,那 pos 呢,默认是不会缓存的,每次啊都会把请求发给服务器, 所以啊适合提交修改这种有数据写入的操作。第三个啊,就是操作的影响, get 请求的页面啊,后退刷新都没有影响那 post 请求的页面,你一刷新就会去提示你重新提交表单,你平时付完钱啊,刷新网页弹的提示就是这个原因, 很容易啊,造成像重复付款等等的一些问题。那第四个呢,就是数据类型的支持 get 啊,它只能去传 ask 码,然后传中文,还要编码那 post 请求,它是支持所有数据类型的,包括像二进制,所以影像上传文件也好,传图片也好,都可以用 post。

过去沉睡习惯写一种倒装语法,像这样这种表达式有个专属名字叫尤达表达式,名字来自星球大战里说话总颠倒语气的绝地大师尤达。我们完全可以翻译为山东表达式。当年是为了防止语法错误 才把常量放前面。如今 ai 成了写代码主力军,早就把基础语法错误彻底消除,有答表达式也随之退出历史舞台。借助专业的 ai 编程工具,不仅可以避免基础语法错误,甚至还能自动检测并修复 checkstar 违规静态分析问题。 推荐使用非算 java 内置的 java 整洁器,只需一键就能自动简化表达式,统一代码风格,自动修复 text style 违规代码瞬间干净规范,告别荣誉写法,提升效率,就是这么简单!我是秋秋,关注我,带你了解更多好用的 ai 编程工具!

二年经验面美团面试官问,你们公司的订单表有两亿数据,怎么做的?分库分表,他八股背的滚瓜烂熟。简单,我们按用户 id 储模分了十六个库,每个库六十四张表,一共一千零二十四张表。这样用户查自己的订单特别快,直接定位到具体的表面,士官点了点头,反手就是一个绝杀。 那商家要查自己店铺的订单列表怎么办?商家又没有 u a d, 按你的分法,商家查一次岂不是要扫描全部一千零二十四张表?这系统能不崩?这一问直接把他问哑火了。假如这道题目你也不会回答的话, 我整理了让大厂 hr 沉默的必考题目,囊括各大厂前后端高频面试题,八股文和场景题都有,扣 pdf 就 拿走。 其实分库分表不仅仅是把数据切开这么简单,难点永远在于切开后怎么聚合。今天就结合最经典的电商订单场景,带你从切分维度到多维查询,彻底打通路库分表的任督二脉。一、 什么时候该分,别张嘴就是两千万。面试里问什么时候分库分表,很多人上来就被阿里开发手册说,单表超过五百万行或者两 gb 就 要分, 这太较调了。现在的硬件单表跑个一千万数据锁引建好了照样飞快。真正逼你分库分表的通常不是存储容量,而是连接数和维护成本。连接数瓶颈, 一个 micro 实力的连接数是有限的。当并发 qps 极高,所有请求都打到一个主库,数据库连接池瞬间被打爆。这时候必须分库来分摊并发写压力 ddl 痛苦, 给一张五千万行的表加个字,断你试试,锁表能锁到你怀疑人生,业务直接停摆。这时候必须分表来降低单表大小。 建议大家面试时可以说,虽然手册建议五百万,但我们实战中通常在八百万到一千万区间开始规划,优先考虑硬件升级,实在扛不住了再拆,因为分库分表的代码维护成本极高。二、核心架构切分为度的不可能三角回到开头的死局,按 user id 分, 商家没法查。按 merchant id 分, 用户没法查。 这在架构设计上叫多维查询难题。我们有三种打法一、一购缩影表最通用的解法, 既然切分为度不能兼顾,那就用空间换时间。 c 端主库依然按 urd 百分号十六分片,用户查订单快如闪电。 b 端再搞一套商家库数据,按 merchants id 百分号十六分片 同步机制,用户下单写入用户库成功后,异步把数据同步移分到商家库。面试官一定会追问,如果消息发送失败或者消费者挂了,商家库岂不是一直少订单?满分回答,为了保证最终一致性,我们通常采用 rocket milk 事务消息或本地事务表加定时轮询模式。 事务消息利用 mq 的 半消息机制,确保本地订单入库和消息发送要么同时成功,要么同时失败。兜底重试,配合定时任务扫描未确认的消息,确保 at least once, 保证商家库绝对不会丢单。 解法二,基因法解决 id 查询痛点很多同学会忽略一个场景,用户输入订单 id 查询订单详情,如果只按 user 下滑线 id 分 片,系统拿到 order 下滑线 id 后,根本不知道去哪个库查,只能广播查询,效率极低。这时候要用基因法假设我们分了十六个库 提取基因,假设用户 id 是 幺零零八六二,进至最后四位是零幺幺零,植入基因,生成订单 id 时不要随机生成,而是把这零幺幺零强行拼接到订单 id 的 最后四位。查用户下划线 id 百分号十六,结果是六。查订单 order 下划线 id 百分号十六, 因为末尾植入了基因,结果也是六。这样用户查自己和查具体订单都会稳稳地落在同一个库。加法,三大宽表加 es 终极兜底。如果运营人员要按下单时间、金额、地区等奇葩条件筛选, myico 分 库分表就彻底卸载了。 myico 只负责核心交易链路,按 user id 分 片,把数据通过 canal 加 mq 实时同步到 elastic search 商家查询,运营后台查询复杂报表全部走 e s。 追问, e s 不是 实时强一致的,如果商家刚收到新订单通知,点进去却在 e s 查不到怎么办?答,我们在代码层做了降级逻辑,当 e s 查不到结果时,系统会自动降级回 my secret 的 商家易购库进行点查,虽然后端压力大一点,但保证了用户体验的闭环。 三、面试官可能会提的追问 q, 一、 分表后的局 id 怎么生成?答,绝对不能用自增主见面试时推荐。答,美团 leave 的 号段模式相比于雪花算法,它不强,依赖机器时钟, 不会因为时钟回波导致 id 重复,更适合严谨的金融级业务。 q, 二、分表后怎么做深分页?答,这是分布式数据库的内存杀手,中间键需要去每个分片取钱,一万零十条聚合排序,性能极差。 解决方案有三,一、业务规避,禁止跳页,只允许下一页。二、 seek 有 标法,利用 where id lost underscore id limit 时的方式查询,利用缩影避开 offset 扫描。三、 es, 如果是极其复杂的身份页,直接走 e s。 四、面试标准答案模板,下次被问到如何设计分库分表,直接按这个逻辑输出设计分库分表。我的核心原则是业务驱动读写分离。一、分片策略,针对 c 端订单系统,我优先选择 user id 作为分片键,并利用基因法生成 order id, 保证用户查询和订单号点查的高效路由。 二、多维查询难题,对于弊端商家,我采用易购锁影方案,利用 rocket muq 事务消息实现数据的最终一致性同步,构建一套商家维度的分片库。三、复杂搜索,对于复杂的运营查询,直接引入 elastic search, 并设计了 myico 降级策略,应对 e s。 的 同步延迟。四、 id 与扩容 底层配合力炮段模式生成全局 id, 并预留了两倍扩容的方案,确保系统在未来三年内不需要伤筋动骨。 nice。

很多人都吐槽 java 代码啰嗦,比如在 java 里定义一个变量,还得把类型手写两遍,这纯纯是在浪费生命。其实不是 java 啰嗦,是你没有用对工具。 idea 的 postfix 后缀补全, 就是为了消灭啰嗦。写完代码,加个点,输入点 what? 自动推断类型生成变量,输入点 for 自动生成 for 循环演示如下, 以前敲十次键盘,现在只要敲三次,大大提升开发效率。不过 idea 自带的 postfix 模板还是太少了,只有这些, 想真正起飞需要装插件。它自带了更多开箱即用的模板,关键是还支持自定义模板。下面分享一下我配的这些模板,输入点 log 瞬间生成标准日期,不用再手敲 log, 点 if empty 自动对制,符串集合等判空。 这些模板配置,我导出成了一个文件打 postfix, 我 把这些年积累的王炸模板都送给你,全是实战中提炼出来的,导入就能用。关注我,下期分享 idea 另一个王炸技能, live template, 记得点赞关注哦!

同学们大家好,接下来呢我们来看一道来自于美团的面试题,什么是覆盖所引,对应的薪资呢是三十 k, 对 应的岗位呢是高级开发工程师,那么我们接下来呢就来看一下怎么回答这道面试题。 首先呢我们看一下覆盖锁影,它到底是什么啊?那么覆盖锁影呢,它是一种避免回表查询的优化策略,只需要在一棵锁影树上就能获取所所需的所有列数据,无需回表速度更快。那也就是说我们的这个覆盖锁影呢,它是在一棵锁影树上就拿到了我们所有所需要的数据 啊,那所谓的覆盖锁瘾呢?我们怎么去实现呢?他在实现的时候呢,就是我们将被查询的字段呢,建立这个什么?建立这个普通锁瘾或者联合锁瘾,这样的话呢,我们就能够什么呀,可以直接从我们的锁瘾数呢锁瘾数上去这个 得到我们想要的这个数据,而不需要通过什么通过咱们的那个主键锁瘾去定位行了记录,然后去查询啊,发生这种回表了,对吧?避免这种回表的情况, 那么也就是说我们再去进行这个查询的时候呢,我们应该呢尽量的将这个一些能够需要使用到缩影的这个列呢,咱们给它建立成什么呀?建立成这个复合缩影 啊,那比方说我们下面呢这条 sql, 我 查询了这么三个字段, u 的 name, u 的 h, u 的 level, 对 吧?那么我们再去进行查询的时候,如果说我们的这三个字段啊,它都存储在我们的这个,都是建立在我们的什么这个 一个联合锁瘾上的话,那么我们再去获取数据的时候,是不是说我们只查询这三个字段的这个呃,相关的这个数据信息的话,那么我们就能够直接从这个锁瘾树上把我们想拿到的这个数据是不是给它拿到啊? 对吧?这样的话呢,就可以什么呀,可以去避免了这个回表的发生, ok 吧?啊,那么覆盖锁瘾呢,它的 这个定义和注意事项在这里呢,我们还是要说一下的啊,如果一个缩影呢,它包含了所有需要查询的自断值,那就意味着干嘛呀?就不需要回表了,那这个缩影呢,我们可以把它叫做什么呀?覆盖缩影, ok 吧,可以把它叫做覆盖缩影。那么满错当中呢,只能使用 b 加速作为什么啊? b 加速缩影作为什么作为覆盖缩影 啊?因为呢咱们必加数呢,它是存储了什么呀?缩影的列值的,对吧?那能拿到值才能避免回表了,对吧?还有呢就是在我们的 explain 的 这个 else 列呢,如果出现了 u n x, 那 么它呢就表示呢使用到了这个什么覆盖缩影, ok 吧?哎,从这三点呢大家注意一下啊,在回答面试题的时候呢,我们这道面试题的时候呢,我们首先要把这个覆盖缩影它的定义说清楚,然后呢再说一下为什么使用覆盖缩影可以,可以什么呀?避免回表, 基本上基本上呢其实就没有问题了, ok 吧?哎,以上呢就是对于这道面试题的讲解啊,希望能够帮助到同学们。

有个粉丝啊,在群里吐槽说面美团被挂的心服口服。面试官问啊,你们公司订单表有两亿数据,怎么做到分股分表?他背的滚瓜烂熟。简单,我们用用户 id uzid 取模分的十六个库,每个库六十四张表,一共一千零二十四张表。 这样用户查自己的订单特别快,直接定位到具体的表。面试官点了点头,反手就是一个绝杀。那商家要查自己店铺的订单列表怎么办?商家有没有 uzid? 按你的分法,商家查一次岂不是要扫描全部的一年二四张表?这系统能不崩? 因为直接把它温压火。兄弟们,分分表哎,不仅仅是把数据切开这么简单,难点永远在于切开后怎么集合。 很多教程只教你切,不教你查。这是典型的管杀不管埋。今天 fox 就 结合最经典的电商订单场景,带你从切分为度到多维查询,彻底打通路股分表的人多二脉, 那什么时候该分?别张嘴就是两千万啊?面试,你问什么时候分股分表?很多人上来就背阿里开发手册说单表超过五百万毫或者两 gb 就 要分,这太较巧了,现在的硬件 s s d 加大内存,单表跑格,一千万数据啊,所以你建好了照样飞快。真正比你分库分表的通常不是存储容量,而是连接数和维护成本。 第一个,连接数瓶颈,一个麦赛口实力的连接数啊,是有限的,通常几千个当并发, qps 极高,所有的请求都达到一个主库预库连接池瞬间被打爆,这时候必须分库来分摊并发的写压力。 第二点, ddl 的 痛苦,给一张五千万行的表加个字段,你试试锁表,能锁到你怀疑人生,业务直接停板,这是我必须分表来降低单表大小。 boss 老师建议,面试时你可以说,哎,虽然手册建议五百万,但我们实战中通常在八百万到一千万区间开始规划优先考虑的代码维护成本高。 回到开头的死角,按 user id 分, 商家没法查。按 merchant id 分, 用户没法查,那在架构设计上叫多维查询难题,我们有三种打法,一种比一种高级。 减法一,易购所应表双写荣誉最通用的减法,既然切分为多,不能兼顾,那就用空间换时间。 在 c 单用户的视角,主库依然按 u、 z i、 d 或十六分片用户查订单快如闪电。在 b 单商家视角再搞一套商家库数据按照 erchat id 或十六分片, 那同步机制就是用户下单写入用户库成功后一步,把数据同步一份到商家库, 那这里你就要考阅双写一致性的坑。面试官一定会追问,如果消息发送失败,或者消费者挂了,单加库岂不是一直少订单 满分回答就是为了保证最终一致性。我们通常采用 rocket and call 事务消息,或者是本地事务表加定时流动模式, 是否消息,利用 m 扣的半消息机制,确保本地订单入库和消息发送要么同时成功,要么同时失败。那到底重试,哎,就是配合定时人物扫描未确认的消息确保,哎,至少投递一次,保证商家库绝对不会丢单。 那解法二就是基因法,解决 id 查询的痛点。很多同学忽略一个场景,用户输入订单 id 查询订单详情。如果只按 uzid 分 片,系统拿到 o 的 id 后,根本不知道去哪个库查,只能广播查询,全库扫描效率极低。这个时候要用基因法, 具体的逻辑就是,假设我们分了十六个库,需要四位二进制来定位。首先是提取基因,假设用户 id 是 幺零零八六二进制,最后四位是零幺幺零接十进制。六、 植入基因生成订单 id 时,不要随机生成,而是把这零幺幺零强行拼接到订单 id 的 最后四位。 那漏油规则就是,我查用户的时候, user id 模式六,结果为六。查订单的时候啊, old id 博十六,因为末尾植入了基因,结果也是六。 这样一来,用户查自己带 user id 和查具体订单带 old id 都会稳稳地落在同一个库上。注意啊,基因法解决不了商家查询问题,它专门用于优化非分片间 old id 的 点查询性能 改法,三大款表加 e s。 如果用微人员要按下单时间、额度、地区等奇葩条件筛选 icq, 分 不分表就彻底歇菜了。 icq 只负责核心交易链路存取改的状态。按 user id 分 片,把数据通过 caller 加 m code 实时同步到 e s。 商家查询运营后台查询复杂报表全部走 e s。 注意啊,这里有个降级策略,就是 es 不是 实时强抑制的,通常有一秒的延迟。如果商家刚收到新订单通知,点击却在 es 查不到怎么办?我们可以在单码层做降级逻辑,当 es 查不到结果或者数据明选之后时, 系统会自动降级回马斯克的商家易购库进行检查,虽然后单压力大点,但能够保证用户体验的闭环。 通过分表之后,哎,原本简单的 c 款会变成大坑,有三个点呢,必须守住。第一啊,分表后的全据 id 怎么升?绝对不能用 自增主见面试时推荐搭美团腻腐的耗蛋模式,相比雪花散粉,它不强,依赖于机器,始终不会因为始终回波导致 id 重复,更适合严谨的金融级业务。 第二,分表后怎么做身份页?这是分布数据库的内存杀手,中间键呢,需要去每个分片取钱,一万零十条聚合排序,性能极差。解决方案有三个, 第一个,业务上规避禁止跳页,只允许下页。第二个游标法,用 where id 小 于 last id limit 十的方式查询,利用啊缩影,避开 offset, 扫描第三个 es 的 score, 如果是极其复杂身份页,直接走 e s。 第三个问题,扩容怎么办?原本是这个扩不够用的,要扩到三十二个,那你也可以采用两倍扩容,却必须配合在线数据迁移 全量同步,将旧库数据全量搬入到新库,增量追平,利用开尔追平迁移期间产生的增量数据,注意校验全量比对一致后切流胆战切断,写入冰心漏油规则,将流量切到新库,这样能把对业务的影响 控制在最小。下次被问到如何设计风控表啊,直接按这个逻辑输出设计风控表。我的核心原则是业务驱动,读 第一,分片策略,针对 c 单订单系统,我优先选择 uzid 做分片件,并利用基因法生成 orderid, 保证用户查询和订单号点查的高效路由。 第二,多维查询难题。对于 b 单商家,我采用溢购所引的方案,利用 rockemq 事务消息实现数据的最终一致性同步,构建一套商家维度的分片库。第三,复杂搜索。对于复杂的运营查询,直接引入 e s 并世界 my secret 降级策略,应对 e s 的 同步延迟。四、 id 与扩容底层配合逆斧浩代模式生成全句 id, 并预留两倍扩容方案,保证系统在未来三天内不需要伤筋动骨。分分秒是程序员从 c r u d boy 迈向架构式的第一道坎, 不要为了分而分,能不分就不分,但一旦要分啊,就要把数据怎么进怎么出,怎么对齐,想的明明白白,技术没有银弹,全是取舍。觉得有用的兄弟点个赞收藏起来,万一下次面试就用上了呢?我是 fox, 只讲那些大厂面试官不告诉你的实战内幕。