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

news2024/11/23 1:20:48

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进阶笔记

交流探讨qun:Shepherd_126

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.总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/948127.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

科创板50etf和科创50etf的区别不同点?一定要看!

很多在交易期权的时候会对科创50ETF期权和科创板50ETF期权标的物选择有疑问&#xff0c;两者与有何区别呢&#xff0c;选择哪个比较合适&#xff0c;别着急&#xff0c;下文为大家介绍科创板50etf和科创50etf的区别不同点&#xff1f;一定要看&#xff01;本文来自&#xff1a;…

谁做的方案,竟把财务数据分析套路都摸透了

来不及计算组合多变又复杂量大的财务数据分析指标&#xff1f;不知道该用哪些财务数据分析方法技巧&#xff1f;不知道怎么把信息量巨大的财务数据分析报表做得易读易理解&#xff1f;别担心&#xff0c;奥威BI数据可视化工具都把套路摸透了&#xff0c;并提出一套系统、标准化…

kafka+Kraft模式集群+安全认证

Kraft模式安全认证 前章内容聊到了Kafka的Kraft集群的配置及使用。本篇再来说说kafka的安全认证方面的配置&#xff0c;。 Kafka提供了多种方式来进行安全认证&#xff0c;包括身份认证、授权和加密传输。一些常用的Kafka安全认证方式&#xff1a; SSL/TLS&#xff1a;使用S…

go的数据结构-变量的大小是0字节

查看变量大小 unsafe.Sizeof(int(0)) 变量&#xff1a; 指针&#xff1a; int和指针大小跟随系统字长&#xff0c;空结构体没有任何成员&#xff0c;是有地址没有长度&#xff0c;所有空结构体都指向同一个结构体地址&#xff08;不被包含在其他结构体中&#xff09;zerobas…

OpenHarmony Meetup 2023 广州站圆满举办,城市巡回全面启航

“OpenHarmony正当时——技术开源”OpenHarmony Meetup 2023城市巡回活动&#xff0c;旨在通过meetup线下交流形式&#xff0c;解读OpenHarmony作为下一代智能终端操作系统的新版本及成果转化&#xff0c;提升开发者对OpenHarmony的关注度&#xff0c;普及OpenHarmony开发技能&…

高效利用隧道代理实现无阻塞数据采集

在当今信息时代&#xff0c;大量的有价值数据分散于各个网站和平台。然而&#xff0c;许多网站对爬虫程序进行限制或封禁&#xff0c;使得传统方式下的数据采集变得困难重重。本文将向您介绍如何通过使用隧道代理来解决这一问题&#xff0c;并帮助您成为一名高效、顺畅的数据采…

桌面端后台项目笔记

套用模板 vue-pure-admin 所用主要框架笔记 1. electron app const { app } require(electron) app.on(事件名, () > {} // 回调函数)常用事件 will-finish-launching 当应用程序完成基础的启动的时候触发ready&#xff1a;electron完成初始化时触发window-all-close…

A10的pll reconfig

一、前言 我之前写过《quartus动态配置pll reconfig》&#xff0c;讲的是A5的pll reconfig。 这次调A10&#xff0c;结果发现寄存器配置、地址、操作流程都变了&#xff0c;不能无脑移植。 二、寄存器配置 1&#xff0c;A5的寄存器配置如下&#xff1a; 其中基地址如下&…

皮卡丘靶场搭建遇到的问题大全

该博客记录我在安装皮卡丘靶场中遇到的一些问题。 1、 phpstudy_pro启动Mysql失败 自己电脑开启了mysql服务&#xff0c;使用winr&#xff0c;services.msc&#xff0c;找到自己的mysql服务&#xff0c;关闭。再次尝试使用phpstudy_pro启动mysql&#xff0c;成功解决。 2、皮…

基于Matlab实现生活中的图像信号分类(附上源码+数据集)

在我们的日常生活中&#xff0c;我们经常会遇到各种各样的图像信号&#xff0c;例如照片、视频、图标等等。对这些图像信号进行分类和识别对于我们来说是非常有用的。在本文中&#xff0c;我将介绍如何使用Matlab来实现生活中的图像信号分类。 文章目录 介绍源码数据集下载 介…

ElasticSearch学习5-- 使用RestClient查询文档

1、查询基本步骤 1、创建SearchRequest对象 2、准备Request.source()&#xff0c;也就是DSL。 QueryBuilders来构建查询条件 传入Request.source() 的 query() 方法 3、发送请求&#xff0c;得到结果 4、解析结果&#xff08;参考JSON结果&#xff0c;从外到内…

美团 Flink 资源调度优化实践

摘要&#xff1a;本文整理自美团数据平台计算引擎组工程师冯斐&#xff0c;在 Flink Forward Asia 2022 生产实践专场的分享。本篇内容主要分为四个部分&#xff1a; 相关背景和问题解决思路分析资源调度优化实践后续规划 点击查看原文视频 & 演讲PPT 一、相关背景和问题 在…

OpenSSL 远程代码执行漏洞 CVE-2022-1292 升级方案及步骤

升级方案 升级步骤 1.查看版本号 命令:openssl version 2.下载安全版本openssl: openssl官网 下载 openssl-1.1.1o.tar.gz 3.编译安装 在/usr/lib/下创建目录openssl 输入命令: mkdir openssl 将下载的包openssl-1.1.1o.tar.gz放到这个目录,并解压 输入命令: tar -xv…

SAP 之IMG/SPRO解释

一、IMG是什么 二、使用步骤 1.举例 总结 一、IMG是什么 IMG-IMplementation Guide&#xff0c;是实施指引的简称&#xff0c;事务代码是 SPRO-SAP Project Reference Object。IMG是SAP中用于定制系统以满足业务要求的工具&#xff0c; 二、使用步骤 1.举例 例如&#xff0c…

保姆级教程之SABO-VMD-SVM的西储大学轴承诊断

之前写过一篇优化核极限学习机的轴承诊断&#xff0c;今天再出一期基于SVM的轴承诊断。 依旧是包含了从数据处理&#xff0c;到减法优化器SABO算法优化VMD参数&#xff0c;再到支持向量机的故障诊断&#xff0c;实现故障诊断的全流程&#xff0c;其他类型的故障诊断均可参考此流…

GrapeCity Documents V6.0 Update 2发布,新增支持SpreadJS的.sjs文件格式

近日&#xff0c;GrapeCity Documents 正式迎来其V6.2 的发布更新&#xff0c;能够支持 SpreadJS 中 .sjs 类型的文件。这一重大更新将为用户带来更多地惊喜。 .sjs文件有两个关键优势&#xff1a;空间更小且导入导出速度更快。通过采用 .sjs格式&#xff0c;GcExcel实现了更高…

云计算环境中高性能计算的挑战与对策

文章目录 云计算中的高性能计算挑战1. 资源竞争&#xff1a;2. 网络延迟&#xff1a;3. 数据传输效率&#xff1a;4. 虚拟化开销&#xff1a;5. 节点异构性&#xff1a; 高性能计算在云计算环境中的对策1. 定制化虚拟机镜像&#xff1a;2. 弹性资源调整&#xff1a;3. 高效数据…

【Sql】把数据库字段用函数根据逗号分裂成列表,然后判断列表中是否包含目标值

【Sql】把数据库字段用函数根据逗号分裂成列表&#xff0c;然后判断列表中是否包含目标值 【1】问题描述【2】Oracle内置函数解决【3】mysql的内置函数INSTR()【4】mysql的内置函数FIND_IN_SET() 【1】问题描述 数据库中【库信息db】和【集群信息cluster】是一对多的关系&…

学弟学妹们!要开学了,这些好物一定要提前备

开学的脚步近了&#xff0c;近了&#xff0c;神兽归笼&#xff0c;万物更新&#xff0c;大家迎接开学季的阵仗堪比迎接春天了。灵魂发问&#xff1a;开学装备备齐了吗&#xff1f;神兽们的情绪调整好了吗&#xff1f;自己要不要再回回炉&#xff0c;充充电&#xff1f;这次整理…

javacv 基础04-读取mp4,avi等视频文件并截图保存图片到本地

javacv 读取mp4,avi等视频文件并截图保存图片到本地 代码如下&#xff1a; package com.example.javacvstudy;import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter;import javax.imageio.Im…