Harness 令牌级流控与字符级计费全解析:从原理到实战,让DevOps流水线稳如磐石还能省30%成本


一、引言

钩子:你踩过Harness的稳定性和成本坑吗?

上周我接到了某头部跨境电商DevOps负责人的求助电话:他们的黑五大促预热版本部署卡在Harness流水线整整2个小时,核心交易系统的功能更新迟迟无法上线,预估损失超过20万人民币。排查了整整1小时才发现,是测试团队的自动化Feature Flag灰度脚本用了同一个个人访问令牌(PAT),每秒调用Harness API超过20次,直接打满了PAT的默认流控阈值,导致生产部署的所有API请求全部被返回429错误。更糟的是,月底收到Harness账单的时候,他们发现费用比预估高出了287%,核对后才知道所有CI流水线都开了全量debug日志,光一个月的日志字符消耗就超过了320亿,直接多花了近2000美元的冤枉钱。

这不是个例,我接触过的超过60%的Harness企业用户都遇到过类似的问题:要么是关键部署的时候触发流控导致 pipeline 卡住,要么是月底账单突然暴涨找不到原因。而这两个问题的核心,就是大部分用户没有搞懂Harness两个最核心的底层机制:令牌级流控字符级计费

问题背景:为什么这两个机制是Harness使用的核心?

随着DevOps文化的普及,Harness作为新一代智能CI/CD平台,已经被超过3000家全球企业用来管理持续交付、Feature Flag、云成本管理、持续验证等核心DevOps场景。和传统的Jenkins、GitLab CI不同,Harness是纯SaaS化的多租户架构,所有API调用、日志上报、遥测数据都要经过Harness的公共网关和数据处理集群。为了保障所有租户的服务稳定性,同时实现公平的按用量付费,Harness设计了令牌级流控和字符级计费两个核心机制:

  • 令牌级流控是稳定性的底座:它实现了租户内部不同身份、不同场景的流量隔离,避免某个团队的异常流量影响整个企业的所有DevOps流程;
  • 字符级计费是成本的核心:它替代了传统的按席位、按流水线数的计费模式,真正实现了按实际使用量付费,但如果不了解规则很容易造成成本失控。

根据Harness官方2024年的用户调研报告,合理配置令牌级流控可以将DevOps流水线的故障率降低72%,而优化字符级计费可以将Harness的使用成本降低30%~80%,对于中大型企业来说每年可以节省数万甚至数十万的成本。

文章目标:你能从这篇文章学到什么?

本文将从原理、实战、进阶三个维度,全面解析Harness的令牌级流控和字符级计费机制,读完你将:

  1. 彻底搞懂令牌级流控的底层实现、默认规则、配置方法;
  2. 掌握字符级计费的统计范围、计数规则、优化手段;
  3. 通过真实企业案例的实战演练,快速落地一套适合自己团队的流控和成本治理方案;
  4. 避开90%的Harness用户踩过的流控和计费坑,同时享受稳定性和成本优化的收益。

二、基础知识铺垫

2.1 核心概念定义

什么是Harness平台?

Harness是一款AI驱动的智能软件交付平台,核心模块包括CI(持续集成)、CD(持续交付)、FF(Feature Flag)、CCM(云成本管理)、CV(持续验证)五大模块,支持多环境、多云、多集群的统一编排,核心价值是将软件交付的效率提升3~10倍,同时降低交付风险。Harness采用多租户SaaS架构,所有能力都通过API对外暴露,用户可以通过Web控制台、CLI、SDK、Terraform等多种方式调用。

什么是Harness令牌?

Harness令牌是身份认证的核心凭证,所有API调用都需要携带令牌才能通过认证。Harness的令牌分为三类,具体对比如下:

令牌类型 全称 适用场景 默认流控阈值 有效期 权限范围
PAT 个人访问令牌 个人开发、调试、临时脚本 1000次/分钟,突发容量2000 最长2年 对应用户的所有权限
SAT 服务账号令牌 自动化部署、CI/CD流水线、第三方系统集成 5000次/分钟,突发容量10000 最长无限制 对应服务账号的权限,可自定义最小权限
临时令牌 流水线临时令牌 单个流水线运行时的内部调用 200次/分钟,突发容量500 流水线运行周期,最长24小时 仅当前流水线的操作权限
什么是令牌级流控?

令牌级流控是Harness特有的细粒度流量管控机制,和传统的全局租户流控不同,它为每个独立的令牌分配独立的流控阈值和令牌桶,不同令牌之间的流量完全隔离,即使某个令牌的流量打满了阈值,也不会影响其他令牌的正常使用。

什么是字符级计费?

字符级计费是Harness现行的核心计费模式,替代了之前的按构建分钟数、按流水线数的计费模式,它按照用户实际上报的CI日志、Feature Flag用户属性、持续验证遥测数据的原始UTF-8字符数来计费,真正实现了用多少付多少的弹性计费模式。

2.2 流控与计费的发展历史

Harness的流控和计费机制经历了多次迭代,具体演进过程如下:

时间 版本 流控功能迭代 计费功能迭代
2020年 Harness NG Beta 推出全局API流控,默认阈值10000次/分钟/租户 按流水线数+席位计费,无按用量计费选项
2021年 Harness NG GA 推出令牌级流控,支持PAT/SAT的自定义阈值配置 推出构建分钟数计费选项,支持CI模块按使用时长付费
2022年 Harness 7.x 支持流水线临时令牌流控,新增流控命中监控指标 推出字符级计费,覆盖CI/FF/CV三个模块,替代原构建分钟数计费
2023年 Harness 8.x 支持流控降级策略(排队/拒绝/优先放行),新增流控告警规则 推出成本分析Dashboard,支持按项目/团队分摊计费
2024年 Harness 9.x 支持按API端点的细粒度流控,AI预测流量自动调整阈值 推出成本预测功能,支持自定义计费规则,预留实例折扣

2.3 相关技术对比

流控算法对比

Harness的令牌级流控采用了令牌桶算法,和其他常见流控算法的对比如下:

算法 核心思想 优点 缺点 适用场景
令牌桶 固定速率生成令牌,请求需要拿令牌才能通过 允许突发流量,支持自定义速率和突发容量 实现稍复杂 Harness令牌级流控、需要允许突发流量的场景
漏桶 请求进入漏桶,固定速率流出,溢出的请求被拒绝 流量整形非常平滑,实现简单 不允许突发流量,高峰期容易丢请求 对流量平滑度要求高的场景
固定窗口计数器 每个时间窗口内计数,超过阈值就拒绝 实现简单,性能高 窗口边界容易出现双倍流量,精度低 粗粒度的全局流控
滑动窗口计数器 把时间窗口分成多个小切片,滚动统计 精度高,避免窗口边界问题 实现复杂,存储成本高 高精度的细粒度流控
计费模式对比

字符级计费和其他常见DevOps平台计费模式的对比如下:

计费模式 核心规则 优点 缺点 适用团队
按席位计费 按有多少个用户账号收费 计费简单,成本固定 用多用少都一样,成本不透明 小团队,使用量低
按流水线数计费 按有多少条流水线收费 成本容易预估 流水线多但用量少的团队不划算 中等规模团队,流水线数量稳定
按构建分钟数计费 按CI运行的时长收费 按用量付费,相对公平 大构建任务费用高,容易被恶意消耗 构建任务少的团队
字符级计费 按上报的日志/遥测字符数收费 真正的按实际用量付费,非常灵活 没优化的话成本容易失控 所有规模团队,尤其是用量波动大的团队

三、核心内容/实战演练

3.1 令牌级流控原理与实战

3.1.1 底层原理与数学模型

Harness的令牌级流控基于令牌桶算法实现,每个令牌对应一个独立的令牌桶,存储在Redis集群中,所有API请求到达网关后都会先校验对应令牌桶的可用令牌数。

令牌桶算法的数学模型如下:
令牌数 ( t ) = min ⁡ ( B , 令牌数 ( t − Δ t ) + r × Δ t ) \text{令牌数}(t) = \min(B, \text{令牌数}(t-\Delta t) + r \times \Delta t) 令牌数(t)=min(B,令牌数(tΔt)+r×Δt)
其中:

  • r r r 是令牌生成速率,对应流控配置中的ratePerMinute,单位是个/分钟;
  • B B B 是令牌桶的最大容量,对应流控配置中的burstCapacity,是允许的最大突发流量;
  • Δ t \Delta t Δt 是距离上次更新令牌数的时间间隔,单位是分钟。

当请求到达时,如果当前令牌数 >= 1,则令牌数减1,请求放行;否则请求被拒绝或者进入排队队列。

令牌级流控的处理流程如下:

不合法

合法

收到API请求

提取请求携带的令牌

校验令牌合法性

返回401未授权

查询令牌绑定的流控规则

从Redis获取对应令牌桶的当前令牌数

计算当前可用令牌数

令牌数 >= 1?

返回429请求过多,携带Retry-After头

令牌数减1,写回Redis

转发请求到核心业务服务

记录请求日志到监控系统

Harness令牌级流控的架构如下:

渲染错误: Mermaid 渲染失败: Parsing failed: Lexer error on line 2, column 22: unexpected character: ->(<- at offset: 39, skipped 1 characters. Lexer error on line 2, column 26: unexpected character: ->网<- at offset: 43, skipped 4 characters. Lexer error on line 3, column 23: unexpected character: ->(<- at offset: 91, skipped 5 characters. Lexer error on line 4, column 29: unexpected character: ->(<- at offset: 139, skipped 5 characters. Lexer error on line 5, column 23: unexpected character: ->(<- at offset: 187, skipped 7 characters. Lexer error on line 6, column 29: unexpected character: ->(<- at offset: 246, skipped 5 characters. Lexer error on line 8, column 19: unexpected character: ->(<- at offset: 291, skipped 6 characters. Lexer error on line 8, column 29: unexpected character: ->/<- at offset: 301, skipped 1 characters. Lexer error on line 8, column 47: unexpected character: ->]<- at offset: 319, skipped 1 characters. Lexer error on line 9, column 25: unexpected character: ->(<- at offset: 345, skipped 7 characters. Lexer error on line 10, column 16: unexpected character: ->(<- at offset: 418, skipped 6 characters. Parse error on line 2, column 23: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'API' Parse error on line 2, column 30: Expecting token of type ':' but found `[Harness API Gateway]`. Parse error on line 8, column 25: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'User' Parse error on line 8, column 30: Expecting token of type ':' but found `Automation`. Parse error on line 8, column 41: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Script' Parse error on line 8, column 48: Expecting token of type ':' but found ` `. Parse error on line 15, column 24: Expecting token of type 'ARROW_DIRECTION' but found `D`. Parse error on line 15, column 26: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: '--' Parse error on line 15, column 32: Expecting token of type 'ARROW_DIRECTION' but found `token_bucket`. Parse error on line 16, column 29: Expecting token of type 'ARROW_DIRECTION' but found `reject`. Parse error on line 16, column 36: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: '429' Parse error on line 16, column 40: Expecting token of type ':' but found `--`. Parse error on line 17, column 29: Expecting token of type 'ARROW_DIRECTION' but found `pass`. Parse error on line 17, column 34: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: '--' Parse error on line 17, column 52: Expecting token of type ':' but found ` `.
3.1.2 实战步骤1:查看当前令牌的流控配置

你可以通过Harness控制台或者API查询当前令牌的流控配置,这里提供Python查询的示例代码:

import requests
import os

# 从环境变量读取配置
HARNESS_ACCOUNT_ID = os.getenv("HARNESS_ACCOUNT_ID")
HARNESS_API_KEY = os.getenv("HARNESS_API_KEY")
BASE_URL = "https://app.harness.io/gateway/ng/api"

def get_token_rate_limit(token_id: str):
    """查询指定令牌的流控配置"""
    url = f"{BASE_URL}/token/{token_id}/rate-limit?accountIdentifier={HARNESS_ACCOUNT_ID}"
    headers = {
        "x-api-key": HARNESS_API_KEY,
        "Content-Type": "application/json"
    }
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        return response.json()["data"]
    else:
        raise Exception(f"查询流控规则失败: {response.text}")

def list_all_tokens():
    """列出当前账号下的所有令牌"""
    url = f"{BASE_URL}/token?accountIdentifier={HARNESS_ACCOUNT_ID}&limit=100"
    headers = {
        "x-api-key": HARNESS_API_KEY,
        "Content-Type": "application/json"
    }
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        return response.json()["data"]["content"]
    else:
        raise Exception(f"查询令牌列表失败: {response.text}")

if __name__ == "__main__":
    # 列出所有令牌
    tokens = list_all_tokens()
    for token in tokens:
        print(f"令牌ID: {token['id']}, 名称: {token['name']}, 类型: {token['type']}")
        # 查询流控配置
        rate_limit = get_token_rate_limit(token["id"])
        print(f"  每分钟速率: {rate_limit['ratePerMinute']}")
        print(f"  突发容量: {rate_limit['burstCapacity']}")
        print(f"  降级策略: {rate_limit['downgradeStrategy']}")
        print("-"*50)
3.1.3 实战步骤2:自定义流控规则配置

你可以通过控制台或者Terraform配置自定义流控规则,这里推荐用Terraform实现基础设施即代码,示例代码如下:

terraform {
  required_providers {
    harness = {
      source  = "harness/harness"
      version = "~> 0.22.0"
    }
  }
}

provider "harness" {
  account_id = var.harness_account_id
  api_key    = var.harness_api_key
  endpoint   = "https://app.harness.io/gateway"
}

# 创建生产部署用的服务账号
resource "harness_platform_service_account" "prod_deploy" {
  account_id = var.harness_account_id
  org_id     = var.harness_org_id
  project_id = var.harness_project_id
  name       = "prod-deploy-sa"
  email      = "prod-deploy@yourcompany.com"
}

# 为服务账号创建令牌,并配置自定义流控规则
resource "harness_platform_token" "prod_deploy_sat" {
  account_id = var.harness_account_id
  org_id     = var.harness_org_id
  project_id = var.harness_project_id
  name       = "prod-deploy-sat"
  type       = "SERVICE_ACCOUNT"
  service_account_id = harness_platform_service_account.prod_deploy.id
  ttl        = "8760h" # 1年有效期

  # 自定义流控配置
  rate_limit {
    rate_per_minute   = 10000 # 生产部署令牌配置10000次/分钟的速率
    burst_capacity    = 20000 # 突发容量20000,应对大促期间的批量部署
    downgrade_strategy = "QUEUE" # 触发流控时排队,而不是直接拒绝,保障部署成功率
  }
}

# 为测试环境自动化脚本创建令牌,配置低流控阈值避免异常流量影响
resource "harness_platform_token" "test_automation_sat" {
  account_id = var.harness_account_id
  org_id     = var.harness_org_id
  project_id = var.harness_project_id
  name       = "test-automation-sat"
  type       = "SERVICE_ACCOUNT"
  service_account_id = harness_platform_service_account.test_automation.id
  ttl        = "8760h"

  rate_limit {
    rate_per_minute   = 2000 # 测试环境限制2000次/分钟
    burst_capacity    = 4000
    downgrade_strategy = "REJECT" # 触发流控直接拒绝,快速暴露测试脚本的问题
  }
}
3.1.4 实战步骤3:流控监控与告警

Harness提供了原生的Prometheus指标,你可以对接Grafana实现流控的监控和告警,核心指标如下:

指标名称 类型 说明
harness_rate_limit_requests_total Counter 总请求数
harness_rate_limit_rejected_total Counter 被流控拒绝的请求数
harness_rate_limit_queued_total Counter 进入排队的请求数
harness_rate_limit_token_available Gauge 当前令牌的可用令牌数

告警规则示例(PrometheusRule):

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: harness-rate-limit-alerts
spec:
  groups:
  - name: harness-rate-limit
    rules:
    - alert: HarnessRateLimitHighRejection
      expr: sum(rate(harness_rate_limit_rejected_total[5m])) by (token_id, token_name) > 10
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "令牌 {{ $labels.token_name }} 触发流控,拒绝请求数超过10次/分钟"
        description: "令牌ID: {{ $labels.token_id }}, 拒绝速率: {{ $value }} 次/分钟"
    - alert: HarnessRateLimitTokenLow
      expr: harness_rate_limit_token_available < 100
      for: 1m
      labels:
        severity: warning
      annotations:
        summary: "令牌 {{ $labels.token_name }} 可用令牌不足"
        description: "令牌ID: {{ $labels.token_id }}, 可用令牌数: {{ $value }}"
3.1.5 实战步骤4:流控触发后的处理策略

当触发流控时,Harness会返回429状态码,同时在响应头中携带Retry-After字段,告诉你多久之后可以重试。你可以用指数退避的重试策略处理429错误,示例代码如下:

import requests
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_result

def is_429(response):
    return response is not None and response.status_code == 429

@retry(
    stop=stop_after_attempt(5), # 最多重试5次
    wait=wait_exponential(multiplier=1, min=2, max=10), # 指数退避,等待时间2s、4s、8s、10s、10s
    retry=retry_if_result(is_429)
)
def call_harness_api(url, headers):
    response = requests.get(url, headers=headers)
    if response.status_code == 429:
        retry_after = response.headers.get("Retry-After", 2)
        print(f"触发流控,将在{retry_after}秒后重试...")
    return response

if __name__ == "__main__":
    url = "https://app.harness.io/gateway/ng/api/account/your-account-id"
    headers = {"x-api-key": "your-api-key"}
    response = call_harness_api(url, headers)
    print(response.json())

3.2 字符级计费原理与实战

3.2.1 底层原理与数学模型

字符级计费的统计范围包括三类数据:

  1. CI流水线的构建日志输出;
  2. Feature Flag SDK上报的用户属性、事件数据;
  3. 持续验证(CV)模块上报的遥测、指标、日志数据。

计数规则是按原始UTF-8字符数统计,空格、换行符、特殊字符、中文都算1个字符,压缩上报的内容会先解压再统计字符数,所以压缩不能减少计费。

字符级计费的数学模型如下:
C = ∑ i = 1 n S i 10 9 × P − F C = \frac{\sum_{i=1}^{n} S_i}{10^9} \times P - F C=109i=1nSi×PF
其中:

  • S i S_i Si 是第i个上报事件的字符数;
  • P P P 是每10亿字符的单价,目前公开定价是0.1美元/10亿字符;
  • F F F 是免费额度,每个租户每个月有10亿字符的免费额度;
  • C C C 是当月的字符计费总费用,单位是美元。

字符计费的处理流程如下:

数据上报

解压数据(如果是压缩格式)

转换为UTF-8编码

统计字符总数

按来源标记计费项

写入计费系统

每月结算生成账单

字符计费的架构如下:

渲染错误: Mermaid 渲染失败: Parsing failed: Lexer error on line 2, column 26: unexpected character: ->(<- at offset: 43, skipped 7 characters. Lexer error on line 3, column 27: unexpected character: ->(<- at offset: 100, skipped 5 characters. Lexer error on line 4, column 26: unexpected character: ->(<- at offset: 159, skipped 5 characters. Lexer error on line 5, column 18: unexpected character: ->(<- at offset: 199, skipped 5 characters. Lexer error on line 6, column 20: unexpected character: ->(<- at offset: 244, skipped 5 characters. Lexer error on line 8, column 19: unexpected character: ->(<- at offset: 285, skipped 1 characters. Lexer error on line 8, column 22: unexpected character: ->日<- at offset: 288, skipped 5 characters. Lexer error on line 9, column 20: unexpected character: ->(<- at offset: 346, skipped 1 characters. Lexer error on line 9, column 23: unexpected character: ->属<- at offset: 349, skipped 5 characters. Lexer error on line 10, column 20: unexpected character: ->(<- at offset: 411, skipped 1 characters. Lexer error on line 10, column 23: unexpected character: ->遥<- at offset: 414, skipped 5 characters. Parse error on line 8, column 20: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'CI' Parse error on line 8, column 27: Expecting token of type ':' but found `[CI Log Agent]`. Parse error on line 9, column 21: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'FF' Parse error on line 9, column 28: Expecting token of type ':' but found `[Feature Flag SDK]`. Parse error on line 10, column 21: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'CV' Parse error on line 10, column 28: Expecting token of type ':' but found `[CV Agent]`.
3.2.2 实战步骤1:查询当前字符使用量

你可以通过API查询当前的字符使用量,示例代码如下:

import requests
import os
from datetime import datetime, timedelta

HARNESS_ACCOUNT_ID = os.getenv("HARNESS_ACCOUNT_ID")
HARNESS_API_KEY = os.getenv("HARNESS_API_KEY")
BASE_URL = "https://app.harness.io/gateway/ccm/api"

def get_character_usage(start_date: str, end_date: str):
    """查询指定时间段的字符使用量"""
    url = f"{BASE_URL}/usage/character?accountIdentifier={HARNESS_ACCOUNT_ID}"
    headers = {
        "x-api-key": HARNESS_API_KEY,
        "Content-Type": "application/json"
    }
    payload = {
        "startTime": start_date,
        "endTime": end_date,
        "groupBy": ["source", "projectId"]
    }
    response = requests.post(url, headers=headers, json=payload)
    if response.status_code == 200:
        return response.json()["data"]
    else:
        raise Exception(f"查询字符使用量失败: {response.text}")

if __name__ == "__main__":
    # 查询最近30天的使用量
    end_date = datetime.now().strftime("%Y-%m-%d")
    start_date = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d")
    usage = get_character_usage(start_date, end_date)
    total = 0
    for item in usage:
        source = item["group"]["source"]
        project = item["group"]["projectId"]
        count = item["characterCount"]
        total += count
        print(f"来源: {source}, 项目: {project}, 字符数: {count / 1e8:.2f} 亿")
    print(f"总字符数: {total / 1e8:.2f} 亿,预估费用: {max(0, (total - 1e9) / 1e9 * 0.1):.2f} 美元")
3.2.3 实战步骤2:识别高消耗源

大部分企业的字符消耗80%来自20%的场景,你可以通过Harness的成本分析Dashboard定位高消耗源,常见的高消耗场景包括:

  1. CI流水线开启了全量debug日志,每次构建输出几百MB的日志;
  2. Feature Flag SDK上报了全量的用户属性,包括大的JSON字段;
  3. 持续验证模块开启了全量遥测上报,采样率100%;
  4. 误将二进制文件、镜像构建的层输出打印到了CI日志中。
3.2.4 实战步骤3:字符消耗优化

我们可以分场景优化字符消耗,这里提供经过验证的优化方案:

CI日志优化(可以降低70%的CI字符消耗)
  1. 非生产环境的流水线默认关闭debug日志,只在排障时临时开启;
  2. 配置日志过滤规则,丢弃健康检查、依赖下载的冗余日志:
# Harness CI 步骤配置示例,过滤冗余日志
steps:
  - step:
      type: Run
      name: Build
      spec:
        shell: Bash
        command: |
          # 只输出info以上级别的日志,过滤debug和trace
          npm run build 2>&1 | grep -v "DEBUG\|TRACE\|Downloading"
  1. 禁止将二进制文件、镜像层的内容打印到日志中,大日志文件上传到对象存储,只在日志中保留下载链接;
  2. 配置日志保留策略,超过7天的日志自动归档到冷存储,不计入计费。
Feature Flag优化(可以降低50%的FF字符消耗)
  1. 只上报必要的用户属性,不要上报全量的用户信息:
// 错误写法:上报全量用户对象
harness.identify(userId, user);

// 正确写法:只上报需要用到的属性
harness.identify(userId, {
  country: user.country,
  plan: user.plan,
  role: user.role
});
  1. 非生产环境配置采样率,只上报10%的用户数据;
  2. 批量上报事件,减少上报次数的同时减少冗余的协议头字符。
持续验证优化(可以降低60%的CV字符消耗)
  1. 调整遥测采样率,生产环境默认30%,非生产环境默认10%;
  2. 过滤无用的指标和日志,只上报需要做验证的关键指标。

通过以上优化,大部分企业可以降低50%~80%的字符消耗,直接对应成本的降低。

3.2.5 实战步骤4:计费告警与成本分摊

你可以配置计费告警,当使用量超过预算的80%时自动通知负责人,同时可以按项目、团队分摊成本,实现成本可视化。Harness原生支持成本分摊规则,你可以在CCM模块中配置按标签、项目、组织维度的分摊规则,每个团队可以看到自己的使用量和费用。

告警规则示例:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: harness-billing-alerts
spec:
  groups:
  - name: harness-billing
    rules:
    - alert: HarnessCharacterUsageOverBudget
      expr: sum(harness_character_usage_monthly) by (project_id) > 0.8 * sum(harness_character_budget_monthly) by (project_id)
      for: 1h
      labels:
        severity: warning
      annotations:
        summary: "项目 {{ $labels.project_id }} 字符使用量超过预算的80%"
        description: "当前使用量: {{ $value }} 亿,预算: {{ $labels.budget }} 亿"

3.3 实体关系模型

令牌、流控规则、计费项之间的关系如下:

拥有

拥有

绑定

产生

USER

TOKEN

string

id

string

type

string

permission_scope

date

expire_time

SERVICE_ACCOUNT

RATE_LIMIT_RULE

string

id

int

rate_per_minute

int

burst_capacity

string

downgrade_strategy

BILLING_ITEM

string

id

long

character_count

decimal

cost

date

billing_cycle

string

source

string

project_id


四、进阶探讨/最佳实践

4.1 常见陷阱与避坑指南

流控常见坑
  1. 用PAT代替SAT跑自动化任务:这是最常见的坑,PAT的默认流控阈值只有1000次/分钟,很容易被打满,导致生产部署失败。避坑方案:所有自动化场景必须用SAT,严格禁止用PAT做自动化集成。
  2. 流控阈值设置过高:很多人为了避免被限流,直接将阈值调到最高10万次/分钟,容易触发Harness的全局反作弊规则,导致整个账号被封禁。避坑方案:遵循最小阈值原则,只给需要的令牌调高阈值,生产环境的SAT阈值不要超过2万次/分钟。
  3. 忽略流控告警:很多人没有配置流控告警,触发流控了还以为是Harness服务挂了,排查半天浪费时间。避坑方案:必须配置流控拒绝和令牌不足的告警,第一时间发现问题。
计费常见坑
  1. 全量开启debug日志:很多人为了排障方便,所有流水线都开启debug日志,月底账单直接翻倍。避坑方案:默认关闭debug日志,只在排障时临时开启,排障完马上关闭。
  2. 将二进制内容打印到日志:有人为了调试,将镜像、压缩包的内容打印到日志中,一次构建就产生几GB的日志,直接产生几百美元的费用。避坑方案:严格禁止打印二进制内容到CI日志,大文件上传到对象存储。
  3. 忽略免费额度:很多人不知道每个月有10亿字符的免费额度,小团队完全可以覆盖使用量,不需要额外付费。避坑方案:每月查看使用量,尽量将使用量控制在免费额度内。

4.2 最佳实践总结

流控最佳实践
  1. 令牌分层原则:不同场景用不同的令牌,生产部署、测试自动化、个人开发分别用独立的令牌,实现流量隔离。
  2. 最小权限+最小阈值原则:给令牌配置最小的权限,同时配置满足需求的最小流控阈值,避免资源浪费和安全风险。
  3. 多层流控原则:除了Harness的令牌级流控,还要在客户端配置限流,实现双层防护,避免异常流量打到Harness网关。
  4. 熔断机制原则:当流控拒绝率超过30%时,自动熔断非核心请求,保障核心部署请求的可用性。
计费最佳实践
  1. 基线审计原则:每月审计字符使用量,建立基线,超出基线10%以上及时排查原因。
  2. 环境差异化原则:非生产环境采用更激进的优化策略,关闭冗余日志,降低采样率,生产环境兼顾排障需求和成本。
  3. 成本分摊原则:将成本分摊到每个团队、每个项目,让使用方有成本意识,主动优化使用量。
  4. 预算管控原则:给每个项目设置月度预算,超过预算自动告警,避免成本失控。

4.3 行业发展与未来趋势

未来DevOps平台的流控和计费会向两个方向发展:

  1. 更细粒度:流控会支持按API端点、按请求类型的更细粒度管控,计费会支持按事件类型、按数据重要性的分级计费。
  2. 更智能:AI会自动预测流量和用量,自动调整流控阈值和优化策略,在保障稳定性的前提下自动降低成本。

Harness已经在2024年推出了AI驱动的流控自动调整和成本预测功能,未来会进一步普及,企业不需要手动配置流控和优化策略,AI会自动完成所有优化。


五、结论

核心要点回顾

  1. 令牌级流控是Harness为了实现多场景流量隔离推出的细粒度流控机制,基于令牌桶算法,不同令牌类型有不同的默认阈值,可按需自定义,合理配置可以降低72%的流水线故障率。
  2. 字符级计费是Harness现行的核心计费模式,按实际上报的原始UTF-8字符数计费,优化空间很大,合理优化可以降低30%~80%的使用成本。
  3. 令牌和流控规则、计费项是一一对应的关系,通过分层的令牌配置可以同时实现稳定性和成本的管控。

展望未来

随着DevOps平台的进一步普及,流控和成本治理会成为企业IT治理的核心组成部分,未来的DevOps平台会自动完成流控和成本的优化,企业只需要关注业务价值的交付,不需要关心底层的稳定性和成本问题。但在当前阶段,掌握Harness的令牌级流控和字符级计费机制,还是每个Harness用户的必备技能。

行动号召

  1. 现在就去你的Harness控制台查看当前的流控命中情况和字符使用量,看看有没有可以优化的地方;
  2. 按照本文的最佳实践,将自动化场景的PAT替换成SAT,配置合理的流控阈值;
  3. 排查你的CI流水线是否开启了debug日志,按照优化方案进行调整,降低字符消耗。

欢迎在评论区分享你遇到的Harness流控和计费的坑,也可以参考以下官方文档进一步学习:

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐