当前位置: 首页 > news >正文

【系统设计】2WTPS生产级数据处理系统设计Review

欢迎来到啾啾的博客🐱。
记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。
有很多很多不足的地方,欢迎评论交流,感谢您的阅读与评论😄。

目录

  • 反正能用的系统
  • 问题分析
  • 方案一:简单多实例增加些许容错
  • 方案二:任务调度机制
  • 方案三:Kubernetes+主备模式

反正能用的系统

几年前,我曾经参与过一个月工单10亿级别(TPS数万/秒)的系统开发,当时的架构设计大致如下。
图以数据流为导向,省去了一些微服务架构组件。

![[数据处理系统-Review.png]]

很显然,这个架构存在一个明显的问题:数据分区后由不同的服务专门处理,若这个专职的服务挂掉,该分区的数据在服务恢复前都将无法得到处理。

那么,我们应该怎么改善这个设计呢?

问题分析

  • 主要待解决的问题

    • 功能性问题
      专职服务挂掉后,分区数据得不到处理。

    • 拓展问题
      当前的数据分割方式是在系统设计时静态划分。如果数据量超出设计预期,系统处理不了,也不好拓展。

    • 性能问题
      不能保障数据均匀地分布在各个分区,也不能保障每个专职服务处理速度一致。可能Server1处理完数据了,Server2还有一半没有处理,服务器性能得不到充分利用。

  • 其他问题
    略…

方案一:简单多实例增加些许容错

每个专职服务都部署成多实例,从而提升容错能力,解决部分功能性问题。

多实例会带来一个问题:多个服务竞争同一批任务。

这是很简单的资源竞争问题,可以简单使用锁来避免资源竞争。
在分布式架构中,使用第三方存储即可解决,如Redis,ZooKeeper。
另外设计兜底机制,如果多个服务实例中存在不靠谱实例,竞争到了资源但是没有完成,使用告警机制重新竞争处理。
以及从底层设计支持幂等,防止重复消费带来问题。

  • 基于Redis或Zookeeper设计任务分片获取

关于任务:任务应该有一个唯一ID、状态(如:待处理、处理中、已完成、失败)、处理实例ID(可选,用于追踪)、尝试次数等字段。

实例需要尝试获取并锁定一个“未处理”的任务批次。
因此,我们需要一种方式来标识数据分片。
如果数据本身有连续ID或者可以按某种规则分批,那是最好的。如果不行,可能需要预先在DB中标记好批次,或者有一个专门的“任务池”表。为了简化,我们假设数据可以按ID范围划分。

简单流程图如下:
选定几个实例负责加载任务,所有实例从任务池中获取任务,并对任务加锁(Redis的SETNX)。
![[数据处理系统-Review-4.png]]

详细UML如下(AI生成):
![[数据处理系统-Review-5.png]]

但是这样设计容错率还是不够、且不能无法解决其他分区的动态资源分配问题。对所有服务来说性能也没有利用到极致。

方案二:任务调度机制

我们可以补充设计一个资源调度系统来解决所有问题。
简单草图如下:
![[数据处理系统-Review-3.png]]

很显然,我们需要有

  • 服务管理与检测
    需要获取服务状态以分配任务:需要知道服务实例的处理状态,哪些服务可以分配任务,以及还能接收多少数据也会损害服务性能。

  • 动态分区计算
    需要支持动态扩展服务。以及最快最好分配数据处理任务到服务,充分利用资源。
    ![[数据处理系统-Review-1.png]]

原来的数据库分库分表结构不做更改,需要分库分表来缓解数据查询压力。
调度服务需要获取数据与分配数据。
任务(数据)获取注意事项:需要能感知数据源数据量、数据概要信息(比如区间信息,用于分区)。获取连续数据、内存数据、多线程获取并汇总信息用于分配。
任务分配:要避免多个分配者竞争。

  • 容错设计
    如果调度服务挂掉了怎么办?
    管理服务注册表,服务状态检测。

很显然,我们可以使用Kafka来解决上述问题。任务均发送至Kafka,由Kafka的rebalance机制进行任务调度,且Kafka消费者组可以很大程序上解决容错问题。也较易扩展。

方案三:Kubernetes+主备模式

最后但是的团队在一次迭代中选择了容器化+主备模式的方式来解决容错问题。
即,为每个专职服务设置一个备用实例。并且将服务容器化。

http://www.xdnf.cn/news/622477.html

相关文章:

  • 大数据如何让智能物流和仓储管理更高效?从预测到自动调度
  • 【AI实战】从“苦AI”到“爽AI”:Magentic-UI 把“人类-多智能体协作”玩明白了!
  • 超详细网络介绍(超全)
  • YOLOv8损失函数代码详解(示例展示数据变换过程)
  • 如何对轨迹进行减速并保证在原来的轨迹上面
  • Python应用字符串格式化初解
  • [CSS3]Flex布局
  • C++中IO类(iostream、fstream和sstream)知识详解和应用
  • 负载均衡笔记
  • webpack的构建流程
  • 持续集成和部署
  • 每日Prompt:梦回大唐
  • uniapp判断ios或Android定位是否开启并跳转到系统设置
  • 老字号如何逆龄生长?解码数字突围战
  • 5.24本日总结
  • 高效大型语言模型推理优化综述
  • 怎么开发一个网络协议模块(C语言框架)之(三) 全局实例
  • 基于pycharm,python,flask,sklearn,orm,mysql,在线深度学习sql语句检测系统
  • 【uniapp 开发经验】小程序移动端新增页面适配指南
  • vue 引入配置的常量时,常量内部怎么引用 vue 中的值
  • Vue组件通信的 `$attrs`与`$listeners`的优先级
  • 信息收集与搜索引擎
  • RabbitMQ的详细使用
  • 深入理解设计模式:工厂模式、单例模式
  • QTabWidget垂直TabBar的图标和文本水平显示
  • Java 连接并操作 Redis 万字详解:从 Jedis 直连到 RedisTemplate 封装,5 种方式全解析
  • 第十七次CCF-CSP算法(含C++源码)
  • C++八股 —— 手撕定时器
  • QT之INI、JSON、XML处理
  • 深入理解Redis线程模型