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

京东评价系统的海量数据存储设计

时间:2023-03-13 13:48:08 科技观察

京东的商品评论已经达到了数十亿,每天都有数十亿的服务调用,而且这些数据每年还在呈指数级增长,数据存储是重中之重接下来我们介绍京东评论系统的数据存储是如何设计的。整体数据存储包括基础数据存储、文本存储、数据索引和数据缓存。基础数据存储Mysql用于基础数据存储,由于用户评论是文本信息,通常包含文字、字符等,占用存储空间比较大,所以mysql作为基础数据库只存储非文本评论基础信息,包括评论状态、用户、时间等基本数据,以及图片、标签、点赞等附加数据。而不同的数据可以选择不同的数据库分表方案,参考如下:评论基础数据按用户ID和表分拆;图片和标签在同一个数据库中,按照产品编号分别拆解;其他扩展信息数据,由于数据量不大,访问量不高,可以在同库下处理,不分表。它因人而异,因系统而异。根据不同的数据场景选择不同的存储方案,有效利用资源,解决数据存储问题,为高性能、高可用的服务打下坚实的基础。文本存储使用mongodb和hbase进行文本存储,选择nosql而不是mysql。一是减轻mysql存储压力,释放msyql。海量存储也得到可靠保障;第二,nosql的高性能读写,大大提高了系统的吞吐量。体积和减少延迟。存储升级过程尝试过cassandra、mongodb等分布式nosql存储。Cassandra适用于写多读少的情况。Mongodb也是一个基于分布式文件存储的数据库,介于关系型数据库和非关系型数据库之间。同时,它也是一个内存级别的数据库。mongo的写入性能不如cassandra,但是在读写分离的情况下读取性能还是相当不错的,所以从应用场景上我们选择了mongodb。mongodb确实不错,支持系统稳定运行好几年了。但是考虑到未来的数据增长、业务扩展、应用扩展,hbase是最好的选择。其存储容量、可靠性和可扩展性是毋庸置疑的。如果选择hbase,只需要根据评论ID构造Rowkey,然后存储评论文本信息即可。查询时,只需根据ID快速读取评论的文字内容即可。当然,你也可以将评论的其他字段信息冗余存储。这样,根据评论ID读取评论信息后,就不需要再从mysql中读取,减少了数据操作,提高了查询性能。数据索引京东评论分为用户和商品两个维度。对于用户来说,用户需要发表评论、上传图片、查看自己的评论等,因此只要将评论数据按照用户ID拆解存储到mysql数据库中,就可以解决用户数据的读写问题得到解决。对于商品,前台需要统计商品的评论数,并显示所有评论。后台需要根据评论的全字段进行搜索,还要进行模糊查询,评论数据根据userId拆分到数据库表中。现在要按产品获取评论,显然不可能实现现在的分库。一开始考虑按品号拆库拆表,但经过多层分析发现不可行,因为按品号拆需要机器数量翻倍,而且硬件成本非常高。二维分库高度一致,不仅增加了系统维护成本和业务复杂度,而且无法解决评论统计、列表过滤、模糊查询等问题,为此,全文检索引入框架solr(前台)/elasticsearch(后台)进行数据索引。数据索引其实就是将评论数据构建成索引,存储在索引服务中,方便评论数据的模糊查询、条件过滤、断面统计等,弥补无法实现的功能以上数据存储完成。京东评论系统为此使用了solr/elasticsearch搜索服务。都是基于Lucene的全文搜索框架,同时也是分布式搜索框架(solr4.0之后加入了solrcloud,支持分布式),支持数据分片和分面统计,高亮,分词等功能,使用搜索框架可以有效解决前端评论数据统计和列表筛选的问题,还可以在后台系统中支持关键词展示、多字段检索和模糊查询,可谓一举多得。搜索在建立索引时,属性字段可以分为存储字段和索引字段。索引创建后,存储字段会存储索引文档中的内容,同时也会占用相应的索引空间。查询后可以返回原来的内容,索引字段被索引后,不占用索引空间,不能返回原来的内容。它只能用于查询。因此,建议不要为长内容存储索引。在为评论搜索建立索引时,设置主键评论ID的索引方式为storage,其他字段设置为index。这样不仅减少了索引文件的存储空间,而且大大提高了索引的构建效率和查询性能。当然,在使用搜索框架的时候,如果业务数据量比较小,也可以选择存储所有的字段,这样在搜索中查询出结果后,就不需要去数据库中查询其他信息了,这样也减轻了数据库的压力。为了更好的应对前台和后台不同的业务场景,搜索集群分为前台搜索集群和后台搜索集群。前端搜索集群根据商品号进行索引数据分片,用于解决评论前端的评论数统计和评论列表过滤功能。对于评论的统计,如果使用常规数据库进行统计,需要对sql进行分组统计。如果只统计单个群在性能上是可以接受的,但是京东的评论统计需要统计1到5分的评论,随着群数的增加,数据库的压力也会随着增加而增加统计,所以在mysql上用group方法进行统计是行不通的。使用solr的版块统计,只需要一次查询就可以轻松统计商品每个分类的评论数,查询性能也是毫秒级别。横断面统计的使用如下:对于评论列表,只需要根据条件从搜索中查询出评论ID集,然后在mysql和Hbase中根据评论ID。数据组装好后,可以返回给前台展示。后台搜索集群,评论后台系统需要对评论进行查询,包括关键词高亮、全域检索、模糊查询等,为此,solr/elasticsearch是一个不错的选择,目前使用的是elasticsearch。未来还计划将前端搜索集群切换到elasticsearch。面对亿级的数据请求,数据缓存承受不起,直接打通到mysql和搜索服务。因此,有必要对评论数据进行缓存。这里根据不同的业务数据选择高性能缓存redis进行集群。同时采用多机房主从模式解决单点问题。这样,不同的缓存集群只有相应的横向扩展,才能快速提升数据吞吐能力,有效保证服务的高性能和高可用。当然,缓存设计时还有很多细节可以巧妙处理,比如:当用户发表新评论时,要实现前台实时展示,可以在首屏添加最新的评论信息列出带有新添加评论数量的缓存;评论数是读多写少,这样就可以把评论数持久化到redis中。只有当数据更新时,才可以异步刷新缓存;通过nginx+lua可以显示评论数,服务请求不需要返回给应用,既提高了服务性能,又减轻了应用系统的压力;对于评论列表,通常会访问***屏的数据,也就是***页的数据,可以将***页的数据缓存在redis中,然后通过一个异步更新有数据更新时的程序;对于闪购商品,可以结合本地缓存对评论数据进行提前预热,这样当闪购流量瞬间涌入时,不会对缓存集群造成压力;通过减少密钥长度、删除冗余属性和压缩文本来节省内存空间并提高内存使用率。数据容灾和高可用为了解决大数据存储问题,实现数据服务的高可用,引入了很多存储方案。同时,合理的部署设计和相应的容灾处理也是必要的。上述数据存储基本采用多机房主从模式部署,各机房实现主从结构进行数据同步。如图:mysql集群数据库拆解后,每个分库需要部署多个机房做master-slave。系统应用读写分离,按机房调用。当主机房数据库出现故障时,将故障机房的数据操作切换到其他机房,故障排除后进行数据同步和流量切换。采用主从机房部署方式,所有的数据更新操作都必须在主数据库上进行,当主机房出现故障时,需要通过重建数据库主从关系等一系列操作才能解决流量切换、重新配置和发布应用,过程比较复杂,影响较大,所以这是一个单点问题。为此,多中心数据服务将是我们的下一个目标。多中心按照特定规则将用户路由到不同机房进行数据读写,各机房通过数据总线进行数据同步。当某个机房出现故障时,只需一键操作,故障机房内的所有用户流量即可快速转移到该机房。路由到其他机房,实现数据多写多活,进一步实现服务的高可用。数据多中心如下:hbase集群目前使用京东公有集群,实现双机房主备部署。主集群故障后,流量会自动切换到备集群,当整个hbase集群故障时,也可以恢复。降级,同步只写缓存和备份存储mongo,待集群恢复后,后台异步任务将数据写回hbase。搜索集群根据产品编号进行索引数据分片,多机房主从部署,保证至少3个从节点部署在多个机房。当主节点发生故障时,这些从节点中的一个被选为新的主节点提供服务。集群的主节点只提供索引更新操作的异步任务,从节点根据应用机房的部署提供索引查询服务。Redis缓存集群的主从部署还是标准的。主节点只提供数据更新操作,从节点提供前台缓存读服务,实现了缓存数据的读写分离,提高了缓存服务的处理能力。当主节点出现故障时,选择距离最近的机房内的一个从节点作为新的主节点提供写服务,重建主从关系。如果任一从节点发生故障,可通过内部配置中心进行一键切换,将故障节点的流量切换到其他从节点。综上所述,整体数据架构并没有什么高大上的设计,整体数据架构方案也是为了解决实际痛点和业务问题而演进的。没有放之四海而皆准的数据存储方案,只有最适合的。因此,最重要的是根据不同时期、不同业务场景选择合适的设计。大家有什么好的解决方案和建议,可以一起讨论,互相学习,系统稳定,高性能,高可用才是王道。作者:韦石,京东交易平台评价社区负责人,2010年加入京东,先后参与用户、商品、评价等系统架构升级。【本文来自专栏作者张凯涛微信公众号(凯涛博客),公众号id:kaitao-1234567】