订单中心,1亿数据架构,这次服了 糖太宗 • 2022年5月14日 上午12:55 • 技术 • 阅读 19 订单中心,是互联网业务中,一个典型的“多key”业务,即:用户ID,商家ID,订单ID等多个key上都有业务查询需求。 随着数据量的逐步增大,并发量的逐步增大,订单中心这种“多key”业务,架构应该如何设计,有哪些因素需要考虑,是本文将要系统性讨论的问题。 什么是“多key”类业务? 所谓的“多key”,是指一条元数据中,有多个属性上存在前台在线查询需求。 订单中心是什么业务,有什么典型业务需求? 订单中心是一个非常常见的“多key”业务,主要提供订单的查询与修改的服务,其核心元数据为: Order(oid, buyer_uid, seller_uid, time, money, detail…); 其中: (1)oid为订单ID,主键; (2)buyer_uid为买家uid; (3)seller_uid为卖家uid; (4)time, money, detail, …等为订单属性; 数据库设计上,一般来说在业务初期,单库,配合查询字段上的索引,就能满足元数据存储与查询需求。 (1)order-center:订单中心服务,对调用者提供友好的RPC接口; (2)order-db:对订单进行数据存储,并在订单,买家,卖家等字段建立索引; 随着订单量的越来越大,数据库需要进行水平切分,由于存在多个key上的查询需求,用哪个字段进行切分呢? (1)如果用oid来切分,buyer_uid和seller_uid上的查询则需要遍历多库; (2)如果用buyer_uid或seller_uid来切分,其他属性上的查询则需要遍历多库; 总之,很难有一个万全之策,在展开技术方案之前,先一起梳理梳理查询需求。 任何脱离业务需求的架构设计,都是耍流氓。 订单中心,典型业务查询需求有哪些? 第一类,前台访问,最典型的有三类需求: (1)订单实体查询:通过oid查询订单实体,90%流量属于这类需求; (2)用户订单列表查询:通过buyer_uid分页查询用户历史订单列表,9%流量属于这类需求; (3)商家订单列表查询:通过seller_uid分页查询商家历史订单列表,1%流量属于这类需求; 前台访问的特点是什么呢? 吞吐量大,服务要求高可用,用户对订单的访问一致性要求高,商家对订单的访问一致性要求相对较低,可以接受一定时间的延时。 第二类,后台访问,根据产品、运营需求,访问模式各异: (1)按照时间,价格,商品,详情来进行查询; 后台访问的特点是什么呢? 运营侧的查询基本上是批量分页的查询,由于是内部系统,访问量很低,对可用性的要求不高,对一致性的要求也没这么严格,允许秒级甚至十秒级别的查询延时。 这两类不同的业务需求,应该使用什么样的架构方案来解决呢? 要点一:前台与后台分离的架构设计。 如果前台业务和后台业务共用一批服务和一个数据库,有可能导致,由于后台的“少数几个请求”的“批量查询”的“低效”访问,导致数据库的cpu偶尔瞬时100%,影响前台正常用户的访问(例如,订单查询超时)。 前台与后台访问的查询需求不同,对系统的要求也不一样,故应该两者解耦,实施“前台与后台分离”的架构设计。 前台业务架构不变,站点访问,服务分层,数据库水平切分。 后台业务需求则抽取独立的web/service/db来支持,解除系统之间的耦合,对于“业务复杂”“并发量低”“无需高可用”“能接受一定延时”的后台业务: (1)可以去掉service层,在运营后台web层通过dao直接访问数据层; (2)可以不需要反向代理,不需要集群冗余; (3)可以通过MQ或者线下异步同步数据,牺牲一些数据的实时性; (4)可以使用更契合大量数据允许接受更高延时的“索引外置”或者“HIVE”的设计方案; 关于前台与后台分离的架构设计,在《用户中心,1亿数据架构,这次服了》一文中有更为细致的分析,便不再展开。 解决完了后台业务的访问需求,那前台的oid,buyer_uid,seller_uid如何来进行数据库水平切分呢? 要点二:多个维度的查询较为复杂,对于复杂系统设计,应该逐个击破。 假设没有seller_uid,应该如何击破oid和buyer_uid的查询需求? 订单中心,假设只有oid和buyer_uid上的查询需求,就蜕化为一个“1对多”的业务场景,对于“1对多”的业务,水平切分应该使用“基因法”。 要点三:基因法,是解决“1对多”业务,数据库水平切分的常见方案。 什么是分库基因? 通过buyer_uid分库,假设分为16个库,采用buyer_uid%16的方式来进行数据库路由,所谓的模16,其本质是buyer_uid的最后4个bit决定这行数据落在哪个库上,这4个bit,就是分库基因。 什么是基因法分库? 在订单数据oid生成时,oid末端加入分库基因,让同一个buyer_uid下的所有订单都含有相同基因,落在同一个分库上。 如上图所示,buyer_uid=666的用户下了一个订单: (1)使用buyer_uid%16分库,决定这行数据要插入到哪个库中; (2)分库基因是buyer_uid的最后4个bit,即1010; (3)在生成订单标识oid时,先使用一种分布式ID生成算法生成前60bit(上图中绿色部分); (4)将分库基因加入到oid的最后4个bit(上图中粉色部分),拼装成最终64bit的订单oid(上图中蓝色部分); 通过这种方法保证,同一个用户下的所有订单oid,都落在同一个库上,oid的最后4个bit都相同,于是: (1)通过buyer_uid%16能够定位到库; (2)通过oid%16也能定位到库; 关于“一对多”业务,以及“基因法”,在《帖子中心,1亿数据架构,这次服了》一文中有更为细致的分析,便不再展开。 假设没有oid,应该如何击破buyer_uid和seller_uid的查询需求? 订单中心,假设只有buyer_uid和seller_uid上的查询需求,就蜕化为一个“多对多”的业务场景,对于“多对多”的业务,水平切分应该使用“数据冗余法”。 如上图所示: (1)当有订单生成时,通过buyer_uid分库,oid中融入分库基因,写入DB-buyer库; (2)通过线下异步的方式,通过binlog+canal,将数据冗余到DB-seller库中; (3)buyer库通过buyer_uid分库,seller库通过seller_uid分库,前者满足oid和buyer_uid的查询需求,后者满足seller_uid的查询需求; 数据冗余的方法有很多种: (1)服务同步双写; (2)服务异步双写; (3)线下异步双写(上图所示,是线下异步双写); 要点四:数据冗余,是解决“多对多”业务,数据库水平切分的常见方案。 不管哪种方案,因为两步操作不能保证原子性,总有出现数据不一致的可能,高吞吐分布式事务是业内尚未解决的难题,此时的架构方向,是最终一致性,并不是完全保证数据的一致,而是尽早的发现不一致,并修复不一致。 要点五:最终一致性,是高吞吐互联网业务一致性的常用实践。 保证冗余数据最终一致的常见方案有三种: (1)冗余数据全量定时扫描; (2)冗余数据增量日志扫描; (3)冗余数据线上消息实时检测; 关于“多对多”业务,数据冗余多种方案,数据冗余保证最终一致性多种方案,在《好友中心,1亿数据架构,这次服了》一文中有更为细致的分析,便不再展开。 那如果oid/buyer_uid/seller_uid同时存在呢? 综合上面的解决方案即可: (1)如果没有seller_uid,“多key”业务会蜕化为“1对多”业务,此时应该使用“基因法”分库:使用buyer_uid分库,在oid中加入分库基因; (2)如果没有oid,“多key”业务会蜕化为“多对多”业务,此时应该使用“数据冗余法”分库:使用buyer_uid和seller_uid来分别分库,冗余数据,满足不同属性上的查询需求; (3)如果oid/buyer_uid/seller_uid同时存在,可以使用上述两种方案的综合方案,来解决“多key”业务的数据库水平切分难题; 要点总结 一:前后台差异化需求,可使用前台与后台分离的架构设计; 二:对于复杂系统设计,应该逐个击破; 三:基因法,是解决“1对多”业务,数据库水平切分的常见方案; 四:数据冗余,是解决“多对多”业务,数据库水平切分的常见方案; 五:最终一致性,是高吞吐互联网业务一致性的常用实践。 相关文章: 《用户中心,1亿数据架构,这次服了》 《帖子中心,1亿数据架构,这次服了》 《好友中心,1亿数据架构,这次服了》 任何脱离业务的架构设计都是耍流氓,共勉。 发布者:糖太宗,转载请注明出处:https://www.qztxs.com/archives/science/technology/6493 架构 赞 (0) 打赏 微信扫一扫 支付宝扫一扫 糖太宗 0 0 生成海报 帖子中心,1亿数据,架构如何设计? 上一篇 2022年5月14日 上午12:55 百亿关系链,架构如何设计? 下一篇 2022年5月14日 上午12:57 相关推荐 技术 MySQL缓冲池(buffer pool),终于懂了!!!(收藏) 应用系统分层架构,为了加速数据访问,会把最常访问的数据,放在缓存(cache)里,避免每次都去访问数据库。 操作系统,会有缓冲池(buffer pool)机制,避免每次访问磁盘,以加速数据的访问。 MySQL作为一个存储系统,同样具有缓冲池(buffer pool)机制,以避免每次查询数据都进行磁盘IO。 今天,和大家聊一聊InnoDB的缓冲池。... 糖太宗 2022年5月10日 31000 技术 hoho,这个线程模型有点意思 Leader-Follower是一种经典的多线程模型。 上图就是L/F多线程模型的状态变迁图,这个线程模型有6个关键点。 关键点一:线程三种状态。 (1)领导中,leading; (2)处理中,processing; (3)追随中,following; 关键点二:N个线程状态各异。 (1)只有1个leading线程(等待任务); (2)... 糖太宗 2022年5月14日 29000 技术 群消息已读回执(这个屌),究竟是推还是拉? 每当发出一条微信消息,都希望对方尽快看到,并尽快回复,但始终不知道对方是否阅读。 每当收到一条不能立马回复的微信消息,都默默返回,假装没看见。 画外音:不想回复的人,唉,你只是个好人。 微信用于个人社交,产品设计上,在线状态,强制已读回执都有可能暴露个人隐私,故微信并无相关功能。 钉钉用于商务交流,其“强制已读回执”功能,让职场人无法再“假装不在... 糖太宗 2022年5月15日 41000 求最大最小值,最少要进行多少次比较? | 经典面试题 如何从n个数里找到最大值? 很容易想到,用一个循环就能搞定。 int find_max(int arr[n]){ int max = -infinite; for(int i=0; i if(arr[i]>max) max=arr[i]; return max; } 这里,需要执行n... 糖太宗 技术 2022年5月11日 28000 通过宜搭完成JumpServer自动化授权 宜搭表单构建 根据jms 资产授权规则的表单设计宜搭表单,因为是自动化,只需要资产对单个用户授权,需要字段 – 规则名称,用户,资产,系统用户,权限,失效日期,备注几个字段 规则名称 – > 单行文本,标题 用户 –> 提交人,这个自动获取就可以了 资产 –> 下拉复选,通过jms接口获取,赋值给下拉多选组件,参考宜搭文档 获... 常山赵子龙 技术 2022年5月28日 56000 发表回复 您的电子邮箱地址不会被公开。 必填项已用*标注*昵称: *邮箱: 网址: 记住昵称、邮箱和网址,下次评论免输入 提交