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

分布式系统中数据存储方案实践_0

时间:2023-03-13 04:37:00 科技观察

一、背景在项目开发过程中,对数据存储能力的依赖无处不在。在项目初期,相对于系统层面的组件选择和框架设计,由于数据量较小,在存储管理方面通常容易不堪重负。低估了,当项目开发进入中后期,系统的复杂度很大程度上来自于数据层面;从常规的微服务架构系统来看,系统中的数据存储可以分为以下几个模块:组件库、应用库、业务库、公共库、中间件数据、第三方;不同的场景对数据存储能力有不同的要求和依赖;组件库:在微服务架构下,很多基础框架组件都依赖于数据的持久化存储,保证服务能力的稳定性和可控性,避免异常情况下的数据丢失;应用库:作为系统中的应用层,需要具备记录和识别请求动作的能力,存储很多拦截和过滤的规则信息,用于维护底层业务服务的安全和稳定;业务库:作为系统中的核心数据资产,对业务数据的存储和管理有着极高的要求,必须对数据的变更有一定的限制。评估能力,在数据扩容的情况下,提前做好系统测试和拆分方案,确保业务的稳定和持续发展;公共库:系统中大部分业务可能依赖的能力,对于公共库及其对应的服务而言,其吞吐量和并发能力,必须支持所有依赖于该业务的并发服务;中间件:常见的中间件如:缓存、消息队列、任务调度、搜索引擎等,都具有数据存储的性质,只是在实现方式上会有区别;第三方:大部分系统都或多或少地依赖一些第三方仓库,比如Git代码仓库、Maven包仓库、Docker镜像仓库、行为埋点数据、OSS文件服务等;2.Framework组件微服务架构中常见的组件,如GateWay路由网关、Nacos注册配置中心、Seata事务管理器等,都需要数据存储机制;路由网关:通常在网关库中维护各个服务的路由地址和规则策略,虽然黑白名单、流量管理等数据量不大,但鉴于网关服务需要支持流量高并发,对数据读取性能有要求,尽量减少网关层的请求耗时;注册配置:统筹管理各个服务的配置数据,动态维护服务的注册状态,对存储稳定性和数据安全性有极高的要求。需要保证各个环境是隔离的,不能暴露生产环境的配置信息;事务管理:Seata组件提供高性能和易于使用的分布式事务管理能力。常规的事务调度过程需要依赖几个关键的记录表,通常需要一个分布式事务管理的接口,这基本上是处理服务中的核心业务。一定要保证稳定性,还要支持高并发;3、应用管理的应用层相对在系统的上层,如常见的门面服务、管理服务、控制中心等,通常会在相应的库中存储请求记录、具体的过滤拦截策略、异常响应日志、页面展示管理等;一般来说,控制中心统一管理和维护应用库的配置数据,可以直接在各自的应用服务中查询;从而避免重复实现各种基础功能,同时将系统级管理置于控制中心服务中,保证数据修改的单一入口,从而更好地监控操作日志;4、业务数据是系统的核心数据资产。业务数据的精准维护一直是核心问题。除了为必要的业务流程提供数据存储外,还支持数据的动态查询和分析,并且会随着业务的发展,数据的结构和体量不断发生变化;分库分表:当业务过于复杂时,会考虑分库,保证各业务块的相对稳定性;当某些表的数据量巨大时,会采用分表的方式,避免表的处理时间过长,从而影响整体性能;业务数据库表的拆分和基于微服务的管理是目前主流的架构模式;数据维护:随着业务的快速发展,数据量和结构会相应扩大,从而导致质量问题。因此,在日常开发中,很多版本都会进行数据维护,例如:数据清洗、数据迁移、结构拆分等,以更好地管理数据保证业务连续性;微服务架构下数据的动态维护是一个比较复杂的过程。为保证处理过程不停止,需要依赖中间调度服务来完成数据维护过程。在此期间,应用服务优先从旧服务和库中读取未处理的数据,存储新数据和查询新服务,直到整个维护过程结束,然后根据预设的标识关闭旧服务请求和下线;5.缓存管理通常缓存可以有效解决数据查询中的性能问题,比如访问量大、变化不频繁的热点数据,或者过程中经常加载的常量配置。另外,锁机制也是基于Redis的,一般是通过键值对来管理数据的读写;值得注意的是,Redis库和业务库之间通常存在一定的对应关系。比如订单业务库对应订单缓存库,不建议将订单业务库的数据体写入其他缓存,统一通过订单服务接口访问即可,保证每个微服务的数据独立性;6、当搜索引擎业务量较大时,难以实现对数据整体的条件检索机制,如常见的核心业务数据、系统产生的日志或action埋点数据;需要引入搜索引擎的能力,涉及到将业务数据库数据同步到ElasticSearch组件的过程;在不同的业务场景下,通常采用不同的数据同步策略;对于即时性高的业务数据,通常数据存储后执行写入;日志数据量大,进程解耦高,自然有一定延迟;可以基于定时任务拉取分析类的数据;不管是什么数据路径,都需要关注业务库和索引之间的数据结构和一致性;7.消息队列消息队列是进程解耦的常用组件,消息数据的生产和消费需要一定的监控手段。一旦复杂流程中断,需要进行二次重试,需要调度各种参数和消息内容结构,以保证流程的最终完整性;通常消息队列处理的业务复杂度很高,所以流程设计的合理性比较高。如果消息的生产和消费路径没有统一管理,在微服务架构下基于MQ对流程进行分段解耦,如果出现流程中断或者系统异常的情况,很难做二次调度关于相关逻辑;8.日志信息作为系统中的一个基本组成部分,记录的相关数据在日常开发和维护过程中是非常重要的。从整体数据来看大致可以分为系统操作日志,通常基于ELK,业务日志,需要有业务语义,通常采用AOP切面模式进行定制化开发;由于日志数据量大,业务日志一般存储在单独的数据库中,并同步到搜索引擎,系统操作日志按时间段或文件大小策略直接写入搜索引擎;值得注意的是,存储日志数据的ES也需要独立部署,避免与核心业务数据放在一起。一起,流量突然增加时产生的日志数据会非常大;9.文件管理文件管理是系统中一个复杂的模块。因为涉及到IO流,容易造成内存问题,所以文件服务基本都是独立部署的。鉴于文件数据丢失后难以找回,文件通常存储在OSS云端,文件服务中记录了每个文件的地址和描述以及业务应用场景;由于文件类型多种多样,如:PDF、Excel、Word、Csv、Xml等,数据处理方式也各不相同。如果文件太大,则需要将其切成块。同时,文件管理过程需要许多商定的规则。比较常见的有大小限制、命名信息、类型和编码等。10、持续集成代码项目在版本交付过程中,会产生多个分支和包文件。持续集成过程中还涉及多个文件仓库的维护和管理,例如:Git代码仓库、Maven私有产品仓库、Docker镜像仓库、脚本文件仓库等;通过Jenkins服务协调多个仓库,实现流程自动化;对于仓库中存储的各种版本的打包文件,在微服务架构下,存在不同服务依赖同一个服务的不同版本的情况,不排除新旧版本接口存在逻辑冲突的问题。这时候可能需要回滚版本,重新依赖原来的分支包,再寻求解决问题的办法;代码项目中涉及的相关存储基本都是使用第三方云仓库。维护比较简单;十一、参考源码应用仓库:https://gitee.com/cicadasmile/butte-flyer-parent组件打包:https://gitee.com/cicadasmile/butte-frame-parent