当前位置: 首页 > 科技观察

10000个属性,100亿数据,100000吞吐量-秒,架构怎么设计?

时间:2023-03-13 15:47:51 科技观察

有一类业务场景没有固定的schema存储,但是有大量的数据行。这类业务的存储和检索在架构上如何实现?58核心数据“后”架构实现的技术细节,今天和你聊一聊。一、背景描述及业务介绍58的核心数据是什么?58是一个信息平台,有很多垂直类目:招聘、二手货、二手车、黄页等,每个类目下都有很多子类目,无论是哪个类目,核心数据都是“帖子信息”。画外音:它看起来像一个大论坛吗?每一类信息的特点是什么?去过58的朋友可以很容易的了解到这里帖子的信息:每个分类的属性差别很大。招聘帖和二手帖的属性完全不同。二手手机与二手家电的属性完全不同。目前大概有近万个属性;数据量巨大,达到百亿级别;每个属性都有查询需求,每个属性组合可能有组合查询需求。招聘需要查岗位/经验/薪资范围,查二手手机颜色/价格/型号,查二手冰箱/洗衣机/空调;吞吐量非常大,每秒几十万个吞吐量;如何解决100亿数据量、10000个属性、多属性组合查询,10万并发查询的技术难点呢?一步步。2.最容易想到的方案。每个公司的发展都是一个从小到大的过程。抛开并发量和数据量不谈,我们先来看看如何实现属性的扩展性需求;多属性组合查询需求;画外音:公司初期并发量和数据量不大,首先要解决业务问题。如何满足业务的存储需求?一开始,业务只有一个招聘类别,所以post表可能这样设计:tiezi(tid,uid,c1,c2,c3);如何满足各种属性之间的组合查询需求呢?最容易想到的就是通过组合索引来满足查询需求:index_1(c1,c2)index_2(c2,c3)index_3(c1,c3)随着业务的发展,新增了一个类目,那怎么办存储问题解决办法?可以添加一些属性来满足存储需求,这样post表就变成了:tiezi(tid,uid,c1,c2,c3,c10,c11,c12,c13);其中:c1、c2、c3为招聘类别属性c10、c11、c12、c13为新增类别属性。通过扩展属性,可以解决存储问题。如何满足查询需求?第一,跨业务属性一般没有组合查询需求。只需建立少量复合索引即可满足新类别的查询需求。画外音:我不敢想有多少索引可以涵盖所有的二属性查询和三属性查询。当业务越来越多的时候,你是不是发现玩不下去了?3.纵向拆分是一种思路。添加属性是一种扩展方式,添加表也是一种方式,垂直拆分也是一种常见的存储扩展方案。如何按业务垂直拆分?你可以这样玩:tiezi_zhaopin(tid,uid,c1,c2,c3);tiezi_fangchan(tid,uid,c10,c11,c12,c13);在不同的业务中,数据量和吞吐量巨大的数据情况下,垂直拆分会遇到哪些问题?这些表和相应的服务在不同的部门维护。似乎每个业务都有很强的灵活性和闭环研发。这恰恰是悲剧的开始:如何规范tid?有的用mysql做存储,有的自己开发存储;许多组件被反复开发;维护成本太高;……画外音:你想想,一个电商商品表不可能每个品类都有一个表。4.58怎么玩:三大中心服务,一个统一邮中心服务平台创业公司,可能有多个品类,每个品类对异构数据有很多存储需求,不用纠结是分还是分combine:基础数据基础服务的统一是一个很好的做法。画外音:这是一个平台业务。如何统一存储不同类别、异构的数据?所有类别的通用属性统一存储;单个类别的特有属性、类别类型和通用属性存储在json中;更具体地说:tiezi(tid,uid,time,title,cate,subcate,xxid,ext);一些公共字段被提取出来单独存储;通过cate、subcate、xxid等定义ext的含义;使用ext存储不同业务线的个性化需求,比如:招聘岗位,ext为:{"job":"driver","salary":8000,"location":"bj"}和二手岗位,extis:{"type":"iphone","money":3500}post数据,100亿数据量,分为256个数据库,通过ext存储异构业务数据,使用mysql存储,在上面架设一个postcenter服务上层,使用memcache作为缓存,就是这样一个不复杂的架构解决了业务问题大问题。这是58的核心邮政中心服务IMC(InfoManagementCenter)。画外音:这个服务的底层存储在2016年全面切换到自研存储引擎,取代了mysql,但架构理念没有改变。解决了海量异构数据的存储问题,遇到的新问题是:每条记录的ext中的key需要重复存储,占用空间大,能否压缩存储;cateid不足以描述ext中的内容和类别有层次,深度不确定。ext是否可以自描述;可以随时添加属性以确保可扩展性;在解决了海量异构数据的存储问题之后,下一步就是解决品类可扩展性的问题。第二:统一类目服务中每个业务有多少个属性,这些属性的含义是什么,值约束等,耦合到post服务中显然是不合理的,那么怎么办呢?抽象出一个统一的分类,将其分开来管理这些信息,并且将post库ext字段中的json的key统一用一个数字来表示,减少存储空间。画外音:post表只存储元信息,不考虑业务意义。如上图所示,json中的key不再是“salary”“location”“money”这样的长字符串,而是换成了数字1,2,3,4,这些数字是什么意思,属于哪个子类to,值检查约束都存储在类别服务中。画外音:category表存储业务信息和约束信息,与post表解耦。这张表解释了邮局服务中ext字段的数字键:1代表job,属于招聘类别下的100个子类别,取值必须是小于32的[a-z]字符;4代表type,属于二手分类下的200个子分类,取值必须是short;这样,ext扩展属性显示在原帖上:{"1":"driver","2":8000,"3":"bj"}{"4":"iphone","5":3500}key和value都是统一约束的。另外,如果ext中某个key的值不是常规校验值,而是枚举值,则需要一个限制该值的枚举表来校验:这个枚举校验表示key=4的属性(对应第二个-属性表中的手和手机类型字段),其取值不仅要通过“短类型”来验证,而且该值必须是一个固定的枚举值。{"4":"iphone","5":3500}这个ext不合法,key=4的value=iphone不合法,应该是枚举属性,合法的应该是:{"4":"5","5":3500}另外,类目服务还可以记录类目之间的层级关系:一级类目是招聘,二手……二手,还有二手家具,二手手机...二手手机分类分为三层级:二手iPhone、二手小米、二手三星...分类服务说明帖子数据,描述层级关系类目的分类,保证每个类目的属性的可扩展性,保证每个属性值的合理性,这是58的另一个统一核心服务CMC(CategoryManagementCenter)。画外音:这个服务是不是很像电商系统中的SKU延伸服务?品类层级对应电子商务中的品类层级;属性扩展对应电子商务中每个类目商品SKU的属性;枚举值校验对应属性枚举值,如颜色:红、黄、蓝;通过类别服务,解决了密钥压缩、密钥描述、密钥扩展、值验证、类别级问题。还有这样一个问题没有解决:每个分类帖子的属性不一样,查询需求也不一样。如何解决100亿数据量、10000个属性的检索和联合检索需求?第三:当统一检索服务数据量大,查询不同属性的需求时,不可能通过组合索引来满足所有的查询需求,“外部索引,统一检索服务”是一种很常见的做法:数据库提供“postid》正行查询需求;所有非“postid”的个性化检索要求,统一外部索引;元数据和索引数据操作如下:TID前排查询帖子,直接访问帖子服务;修改帖子,帖子服务通知检索服务,同时修改索引;进行复杂查询,通过搜索服务满足需求;画外音:这个搜索服务承载了58同城80%的请求(无论是来自PC还是APP,无论是首页、城市页、分类页、列表页、详情页,最终都会转化为检索请求),它是58易搜的另一项统一核心服务,该搜索引擎完全自主研发。对于这个核心自研服务的搜索引擎架构,我简单说明一下:为了应对百亿级别的数据量,几十万级别的吞吐量,以及业务线中各种复杂复杂的搜索查询,可扩展性是设计重点:(1)统一的代理层作为入口,保证系统性能可以通过加机进行扩展;(2)统一的结果聚合层也可以保证系统性能可以通过增加机器来扩展;(3)search内核检索层、服务和索引数据部署在同一台机器上。服务启动时,可以将索引数据加载到内存中,请求访问时从内存中加载数据。访问速度非常快:索引数据为了满足数据容量的可扩展性,为了满足一条数据的性能可扩展性,同一条数据是冗余的。理论上,增加更多的机器可以扩展系统的性能。延迟,百亿级别的帖子检索,包括请求分离和组合,拉链交集,可以在10ms以内从聚合层返回。画外音:入口层是用Java开发的,聚合层和检索层都是用C语言开发的。对于邮政业务来说,一致性并不是主要矛盾。易搜会定期全量重建索引,保证即使数据不一致也不会长期存在。五、总结文章写了很久了。让我做一个简单的总结。面对百亿数据量、万列属性、十万吞吐量的业务需求,可以使用元数据服务和搜索服务来解决:一种解决存储问题,一种解决类目解耦问题,一种解决检索问题,任何复杂的问题都是一步步解决的。思路比结论更重要,希望大家有所收获。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文