对于 version + ext 方案,还是有很多朋友质疑“线上不可能这么用”。本篇将讲述一下 58同城 最核心的数据“帖子”的架构实现技术细节,说明不仅不是“不可能这么用”,而是大数据,可变属性,高吞吐场景下的“常用手段”。 一、背景描述及业务介绍 问:什么是数据库扩展的 version + ext 方案? 使用 ext 来承载不同业务需求的个性化属性,使用 version 来标识 ext 里各个字段的含义。 例如上述 user 表: verion=0 表示 ext 里是 passwd/nick version=1 表示 ext 里是 passwd/nick/age/sex 优点?
不足?
问:什么是58同城最核心的数据? 58同城是一个信息平台,有很多垂直品类:招聘、房产、二手物品、二手车、黄页等等,每个品类又有很多子品类,不管哪个品类,最核心的数据都是“帖子信息”(业务像一个大论坛?)。 问:帖子信息有什么特点? 大家去58同城的首页上看看就知道了:
如何解决100亿数据量,1万属性,多属性组合查询,10万并发查询的技术难题,是今天要讨论的内容。 二、最容易想到的方案 每个公司的发展都是一个从小到大的过程,撇开并发量和数据量不谈,先看看
最开始,可能只有一个招聘品类,那帖子表可能是这么设计的: tiezi(tid,uid, c1, c2, c3) 那如何满足各属性之间的组合查询需求呢? 最容易想到的是通过组合索引: index_1(c1,c2) index_2(c2, c3) index_3(c1, c3) 随着业务的发展,又新增了一个房产类别,新增了若干属性,新增了若干组合查询,于是帖子表变成了: tiezi(tid,uid, c1, c2, c3, c10, c11, c12, c13) 其中c1,c2,c3是招聘类别属性,c10,c11,c12,c13是房产类别属性,这两块属性一般没有组合查询需求 但为了满足房产类别的查询需求,又要建立了若干组合索引(不敢想有多少个索引能覆盖所有两属性查询,三属性查询) 是不是发现玩不下去了? 三、友商的玩法 新增属性是一种扩展方式,新增表也是一种方式,有友商是这么玩的,按照业务进行垂直拆分: tiezi_zhaopin(tid,uid, c1, c2, c3) tiezi_fangchan(tid,uid, c10, c11, c12, c13) 这些表,这些服务维护在不同的部门,不同的研发同学手里,看上去各业务线灵活性强,这恰恰是悲剧的开始:
想想看,电商的商品表,不可能一个类目一个表的。 四、58同城的玩法 【统一帖子中心服务】 平台型创业型公司,可能有多个品类,例如58同城的招聘房产二手,很多异构数据的存储需求,到底是分还是合,无需纠结:基础数据基础服务的统一,无疑是58同城技术路线发展 roadmap 上最正确的决策之一,把这个方针坚持下来,@老崔 @晓飞 这些高瞻远瞩的先贤功不可没,业务线会有“扩展性”“灵活性”上的微词,后文看看先贤们如何通过一些巧妙的技术方案来解决的。 如何将不同品类,异构的数据统一存储起来,采用的就是类似 version+ext 的方式: tiezi(tid,uid, time, title, cate, subcate, xxid, ext) 1. 一些通用的字段抽取出来单独存储 2. 通过cate, subcate, xxid等来定义 ext 是何种含义(和version有点像?) 3. 通过 ext 来存储不同业务线的个性化需求 例如招聘的帖子: ext : {“job”:”driver”,”salary”:8000,”location”:”bj”} 而二手的帖子: ext : {”type”:”iphone”,”money”:3500} 58同城最核心的帖子数据,100亿的数据量,分256库,异构数据 mysql 存储,上层架了一个服务,使用 memcache 做缓存,就是这样一个简单的架构,一直坚持这这么多年。上层的这个服务,就是58同城最核心的统一服务IMC(Imformation Management Center),注意这个最核心,是没有之一。 解决了海量异构数据的存储问题,遇到的新问题是:
【统一类目属性服务】 每个业务有多少属性,这些属性是什么含义,值的约束等揉不到帖子服务里,怎么办呢? 58同城的先贤们抽象出一个统一的类目、属性服务,单独来管理这些信息,而帖子库 ext 字段里 json 的 key,统一由数字来表示,减少存储空间。 如上图所示,json 里的 key 不再是”salary” ”location” ”money” 这样的长字符串了,取而代之的是数字1,2,3,4,这些数字是什么含义,属于哪个子分类,值的校验约束,统一都存储在类目、属性服务里。 这个表里对帖子中心服务里 ext 字段里的数字 key 进行了解释: 1 代表 job,属于招聘品类下 100 子品类,其 value 必须是一个小于 32 的 [a-z] 字符 4 代表 type,属于二手品类下 200 子品类,其 value 必须是一个 short 这样就对原来帖子表 ext 里的 ext : {“1”:”driver”,”2”:8000,”3”:”bj”} ext : {”4”:”iphone”,”5”:3500} key 和 value 都做了统一约束。 除此之外,如果 ext 里某个 key 的 value 不是正则校验的值,而是枚举值时,需要有一个对值进行限定的枚举表来进行校验: 这个枚举校验,说明 key=4 的属性(对应属性表里二手,手机类型字段),其值不只是要进行“short类型”校验,而是 value 必须是固定的枚举值。 ext : {”4”:”iphone”,”5”:3500} 这个 ext 就是不合法的(key=4 的 value=iphone 不合法),合法的应该为 ext : {”4”:”5”,”5”:3500} 此外,类目属性服务还能记录类目之间的层级关系:
协助解释58同城最核心的帖子数据,描述品类层级关系,保证各类目属性扩展性,保证各属性值合理性校验,就是58同城另一个统一的核心服务CMC(Category Management Center)。 多提一句,类目、属性服务像不像电商系统里的 SKU 扩展服务?
解决了 key 压缩,key 描述,key 扩展,value 校验,品类层级的问题,还有这样的一个问题没有解决:每个品类下帖子的属性各不相同,查询需求各不相同,如何解决100亿数据量,1万属性的查询需求,是58同城面临的新问题。 【统一检索服务】 数据量很大的时候,不同属性上的查询需求,不可能通过组合索引来满足所有查询需求,怎么办呢? 58同城的先贤们,从一早就确定了“外置索引,统一检索服务”的技术路线:
元数据与索引数据的操作遵循:
这个扛起58同城 80% 终端请求(不管来自 PC 还是 APP,不管是主页、城市页、分类页、列表页、详情页,很可能这个请求最终会是一个检索请求)的服务,就是58同城另一个统一的核心服务 E-search,这个搜索引擎的每一行代码都来自58同城@老崔 @老龚 等先贤们,目前系统维护者,就是“架构师之路”里屡次提到的@龙神 。 对于这个服务的架构,简单展开说明一下: 为应对100亿级别数据量、几十万级别的吞吐量,业务线各种复杂的复杂检索查询,扩展性是设计重点:
系统时延,100亿级别帖子检索,包含请求分合,拉链求交集,从 merger 层均可以做到10ms返回。 58同城的帖子业务,一致性不是主要矛盾,E-search 会定期全量重建索引,以保证即使数据不一致,也不会持续很长的时间。 五、总结 文章写了很长,最后做一个简单总结,面对100亿数据量,1万列属性,10万吞吐量的业务需求,58同城的经验,是采用了元数据服务、属性服务、搜索服务来解决的。 再回到文首 version + ext 的方案,希望朋友有新的收获和感触! |
|