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

系统运维2025-11-05 14:08:37298

京东的京东商品评论目前已达到数十亿条,每天提供的系统服务调用也有数十亿次,而这些数据每年还在成倍增长,海量而数据存储是数据设计其中最重要的部分之一,接下来就介绍下京东评论系统的存储数据存储是如何设计的。

整体数据存储包括基础数据存储、京东文本存储、系统数据索引、海量数据缓存几个部分。数据设计

基础数据存储

基础数据存储使用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进行读取,减少数据操作,提升查询性能。

数据索引

京东的云服务器提供商评论是以用户和商品两个维度进行划分的。对于用户而言,用户需要发表评论、上传晒图、查看自己的评论等,因此mysql数据库中只要根据用户ID对评论数据进行拆库拆表进行存储,便能解决用户数据读写问题。而对于商品而言,前台需要将统计商品的评论数并将所有评论展示出来,后台需根据评论的全字段进行检索同时还带模糊查询,而评论数据是按userId进行库表拆分的,现在要按商品去获取评论,显然当前的拆分库是无法实现的。起初考虑过根据商品编号再进行拆库拆表,但经过多层分析后发现行不通,因为再按商品编号进行拆分,得再多加一倍机器,硬件成本非常高,同时要保持用户及商品两维度的分库数据高度一致,不仅增加了系统维护成本及业务复杂度,同时也无法解决评论的数据统计、列表筛选、模糊查询等问题,为此引入了全文检索框架solr(前台)/elasticsearch(后台)进行数据索引。

数据索引其实就是将评论数据构建成索引存储于索引服务中,便于进行评论数据的模糊查询、条件筛选及切面统计等,以弥补以上数据存储无法完成的功能。京东评论系统为此使用了solr/elasticsearch搜索服务,它们都是基于Lucene的全文检索框架,也是分布式的搜索框架(solr4.0后增加了solr cloud以支持分布式),支持数据分片、切面统计、高亮显示、分词检索等功能,利用搜索框架能有效解决前台评论数据统计、列表筛选问题,也能支持后台系统中的关键词显示、多字段检索及模糊查询,可谓是一举多得。

搜索在构建索引时,属性字段可分为存储字段与索引字段,存储字段在创建索引后会将内容存储于索引文档中,同时也会占用相应的索引空间,查询后可返回原始内容,而索引字段创建索引后不占用索引空间也无法返回原始内容,只能用于查询,因此对于较长的内容建议不进行存储索引。

评论搜索在构建索引时,主键评论ID的索引方式设置为存储,其它字段设置为索引,这样不仅减少索引文件的存储空间,也大大提升了索引的构建效率与查询性能。当然,在使用搜索框架时,业务数据量比较小的也可选择将所有字段进行存储,这样在搜索中查询出结果后将不需要从数据库上查询其它信息,也减轻了数据库的压力。

为了更好地应对前后台不同的业务场景,搜索集群被划分为前台搜索集群和后台搜索集群。

前台搜索集群根据商品编号进行索引数据分片,用于解决评论前台的评论数统计、评论列表筛选功能。评论数统计,如果使用常规数据库进行统计时,需要进行sql上的group分组统计,如果只有单个分组统计性能上还能接受,但京东的评论数统计则需要对1到5分的评论分别进行统计,分组增加的同时随着统计量的增加数据库的压力也会增加,因此在mysql上通过group方式进行统计是行不通的。而使用solr的切面统计,只需要一次查询便能轻松地统计出商品每个分级的评论数,而且查询性能也是毫秒级的。切面统计用法如下:

评论列表,只需根据条件从搜索中查询出评论ID集合,再根据评论ID到mysql、Hbase中查询出评论的其它字段信息,经过数据组装后便可返回前台进行展示。

后台搜索集群,评论后台系统需要对评论进行查询,其中包括关键词高亮显示、全字段检索、模糊查询等,为此solr/elasticsearch都是个很好的选择,目前使用elasticsearch。

未来也计划将前台搜索集群切换为elasticsearch。

数据缓存

面对数十亿的数据请求,直接击穿到mysql、搜索服务上都是无法承受的,所以需要对评论数据进行缓存,在此选择了高性能缓存redis,根据不同的业务数据进行集群划分,同时采用多机房主从方式部署解决单点问题,这样只需要对不同的缓存集群进行相应的水平扩展便能快速提升数据吞吐能力,也有效地保证了服务的高性能、高可用。

当然,缓存设计时还有很多细节可以进行巧妙处理的,如:

当用户新发表一条评论,要实现前台实时展示,可以将新增的评论数向首屏列表缓存中追加***的评论信息; 评论数是读多写少,这样就可以将评论数持久化到redis当中,只有当数据进行更新时通过异步的方式去将缓存刷新即可;评论数展示可通过nginx+lua的方式提供服务,服务请求无需回源到应用上,不仅提升服务性能,也能减轻应用系统的压力; 对于评论列表,通常访问的都是***屏的数据,也就是***页的数据,可以将***页的数据缓存到redis当中,有数据更新时再通过异步程序去更新; 对于秒杀类的商品,评论数据可以结合本地缓存提前进行预热,这样当秒杀流量瞬间涌入的时候也不会对缓存集群造成压力;通过减短key长度、去掉多余属性、压缩文本等方式节省内存空间,提高内存使用率。

数据容灾与高可用

引入了这么多的存储方案就是为了解决大数据量存储问题及实现数据服务的高可用,同时合理的部署设计与相应的容灾处理也必须要有的。以上数据存储基本都使用多机房主从方式部署,各机房内部实现主从结构进行数据同步。如图:

mysql集群数据库拆库后需要对各分库进行多机房主从部署,系统应用进行读写分离并根据机房进行就近调用,当主机房数据库出现故障后将故障机房的数据操作都切换到其它机房,待故障排除后再进行数据同步与流量切换。

使用主从机房部署的方式所有数据更新操作都要在主库上进行,而当主机房故障是需要通过数据库主从关系的重建、应用重新配置与发布等一系列操作后才能解决流量切换,过程较为复杂且影响面较大,所以这是个单点问题,为此实现数据服务多中心将是我们下一个目标。

多中心根据特定规则将用户分别路由到不同机房进行数据读写,各机房间通过数据总线进行数据同步,当某一机房出现故障,只需要一键操作便能快速地将故障机房的用户流量全部路由到其它机房,实现了数据的多写多活,也进一步实现了服务的高可用。数据多中心如下:

hbase集群目前使用的是京东的公有集群,实现了双机房主备部署,主集群出现故障后自动将流量切换到备用集群,而当hbase整个集群故障时还可对其进行降级,同步只写入缓存及备用存储mongo,待集群恢复后再由后台异步任务将数据回写到hbase当中。

搜索集群根据商品编号进行索引数据分片多机房主从部署,并保证至少3个从节点并部署于多个机房当中,当主节点出现故障后从这些从节点选取其中一个作为新的主提供服务。集群主节点只提供异步任务进行索引更新操作,从节点根据应用机房部署情况提供索引查询服务。

Redis缓存集群主从部署仍是标配,主节点只提供数据的更新操作,从节点提供前台缓存读服务,实现缓存数据的读写分离,提升了缓存服务的处理能力。当主节点出现故障,选取就近机房的一个从节点作为新主节点提供写服务,并将主从关系进行重新构建。任何一从节点出现故障都可通过内部的配置中心进行一键切换,将故障节点的流量切换到其它的从节点上。

总结

整体数据架构并没有什么高大上的设计,而且整体数据架构方案也是为了解决实际痛点和业务问题而演进过来的。数据存储方案上没有***的,只有最适合的,因此得根据不同的时期、不同的业务场景去选择合适的设计才是最关键的,大家有什么好的方案和建议可以相互讨论与借鉴,系统的稳定、高性能、高可用才是王道。

作者:韦仕,京东商城交易平台评价社区负责人,2010年加入京东,先后参与了用户、商品、评论等系统的架构升级工作。

【本文来自专栏作者张开涛的微信公众号(开涛的博客),公众号id: kaitao-1234567】

本文地址:http://www.bzve.cn/html/17a66899314.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

金河田500w电源质量评测(性能强大,稳定可靠的电源选择)

简历写熟悉Spring源码?你知道它用到了哪些设计模式?

JavaScript 运行原理解析

GitHub上最全中华古诗词数据库又火了

假如你想清理你的 Ubuntu 主机,你可以按照以下的一些简单步骤来移除所有不需要的垃圾文件。移除多余软件包这又是一个内置功能,但这次我们不必使用新得立包管理软件(Synaptic Package Manager),而是在终端中达到目的。现在,在终端窗口中键入如下命令:复制代码代码如下:sudo apt-get autoclean这便激活了包清除命令。这个命令所做的工作是: 自动清除那些当你安装或升级程序时系统所缓存的 .deb 包(即清除 /var/cache/apt/archives 目录,不过只清理过时的包)。假如需要使用清除命令,只需在终端窗口中键入以下命令:复制代码代码如下:sudo apt-get clean然后你就可以使用自动移除命令。这个命令所做的工作是:清除那些 在系统中被某个已经卸载的软件 作为依赖所安装的软件包。要使用自动移除命令,在终端窗口中键入以下命令:复制代码代码如下:sudo apt-get autoremove移除不需要的本地化数据为达到此目的,我们需要安装 localepurge 软件,它将自动移除一些不需要的本地化数据(LCTT 译注:即各种语言翻译)。这个软件是一个简单的脚本,它将从那些不再需要的本地化文件和本地化联机手册( man pages ) 所占用的空间中回收磁盘空间。这个软件将在任何 apt 安装命令运行时 被自动激活。在 Ubuntu 中安装 localepurge:复制代码代码如下:sudo apt-get install localepurge在通过 apt-get install 安装任意软件后, localepurge 将移除所有不是使用你系统中所设定语言的翻译文件和翻译的联机手册。假如你想设置 localepurge,你需要编辑 /ect/locale.nopurge 文件。根据你已经安装的软件,这将为你节省几兆的磁盘空间。例子:假如我试着使用 apt-get 来安装 dicus软件:复制代码代码如下:sudo apt-get install discus在软件安装完毕之后,你将看到如下提示:复制代码代码如下:localepurge: Disk space freed in /usr/share/locale: 41860K移除孤包假如你想移除孤包,你需要安装 deborphan 软件:在 Ubuntu 中安装 deborphan :复制代码代码如下:sudo apt-get install deborphan使用 deborphan,打开终端并键入如下命令即可:复制代码代码如下:sudo deborphan | xargs sudo apt-get -y remove --purge使用 GtkOrphan 来移除孤包GtkOrphan (一个针对 debian 系发行版本的 Perl/Gtk2 应用) 是一个分析用户安装过程状态并查找孤立库文件的图形化工具,它为 deborphan 提供了一个 GUI 前端,并具备移除软件包的功能。在 Ubuntu 中安装 GtkOrphan,打开终端并运行如下命令:复制代码代码如下:sudo apt-get install gtkorphan一张截图使用 Wajig 移除孤包Wajig是 Debian 包管理系统中一个简单的软件包管理前端。它将 apt、apt-cache、 dpkg、 /etc/init.d 中的脚本等 通过一个单一命令集成在一起,它的设计初衷是使用简单和为它的所有功能提供丰富的文档。通过适当的 sudo配置,大多数(假如不是全部)的软件包安装和创建等任务可以通过一个用户 shell 来完成。Wajig 也适用于一般的系统管理。另外,一个 Gnome GUI 命令 gjig也被囊括在这个软件包之中。在 Ubuntu 中安装 Wajig,打开终端并运行如下命令:复制代码代码如下:sudo apt-get install wajigDebfoster --- 跟踪你在安装过程中的操作debfoster 将会维护一个列有被明确需要安装的软件包的列表,但不包括那些作为某个软件的依赖而被安装的软件包。参数是完全可选的,你甚至可以使得在 dpkg 和/或 apt-get 每次运行之后马上激活 debfoster 。另外,你还可以在命令行中使用 debfoster 来安装或移除某些特定的软件包。那些后缀为 --- 的软件包将会被移除,而没有后缀的软件包将会被安装。假如一个新的软件包或 debfoster 注意到作为某个软件包的依赖的软件包是一个孤包,则 debfoster 将会询问你下一步如何操作。若你决定保留这个孤包, debfoster 将只会进行记录并继续安装过程;若你觉得这个软件包不足以引起你的兴趣,在 debfoster 询问这个问题后,它将移除这个软件包。进一步的,假如你的决定使得其他的软件包变为孤包,更多的提问将会接踵而来。在 Ubuntu 中安装 debfoster,打开终端并运行如下命令:复制代码代码如下:sudo apt-get install debfoster使用 debfoster为了创建一个初始跟踪文件,可以使用如下命令:复制代码代码如下:sudo debfoster -q你总可以编辑 /var/lib/debfoster/keepers 文件,来定义那些你想留在系统中的软件包。为了编辑这个文件,可以键入:复制代码代码如下:sudo vi /var/lib/debfoster/keepers要强制使 debfoster 去移除所有没有被列在上面这个文件的软件包,或安装作为某些列在这个文件中的软件包的依赖,它也同时会添加所有在这个列表中没有被安装的软件包。若要根据这个列表来执行相关操作,只需执行:复制代码代码如下:sudo debfoster -f若需要跟踪你新安装的软件包,你需要时不时地执行如下命令:复制代码代码如下:sudo debfosterxdiskusage -- 查看你的硬盘空间都去哪儿了图形化地展示磁盘使用情况的 du。xdiskusage 是一个用户友好型的程序,它将为你展示你所有磁盘的使用情况。 它是在 Phillip C. Dykstra 所写的 “xdu” 程序的基础上设计的。做了一些修改以使得它可以为你运行 “du”命令,并显示磁盘的剩余空间,并且假如你想清晰地了解你的磁盘空间都去哪儿了,它还可以生成一个 PostScript 格式的名为 display.xdiskusage 的文件。在 Ubuntu 中安装 xdiskusage,只需使用如下命令:复制代码代码如下:sudo apt-get install xdiskusage若你想打开这个应用,你需要使用如下命令:复制代码代码如下: sudo xdiskusage一旦这个应用被打开,你将看到如下图所示的界面:BleachbitBleachBit 能快速地释放磁盘空间并不知疲倦地保护你的隐私。它可以释放缓存,删除 cookie,清除 Internet 上网历史,粉碎临时文件,删除日志,丢弃你所不知道存在何处的垃圾。为 Linux 和 Windows 系统而设计,它支持擦除清理数以千计的应用程序,如 Firefox, Internet Explorer, Adobe Flash, Google Chrome, Opera, Safari 等等。除了简单地删除文件,BleachBit 还包括许多高级功能,诸如粉碎文件以防止恢复,擦除磁盘空间来隐藏被其他应用程序所删除文件的痕迹,为火狐“除尘”,使其速度更快等。比免费更好,BleachBit 是一个开源软件。在 Ubuntu 中安装 Bleachbit,打开终端并运行如下命令:复制代码代码如下:sudo apt-get install bleachbit一张截图

从来没有一个人能把Flink讲的这么透彻

Java静态内部类、匿名内部类、成员式内部类和局部内部类

5大代码规则,守护程序猿世界的爱与和平!

友情链接

滇ICP备2023006006号-39