前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >后端服务重构

后端服务重构

原创
作者头像
HaveTryTwo
发布2024-01-22 00:15:51
1340
发布2024-01-22 00:15:51

一、背景

随着项目进展,现有模块在功能和非功能特性(包括可用性、性能和维护性)上可能不再符合需求,因此,对这些模块进行重构变得很有必要,以提升系统的整体效能并解决当前面临的挑战。例如,在项目初期,为了迅速上线并满足业务需求,我们可能会采用统一的架构来处理读写操作。然而,随着产品需求的演变,原有架构可能难以同时高效处理读取操作的多样化筛选需求和历史数据查询,以及写入操作的实时性和高成功率。在这种情况下,一种可行的重构策略是采用CQRS架构,它将读写操作彻底分离,并使用不同的存储解决方案来优化各自的性能和可用性。

二、困难

在重构过程中,我们首先明确重构的目标,如引入新功能、性能提升、增强系统可用性等。同时,我们也专注于重构本身必须考虑的关键事项,具体包括:

  • 功能一致性:由于底层系统与上层业务通过定义明确的接口契约进行交互,重构不应引起功能上的变化,以避免破坏业务逻辑并确保结果符合预期。
  • 数据一致性:重构可能涉及对数据链路的调整,例如更换数据库组件以提高可用性和性能。在这种情况下,必须仔细考虑不同存储系统间的差异,确保逻辑层和存储层的协同工作,以保持数据在重构前后的一致性。

三、思路

后台重构可以根据服务的不同需求划分为以下几类:

  • 逻辑模块重构:专注于优化代码逻辑和业务流程。
  • 存储模块重构:改进数据存储和检索机制。
  • 逻辑与存储模块联合重构:同时升级业务逻辑和数据存储结构。

对于这三种不同的重构场景,我们将分别制定相应的重构策略。

1、逻辑模块重构

逻辑模块重构的原因多样,例如,未进行充分的领域建模可能会造成业务逻辑混乱,进而导致维护成本剧增。通过采用分层设计,我们可以将逻辑模块划分为控制层、实体层和DAO层,并依托业务建模对逻辑进行精细化重构。这样的重构不仅清晰地界定了各层的职责,还提高了模块的可维护性和可扩展性。重构前后,模块的效能得到了显著提升。对应重构前后的效果:

在重构过程中,我们主要面临的挑战是确保“功能一致性”,即在重构前后逻辑模块的功能应当保持不变。为了应对这一挑战,我们引入了一个代理模块,专门负责验证读接口功能的一致性。下面是相应的迁移架构图:

代理模块实现验证流程具体如下:

  • 从旧架构读取数据并提供给上层应用。
  • 同时从新架构读取数据,并核对其与旧架构数据的一致性。若发现不一致,则需调整新架构的代码。

在上述架构中,验证主要针对读取接口。对于写入接口,新旧架构是互斥的,即不能同时在两个架构中成功写入。只能从一个架构平滑迁移到另一个。这里的风险在于,新架构的写入接口可能与旧架构不一致,从而可能导致数据错误。为了解决这个问题,我们可以采取以下策略:

  • 对于简单模块,通过单元测试和集成测试来确保写入接口的功能一致性。
  • 对于那些逻辑复杂且大规模重构的写入接口,单元测试和集成测试可能不足以全面保障覆盖率。错误的写入操作可能导致严重后果,例如资金处理异常。为了确保系统的稳定运行,我们可以引入一个额外的存储模块来进行早期的旁路验证。具体的架构设计如下所示:

为了确保逻辑模块重构的成功,我们采用了上述机制,以实现重构目标的同时,确保功能上的一致性,从而顺利达成预定的重构成果。

2、存储模块重构

存储模块重构的动因是多方面的。例如,由于原存储模块不支持CAS(比较并交换)操作,这增加了逻辑架构的复杂性,并进一步导致运营管理变得繁琐。采用能够支持CAS操作的新组件,可以显著简化逻辑层的实现。以下是重构前后效果的对比:

面对这类重构,最大的挑战在于保证“数据一致性”。这是因为更换存储组件后,由于各组件解决问题的目标不同,可能会在存储结构、数据结构和索引结构上出现显著差异。因此,确保在不同存储组件之间进行重构前后数据保持一致性至关重要。下面是一个基础的数据迁移架构示例:

优化后的基本流程如下:

  • 构建新的存储模块,并配置相应的代理模块。
  • 实施双写策略:代理模块同时向新旧存储模块转发请求,以保持数据同步。
  • 执行数据迁移:通过迁移模块,将数据平移到新的存储模块,并在必要时进行数据转换。
  • 进行数据校验:代理模块从新存储模块读取数据以进行验证。
  • 完成全面验证:确保新旧存储模块之间的数据完全一致。
  • 切换读操作:将所有读取请求重定向至新的存储模块。
  • 切换写操作:停止旧架构的写入操作,完全过渡到新架构。

在整个过程中,为确保数据一致性,我们需要关注以下几个关键点:

1、数据写入的一致性:确保双写和数据迁移的准确性,这可能因组件的不同而有较大差异。常见的策略包括:

  • 采用CAS(Compare-And-Swap)机制:在写入过程中,只接受最高版本的数据,确保双写和迁移操作使用统一的版本号系统。
  • 利用存储组件的文件分层机制:使用LSM(Log-Structured Merge-tree)存储引擎,利用文件层次结构中数据的新旧优先级,将双写数据迁移到更新层,同时将旧数据写入较旧层,以此确保数据的准确性。这种方法对于没有CAS机制的情况尤其有效。
  • 结合存储数据与增量oplog(操作日志):在这种方法中,不进行双写,而是先迁移数据,然后将增量操作日志同步到新的存储组件。在追赶上操作日志后,再将写操作切换到新架构。这种方法可能需要短暂的写暂停来确保数据同步,适用于没有CAS机制的组件。
  • 细粒度锁定写入:在系统中实现逻辑,将多个键根据特定条件组合成一个更大的键,例如按用户粒度。这样可以按用户粒度迁移所有数据,然后启动用户级别的双写。这种方法的优点是适用性强,但实现的逻辑复杂度较高。

2、为了确保数据读取的一致性,我们需要实施以下措施:

  • 代理模块的读取一致性验证:从业务层面确保不同存储之间读取到的数据是一致的。
  • 为确保数据一致性,必须在存储层面对新旧架构的数据进行全面校验。针对性能考量,特别是在处理大规模冷数据时,关键在于采用高效策略,以优化验证流程的速度和效率。

通过实施上述机制,我们确保了存储模块重构的顺利完成。正如所讨论的,存储模块的复杂性主要源于其数据相关性;因此,在决定进行重构之前,必须细致评估各项重构细节,包括数据规模、迁移策略、可接受的迁移时间窗口以及数据一致性保障措施。这样做可以确保整个过程处于可控状态,避免因数据异常导致的重迁移,这种情况下的成本通常非常高昂。

3、逻辑模块+存储模块重构

在实际业务中,我们常遇到这样的情况:为了满足业务需求,不仅逻辑模块需要优化,存储模块也需重新选择合适的技术方案。以下是重构前后效果的对比:

此类重构不仅要应对逻辑模块重构时的“功能一致性”问题,还要解决业务存储模块重构时的“数据一致性”挑战,两者都必须得到充分考虑。以下是相应的重构架构示例:

在迁移过程中,为确保“功能一致性”与“数据一致性”,我们将逻辑模块迁移与存储模块迁移相结合。具体来说,通过引入代理模块来核验“功能一致性”,并通过数据校验来确保“数据一致性”。尽管在具体实施上存在一些差异,但这两种方法都是为了达到迁移的准确性和完整性。

四、预期效果

重构是项目发展中不可避免的一环。关键在于把握重构的核心要点:首先明确重构的目标并集中解决关键问题,其次确保在重构过程中维持“功能一致性”和“数据一致性”。这样做可以使整个重构过程更加流畅,并确保重构带来的收益远大于其成本。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、困难
  • 三、思路
    • 1、逻辑模块重构
      • 2、存储模块重构
        • 3、逻辑模块+存储模块重构
        • 四、预期效果
        相关产品与服务
        数据保险箱
        数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档