本文章为参加2024 ospp Milvus社区的赛题:与 Kubernetes 进行集成增强 seata-ctl 的运维能力,做的相关工作后,根据导师的要求撰写的文档。

该项目已经中选OC.

1.技术方案:

1.1 SeataServer 资源的部署、扩缩容、删除等功能:

1.1.1 设计目标:

当前用户可以使用incubator-seata-k8s在k8s集群上通过yml配置的方式部署k8s集群,但是这种方式需要准备yml文件,而且不具备其他功能,实用性不太高。

本设计的目标是让用户可以通过简单的命令就可以实现部署的功能,不需要自己编写yml文件,而且可以通过简单命令实现缩扩容,删除等功能。

1.1.2 命令设计:

该设计本质上是通过用户命令转化为yml配置文件再发送到k8s集群上部署的过程,追求的应该是命令尽可能的简单,降低用户的学习和使用成本。

1.1.2.1 部署资源:

1.1.2.1.1 命令:
seata-ctl deploy 
1.1.2.1.2 参数:

incubator-seata-k8s定义的完整yml文件在https://github.com/apache/incubator-seata-k8s/blob/master/config/crd/bases/operator.seata.apache.org_seataservers.yaml可以找到,重要的配置如下:

  1. serviceName: 用于定义 controller 部署的 Headless Service 的名称。

  2. replicas: 用于定义 Seata Server 的副本数量

  3. image: 定义了 Seata Server 的镜像名称

  4. store.resources: 用于定义挂载的存储资源要求

为这个四个参数分别设计一个命令,其中必须指定的是replicas,其他的为用户可选,如果不选择就是用默认值。同时为该条配置指定名称name

同时制定持久化yml命令persist,用于将此配置文件持久化。

完整的命令如下:

seata-ctl deploy  --name deploy1 -- replica 3 --storage 5Gi --serviceName SeataServer --image seataio/seata-server:latest --persist true

为了让用户能知道具体执行的yml是什么,在用户运行此命令后,会在控制台输出包含这几个核心标签的yml文件(如果用户不配置持久化的话,如果配置就直接生成文件即可)(类似mockgen的方式),并显示执行结果。

同时,可能有用户需要使用yml文件进行部署,seata-ctl同时提供根据yml文件部署的方式,具体命令为:

seata-ctl deploy --name deploy1 --file seata.yml

这样运行命令,就不需要展示yml文件,同时出现其他参数也会被视为非法而显示错误信息。

1.1.2.2 删除资源:

1.1.2.2.1 命令:
seata-ctl undeploy
1.1.2.2.2 参数:

提供两个参数:

name:部署资源时的名字

servername:资源的种类

这两个命令只能选择一个,选择多报错,找不到对应的名称也报错。

1.1.2.3 扩容/缩容:

1.1.2.3.1 命令:

k8s中使用scale(规模)这个词进行扩缩容,在这里同样使用这个单词。

seata-ctl scale
1.1.2.3.2 参数:

提供两个参数:

name:部署资源时的名字

replica:新的机器数量

进行命令的同时,如果进行了持久化则同步修改配置文件。

1.1.2.4 展示状态:

1.1.2.3.2 命令:
seata-ctl status
1.1.2.3.3 参数:

提供一个参数:

name:部署资源时的名字

1.1.2.3.4 展示:

展示状态时,为了增加可读性和美观程度,采用tui的方式进行展示。

go语言的tui有很多,拟采取tview(https://github.com/rivo/tview)进行展示,主要原因这个库较为成熟(包括k9s在内的很多项目都是使用这个库进行开发的),star数较多,功能强大,而且依旧保持维护状态。

展示的结果应当是一个表格,每一个副本为一行,展示其当前状态等信息。

表格的示例如下:

image-20240602001117354

展示的指标暂时如下:

主要考虑事务状态和接口的可用性。

  1. 服务可用性

    • 显示Seata Server的运行状态,是否处于活跃状态。

    • 显示服务的响应时间,以评估服务性能。

    • 接口的可用性 (主要考虑)

  2. 资源使用情况

    • CPU使用率:监控Seata Server的CPU使用情况。

    • 内存使用率:监控Seata Server的内存使用情况。

    • 磁盘使用率:监控Seata Server的磁盘使用情况,特别是日志和数据存储。

  3. 事务状态:(主要考虑)

    • 事务总数:显示当前Seata Server处理的事务总数。

    • 活跃事务数:显示当前正在进行中的事务数量。

    • 完成事务数:显示已成功提交或回滚的事务数量。

    • 事务超时数:显示因超时而失败的事务数量。

  4. 网络状态

    • 网络延迟:监控Seata Server与其他服务之间的网络延迟。

    • 网络流量:监控进出Seata Server的网络流量。

  5. 错误和异常

    • 错误日志:显示错误和异常的日志信息,帮助定位问题。

    • 异常率:显示异常发生的比例。

  6. 配置信息

    • 显示Seata Server的配置参数,如事务超时时间、存储模式等。

  7. 集群健康状态

    • 显示集群中各个Seata Server实例的健康状态。

    • 显示集群的负载均衡情况。

  8. 版本信息

    • 显示Seata Server的版本信息,以便了解当前运行的是哪个版本的服务。

1.1.3 实现方案:

1.1.3.1 数据结构与持久化:

这个ctl并不需要在后台运行,所以需要持久化用户的配置,拟采用配置文件的形式进行存储。配置文件分为两种,一种是ctl的全局配置文件,存储连接信息,yml配置文件位置等全局的信息。另一种是yml配置文件,由用户导入或者由系统自动生成。方便用户管理。

1.1.3.2 代码实现:

使用当前seata-cli 的cobra包实现,新增cmd命令,读取命令进行判断并转换为yml的模块,进行文件处理的模块,发送请求的模块,进行tui展示的模块以实现功能。

1.2 读取 Prometheus 中 Seata 相关的指标进行展示:

1.2.1 设计目标:

Seata 已经集成了 Prometheus ,可以收集一些指标。如下:

image-20240602002307322

现在需要通过seata-ctl去展示这些指标,并做用户友好的输出。

1.2.2 命令设计:

1.2.2.1 展示数据:

1.2.2.1.1 命令:
seata-ctl metrics
1.2.2.1.2 参数:

因为seata的Metrics模块可以使用SPI拓展,所以为了后续的可拓展性,采取一个参数,表示Metrics获取的渠道。

region:表示获取的渠道,如果不填默认为Prometheus,具体的渠道信息在ctl的总配置文件中配置。

同时还有一个数据表证要读取的是哪一个seata集群的指标(可能有多个seata集群),采用部署的名字实现。

name:部署资源时的名字

1.2.2.1.3 展示方式:

同样采取tui表格的方式进行展示。表格的行为参数,右侧为值。

1.2.3 实现方式:

通过在配置文件中配置Prometheus地址,由seata-ctl读取Prometheus api并展示的方式实现。

需要在代码中编写读取模块,数据结构转换模块,展示模块。

1.3 seata日志诊断分析:

1.3.1 设计目标:

在seata的可观测实践(https://seata.apache.org/zh-cn/blog/seata-observable-practice/#logging%E7%BB%B4%E5%BA%A6)这篇文章中,将可观测性分为三个维度:

Metrics:主要关注机器的当前运行状态。

Tracing:主要关注事务链路的相关信息

Logging:日志包含seata操作的所有信息,可以实现链路追踪与统计分析的功能。

对于当前的seata集群来说,一个事务可能会经过多个实例最终完成,而每个实例的日志都是不同的,而每个实例的日志都会存在本地,不能做到有效的互通。自然无法进行有效的分析。

现在需要设计一整套seata集群的日志诊断分析工具,并使用seata-ctl实现查看日志分析结果的功能。

1.3.2 架构设计:

在分布式环境中实现日志收集与聚合的完整解决方案通常涉及以下几个组件:

  1. 日志收集器

    负责从各个服务实例中捕获日志。

  2. 日志存储系统

    用于存储收集到的日志数据。

  3. 日志索引与查询

    对日志数据建立索引,便于快速查询和分析。

  4. 日志可视化与分析

    创建仪表板和可视化查询结果。

当前官网上推荐的对seata进行日志分析的方式是采用ELK技术栈:

  1. Elasticsearch:承担日志存储与索引建立的功能。一个实时的分布式搜索和分析引擎,用于存储、搜索和分析大规模的结构化和非结构化数据。Elasticsearch 提供了强大的全文搜索、实时分析和聚合功能,使用户能够轻松地从海量数据中提取有价值的信息。

  2. Logstash:承担日志收集的功能。一个用于日志收集、处理和转发的数据处理管道。Logstash 可以从各种来源收集日志数据,如文件、消息队列、数据库等,然后对数据进行过滤、转换和丰富,最后将处理后的数据发送到 Elasticsearch 或其他存储和分析系统中。

  3. Kibana:承担日志分析的功能。一个用于数据可视化和分析的开源工具。Kibana 提供了丰富的图表、仪表盘和可视化组件,使用户可以轻松地探索和分析 Elasticsearch 中的数据,并创建交互式的可视化报告。

我们开发此工具需要考虑其应用场景,使其尽可能多的适配不同的场景,可能现在有的公司使用ELK,或者当前并没有针对seata的日志系统需要接入,seata-ctl都需要支持。

参考go-micro的代码插装思路设计,分别为这三个功能建立server,并通过接口的方式实现互相的交互。用户可以自由的选择是否需要该层的功能,并选择每一层采用什么方式实现,将这些配置在seata-ctl的主配置文件仓库中。

可以用下面这张示意图表示:

db763c79998039e14f5d74a34a6cf892

下面分别介绍这三个server。

1.3.2.1 日志收集系统:Log-collection-server:

这一部分的功能是收集 K8s 中每一个seata-server节点的pod日志,并发送到指定的位置。

主要实现是通过 client-go 访问k8s的api获取Pod 的日志。

1.3.2.2 日志分析系统:Log-analysis-server:

这一部分的功能是接收特定格式的日志,并进行特定方式的转换。并提供转换之后的api以供日志展示系统进行访问。

1.3.2.3 日志展示系统:Log-display-server:

获取日志分析系统的数据,按照用户输入进行展示。

1.3.2.4 用户使用:

第三个系统是与seata-cli强绑定绑定在一起的,与两个系统解耦。这样用户在使用的时候就会出现以下几种情况:

1.3.2.4.1 全部部署在本地:

如果用户的电脑性能非常好(比如新款的mac),而又没有其他的日志收集系统,那么可以选择三个server全部集成部署在本地。这样当用户输入命令时,三个系统的工作全部在本地进行。

当部署在本地时,三个server通过程序内部进行数据交互。

但是在这种方式下,收集系统和分析系统无法长时间运行,所以每次使用都需要等带较长的时间才能得到结果。

1.3.2.4.2 部分系统部署在用户自己的服务器:

为了性能和用户体验考虑,用户可以选择将分析系统或者收集系统部署在自己的服务器上。

当部署在服务器时,部署在服务器的系统和部署在本地的系统之间通过http/rpc通信进行交互。

如果使用这种方式部署自己的收集系统和展示系统,可以通过设置定时任务的方式,定时的去拉取seata集群的日志数据并作一定的聚合分析,这样当seata-ctl访问时可以直接获取到结果。

1.3.2.4.3 部分系统使用现有工具:

比如已经搭建好了elk全套技术,那么只需要对接es的相关接口并作展示。

又比如目前只有Logstash做日志收集,那么需要对接Logstash的相关接口。

这三个server的使用方式和一些其他的配置全部都在ctl的主配置文件中进行。

1.3.3 具体实现:

首先需要开发自己的三个server的具体实现,同时还需要开发对接Logstash,对接es的实现。

对于这种组件层层嵌套由可以自由插装的需求,可以使用装饰者模式结合go的特性实现。

装饰者模式(Decorator Pattern)是一种设计模式,它允许用户在不改变对象自身的基础上,向一个对象添加新的功能。这种模式通过创建一个包装对象,也就是装饰者,来包裹实际对象。装饰者实现了与实际对象相同的接口,并持有一个指向实际对象的引用,在调用实际对象的方法前后,可以执行额外的功能。

具体来说设计三个接口:

  1. Log-collection-server-interface:

    日志收集系统的抽象接口,提供收集日志数据的方法。

    这个接口有两个实现,一个是Log-collection-server的具体实现,一个是去访问Logstash并作格式转换的实现,

  2. Log-analysis-server-interface

    日志分析系统的抽象接口,提供展示日志结果的方法。

    这个接口有两个实现,一个是访问es api并作格式转换的实现,一个是持有一个Log-collection-server-interface对象,调用这个对象中的方法并作日志分析并存储的实现。

    后续可以考虑新增对接kafka等其他的消息队列系统。并使用这种日志方式为其他分布式中

    渐渐系统提供完整的日志解决方案。

    对接es的具体思路是首先定义seata日志资源的索引,然后通过es提供的

    GET /my_index/_search
    {
      "query": {
        "match": {
          "field_name": "search text"
        }
      }
    }

    api进行调用,从而获取日志相关信息。

    索引定义字段参考:

    1. 事务 ID(Transaction ID)

      • 事务 ID 是识别和管理分布式事务的关键字段,需要建立索引以快速查询和聚合相关事务日志。

    2. 时间戳(Timestamp)

      • 日志时间戳用于确定日志发生的顺序和时间范围查询,应该建立索引。

    3. 日志级别(Log Level)

      • 如 INFO, DEBUG, WARN, ERROR 等,可以帮助过滤和聚合不同级别的日志。

    4. 服务名称或实例 ID(Service Name/Instance ID)

      • 标识日志来源的服务或实例,有助于在多服务环境中定位问题。

    5. IP 地址(IP Address)

      • 如果日志中包含 IP 地址,可以用于分析特定 IP 的活动或安全事件。

    6. 操作类型(Operation Type)

      • 标识日志记录的操作类型,如“开始”、“提交”、“回滚”等。

    7. 资源 ID(Resource ID)

      • 如果日志涉及特定资源,如数据库连接或远程服务,资源 ID 有助于跟踪和管理。

    8. 异常或错误代码(Exception/Error Code)

      • 对于错误日志,异常或错误代码是快速定位问题的关键字段。

    9. 用户 ID(User ID)

      • 如果日志记录了用户操作,用户 ID 有助于分析用户行为或安全问题。

    10. 跟踪 ID(Trace ID)

      • 在分布式系统中,跟踪 ID 用于关联跨多个服务的日志记录。

    11. 租户 ID(Tenant ID)

      • 如果系统支持多租户,租户 ID 有助于隔离和分析特定租户的数据。

    12. 状态码(Status Code)

      • 对于记录操作结果的日志,状态码可以表示操作的成功或失败。

    13. 消息(Message)

      • 日志消息内容可能包含关键词或错误描述,建立索引可以支持全文搜索。

    14. 持续时间(Duration)

      • 对于记录操作耗时的日志,持续时间字段可以用于性能分析。

    15. 应用名称(Application Name)

      • 标识日志所属的应用,有助于在大型系统中区分不同的应用组件。

  3. Log-display-server-interface

    日志展示系统的抽象接口,提供展示分析结果的方法。

    这个接口有一个实现,这个实现包含一个Log-analysis-server-interface对象,使用时通过注入不同的Log-analysis-server-interface对象完成从es或者从Log-analysis-server获取展示数据的功能。

在初始化的时候根据配置文件的具体类容初始化相关的对象并进行对象的组装,最终得到一个Log-display-server-interface对象,并在seata-ctl中调用这个对象的相关方法。

全部的结构和流程可以使用下图表示:

3EFA249214108C6C98BE7F71E18C055C

1.3.4 命令设计:

1.3.4.1 展示聚合日志:

1.3.4.1.1 命令:
seata-ctl log 
1.3.4.1.2 参数:

name:部署资源时的名字

id:事务的id,如果不传就展示最新的几个日志(正确/错误根据status判断)

status:是否只显示错误的事务

1.3.4.2 部署:

1.3.4.2.1 命令:
seata-ctl logdeploy

该命令会根据文件夹下的全局配置文件初始化选择server的具体部署方式。

1.4 全局配置文件介绍:

该文件包含seata-ctl各种连接的配置,以及日志诊断分析节点的部署情况。

该文件主要包括三部分:

  1. k8s集群的连接信息

  2. Prometheus 的相关连接信息

  3. 日志诊断分析系统的配置信息

使用yml格式,仿照springboot的application.yml文件进行设计。简要的示意图如下:

Kubernetes:
    url:
    ....
Prometheus:
    url:
    ...
Log:
  collection:
      enable:
      url:
  analysis:
      enable:
      url:

2.开发计划:

首先说明一下情况,现在大三,暑期事情不多,大四学校并未安排课程,每天可以拿出三小时以上时间开发此项目。

按照ospp官网的设计,6.26号进行中选公示,如果能提交之后就确定中选的话,进行如下的时间安排:

  1. 6.4-6.26 根据设计完善细节,包括各种命令细节的完善,三个server具体交互的接口的格式设计等,并整理成完整的文档。

  2. 6.26-8.20 进行项目代码的开发,并继续交流可能遇到的问题,目前看来该题目的代码工程量应该会特别大(主要来源于三个server的开发),开发期间协商周期进行测试并提交pr。并在开发过程中编写单元测试方法。(该设计天然适配go-mock测试框架,有利于单元测试)。

  3. 8.20-9.10 进行整体全流程的测试,修改可能存在的问题,优化测试用例,尝试进行性能测试优化性能,并撰写完整的文档,

  4. 9.10-9.31 继续修复bug与完善文档,如果有可能的话尝试参与社区的其他工作。