Spring Boot业务系统如何实现海量数据高效实时搜索

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 我们都知道随着业务系统的发展和使用,数据库存储的业务数据量会越来越大,逐渐成为了业务系统的瓶颈。在阿里巴巴开发手册中也建议:单表行数超过500万行或者单表容量超过2GB才推荐进行分库分表,如果预计三年后数据量根本达不到这个级别,请不要在创建表时就分库分表。数据库最终都是存储在磁盘上,随着数据量变大,会导致数据操作变得缓慢,无论是计算还是IO,但是话又说回来,单表数据量大就一定要进行分库分表操作吗?答案是否定的,因为分库分表本身是一个“很重”的操作,这里就不卖关子了,直接来看看分库分表带来的以下问题和挑战

1.概述

我们都知道随着业务系统的发展和使用,数据库存储的业务数据量会越来越大,逐渐成为了业务系统的瓶颈。在阿里巴巴开发手册中也建议:单表行数超过500万行或者单表容量超过2GB才推荐进行分库分表,如果预计三年后数据量根本达不到这个级别,请不要在创建表时就分库分表。数据库最终都是存储在磁盘上,随着数据量变大,会导致数据操作变得缓慢,无论是计算还是IO,但是话又说回来,单表数据量大就一定要进行分库分表操作吗?答案是否定的,因为分库分表本身是一个“很重”的操作,这里就不卖关子了,直接来看看分库分表带来的以下问题和挑战:

  • 重构适配系统 本身我们的业务系统不可能一开始开发上线的时候就会分库分表,都是随着系统使用和时间推移数据量日益膨胀才考虑的,进行分库分表我们业务服务项目代码需要从单一数据库表适配成多库多表,这是一次极其繁重的重构任务,还涉及到数据迁移、备份、扩容等操作问题,该任务上线链路之长、风险之大不言而喻,这也是很多小公司即使数据量上来了也不会马上分库分表的原因吧。
  • 事务问题 目前数据库只能够实现本地事务,也就是在同一个数据库中,可以允许一组操作要么全都正确执行,要么都不执行,从而确保数据库的一致性。单从分区角度出发,实际上仍然是一张表,一个库中,它不会存在事务一致性的问题,但是会使得事务变得非常复杂。而分库分表会涉及到分布式事务,目前数据库并不支持跨库事务,所以在这一块需要解决分布式事务可能带来的不一致性
  • 分页、排序、聚合函数问题 分页需要按照执行的字段进行排序,当排序字段就是分片字段的时候,通过分片规则就比较容易定位到指定的分片;当排序字段并非分片字段的时候,就需要在不同分区、分表中进行排序并且返回,然后再将不同分区、分表中返回的结果集进行汇总和再次排序,最终得到返回结果。取得页数越多,性能受影响也就越大。因为在分区、分表的时候都已经限定了分片字段,而其他字段是跟着分片的字段被分到不同的区域或者表中,这样各个分区、分表中的数据可能是随机的,为了排序的准确性,需要将所有分区、分表节点的前的数据都排好序做合并,最后进行整体排序,这样的操作是非常耗费CPU和内存资源的,所以在分区、分表的情况下、分页数越大,系统的性能也会越差。同样、在使用聚合函数,如Max、Min、Sum、Count进行计算的时候,也会像排序那样在每个分区、分表执行相应的函数,然后再将各个分区、分表的结果集进行汇总和再次计算,最终将结果返回。
  • 全局主键避免重复 单表主键id自增能够保证id不重复,但是分库分表之后,多张表就不能保证主键id不重复了,这时候就要使用分布式id算法进行生成。

  • 数据迁移、扩容问题 随着数据持续增加分表后还需要进行动态新增表时,这个时候就要考虑数据迁移以及扩容问题。一般做法是先读出历史数据,然后按照指定的分表规则再将数据写入各个分表中。这本身就是繁杂之事。

当然以上问题并不是说分库分表是一个不可取的方案,现在分库分表方案在很多公司系统都有应用的,这里想表达的是需要根据个人公司业务系统数据特点,综合评估做权衡来选择解决数据量大的实施方案。

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用

Github地址https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公众号Shepherd进阶笔记

2.业务数据量大的解决方案

2.1 数据归档

来分析一个美团业务场景:我们日常每天点外卖,平时会去查看一年前的订单,看看一年前吃了什么吗?答案是几乎不会,或者说这种查询的请求量比较小,出现这种请求大概是有人问你很早之前点的那家外卖好吃,但是你不喜欢记不得了,你帮她查找一下的场景吧~~。由此可见,我们可以根据这一特点进行数据历史归档,即数据做冷、热区分存储。当然这个区分时限要根据自身系统数据特点来指定时限是一年还是半年....这样就能保证我们高频查询的热数据量不大了。

在查询历史数据表时,可以限制查询条件如必须选择日期范围,日期范围不能超过N个月等等从而减轻查询压力。处理历史存量数据比较简单,因为历史数据一般不会变更了,所以一般只需要两个步骤进行归档:

  • 迁移满足限定数据到指定历史归档表
  • 根据主键分批删除业务原表数据,从而降低业务数据量

这里需要强调一下,不能一次性删除所有数据,因为数据量太大可能会引发超时,锁表,长事务等问题,而是应该根据ID分批删除,例如每次删除500或1000条数据。操作步骤如下:

SELECT MAX(id) AS maxId FROM t WHERE create_time < '指定时间'

查出满足归档条件的数据最大id,接下来就可以分批归档和删除了,初始化 startId=0,每次归档500条

select * into t_bak from t where id > startId and id <= maxId limit 500

查询归档表获取最大id:maxBakId,赋值给startId方便下次分批归档删除

select max(id) from t_bak

数据删除:

delete from t where id <= maxBakId

重复上面的归档删除操作,直至startId到maxId结束

2.2 读写分离和热点缓存

大部分的业务系统场景都是读多写少,读写比一般都在几十左右,平均每发生几十次查询请求,才有一次更新请求。换句话来说,数据库需要应对的绝大部分请求都是只读查询请求。针对这种情况我们可以通过读写分离方案来降低数据库压力。

主库负责执行应用程序发来的所有数据更新请求,然后异步将数据变更实时同步到所有的从库中去,这样,主库和所有从库中的数据是完全一样的。多个从库共同分担应用的查询请求。

对于一些高频访问的热点数据,我们可以提前预处理使用redis缓存,这样也可以有效降低数据库的压力。

2.3 同步异构数据源

我们知道MySQL会随着数据量增大而查询变慢,那么我们换成其他数据源来完成OLAP查询场景不就得了。特别是在当下大数据时代,现在互联网公司一般都具备与之规模相对应的大数据服务或者平台,那么作为业务开发者要善于应用公司大数据能力,减轻业务数据库压力。比如我们可以把数据同步到ES、HBASE等平台。

使用elasticsearch来实现海量数据搜索就是一个不错的选择,elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。能够达到实时搜索,稳定,可靠,快速,安装使用方便。但是如何实现MySQL数据同步elasticsearch呢?

答案是阿里的开源项目Canal,就是用来解决异构数据源数据同步这个问题的,Canal项目利用了MySQL数据库主从同步的原理,将Canal Server模拟成一台需要同步的从库,从而让主库将binlog日志流发送到Canal Server接口。Canal项目对binlog日志的解析进行了封装,我们可以直接得到解析后的数据,而不需要理会binlog的日志格式。而且Canal项目整合了zookeeper,整体实现了高可用,可伸缩性强

2.4 分库分表

如果通过以上:历史数据归档、数据同步异构数据源、读写分离、热点缓存都不能解决MySQL单表数据压力的,这时我们只能拆分数据表,即把单库单表数据迁移到多库多表中。这也是一线流量互联网公司需要面对的,你试想一下淘宝双11那几天要上架多少商品,产生多少订单,这已经不是前面的方案所能解决了,只能分库分表了。当然分库分表是一个复杂的操作,也不是三言两语就能全面讲清楚的,且也不是我们今天主要议题,所以我这里粗略概述一下,感兴趣的可自行查阅相关资料。

垂直拆分

垂直拆分就是按照业务拆分,我们将电商数据库拆分成三个库,订单库、商品库。支付库,订单表在订单库,商品表在商品库,支付表在支付库。这样每个库只需要存储本业务数据,物理隔离不会互相影响。

水平拆分

按照垂直拆分方案,现在我们已经有三个库了,平稳运行了一段时间。但是随着业务增长,每个单库单表的数据量也越来越大,逐渐到达瓶颈。

这时我们就要对数据表进行水平拆分,所谓水平拆分就是根据某种规则将单库单表数据分散到多库多表,从而减小单库单表的压力。

水平拆分策略有很多方案,最重要的一点是选好ShardingKey也就是按照哪一列进行拆分,怎么分取决于我们访问数据的方式

比如我们可以根据时间范围分片,根据创建时间分配到不同的表中。也可以根据哈希分表,哈希分片可以较为均匀将数据分散在数据库中。我们现在将订单库拆分为4个库编号为[0,3],每个库4张表编号为[0,3],根据分布式id%编号落库,当然也有其他分片方案,这取决于你们公司业务数据特点。

3.如何实时同步数据到elasticsearch支持海量查询

我一开始就强调了分库分表带来的问题,可见今天的重点肯定不是采用分库分表来解决数据量大的问题的,所以我接下来来讲讲我司的解决方案:数据归档+读写分离+同步异构数据源

数据归档可以有效降低数据库数据量,读写分离可以降低单数据库的读写压力,异构数据源es满足日常查询性能要求。

数据归档的操作步骤前面说过了,至于数据库读写分离实现方案等后续有时间再分析一波,今天主要讲讲如何高效实时同步elasticsearch满足查询要求。直接看架构图:

数据同步elasticsearch大概有两种:

1.针对代码中进行数据库的增删改操作时,同时进行elasticsearch的增删改操作。这种方式代码侵入性强,耦合度高,实时性高,改造起来比较痛苦,因为你不能错过任何一个增删改的地方同步操作es,否则就会出现数据不一致问题。

2.利用监听mysql binlog同步,实时性强,对于应用无任何侵入性,且性能更好,不会造成资源浪费。正好阿里巴巴开源的canal就是干这个的,完美解决问题。通过上面的架构图知道可以通过canal client拿到canal server对binlog的解析直接同步到es,但是这种方式处理比较慢,等于我们是一条一条的去同步,很多情况下es的索引表是一张大宽表,是来自MySQL几张表join的信息,这要求我们同步的时候还要根据主键通过join sql语句查出数据再同步,自然就更慢了。所以要使用消息队列kafka进行数据削峰填谷,批量操作是保证实时性的关键。

4.总结

以上全部就是我们对海量数据实时搜索的解决方案浅析,各有利弊。我们可以根据自身的业务数据情况选择合适的方案即可,切勿动不动就来分库分表,显得有点不知深浅。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
2月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
155 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
14天前
|
XML Java 数据库连接
SpringBoot集成Flowable:打造强大的工作流管理系统
在企业级应用开发中,工作流管理是一个核心组件,它能够帮助我们定义、执行和管理业务流程。Flowable是一个开源的工作流和业务流程管理(BPM)平台,它提供了强大的工作流引擎和建模工具。结合SpringBoot,我们可以快速构建一个高效、灵活的工作流管理系统。本文将探讨如何将Flowable集成到SpringBoot应用中,并展示其强大的功能。
58 1
|
23天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
1月前
|
存储 安全 Java
打造智能合同管理系统:SpringBoot与电子签章的完美融合
【10月更文挑战第7天】 在数字化转型的浪潮中,电子合同管理系统因其高效、环保和安全的特点,正逐渐成为企业合同管理的新宠。本文将分享如何利用SpringBoot框架实现一个集电子文件签字与合同管理于一体的智能系统,探索技术如何助力合同管理的现代化。
62 4
|
1月前
|
前端开发 Java Apache
SpringBoot实现电子文件签字+合同系统!
【10月更文挑战第15天】 在现代企业运营中,合同管理和电子文件签字成为了日常活动中不可或缺的一部分。随着技术的发展,电子合同系统因其高效性、安全性和环保性,逐渐取代了传统的纸质合同。本文将详细介绍如何使用SpringBoot框架实现一个电子文件签字和合同管理系统。
59 1
|
1月前
|
文字识别 安全 Java
SpringBoot3.x和OCR构建车牌识别系统
本文介绍了一个基于Java SpringBoot3.x框架的车牌识别系统,详细阐述了系统的设计目标、需求分析及其实现过程。利用Tesseract OCR库和OpenCV库,实现了车牌图片的识别与处理,确保系统的高准确性和稳定性。文中还提供了具体的代码示例,展示了如何构建和优化车牌识别服务,以及如何处理特殊和异常车牌。通过实际应用案例,帮助读者理解和应用这一解决方案。
|
2月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
223 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
2月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
162 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
2月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
56 3
基于Java+Springboot+Vue开发的美容预约管理系统
|
2月前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)

热门文章

最新文章