开源功能开关(feature flags) 和管理平台之unleash

背景

功能管理是持续发布/持续部署 ( CI/CD ) 流程的重要组成部分,它允许开发人员与一小部分用户逐步测试新功能、打开或关闭功能以及进行 A/B 测试,以深入了解什么是最有效的,而无需发布一个全新的版本。

对项目内的功能启用进行动态控制, Feature Toggle,

Feature Toggle,顾名思义就是表示 Feature 的开关,通常可以使用 Feature Toggle 来管理不同功能开关,并且可以根据不同的参数对开关进行动态配置。在项目中引入 Feature Toggle 可以更好的对于功能进行灰度发布和定向测试。

Netflix的开源项目Unleash正是这样一款工具,它提供了一种动态管理应用程序功能开关的方式,帮助企业更有效地进行灰度发布、A/B测试和其他迭代策略。

开源方案 Unleash。Unleash 是一个开源的 Feature Toggle 服务。

Flagsmith 和 Unleash

Flagsmith 视频介绍:https://www.reddit.com/r/selfhosted/comments/o5hyug/self_hosted_feature_flag_and_remote_config/?tl=zh-hans

场景FlagsmithUnleash
快速集成适合需要 SaaS 或快速启动的项目适合愿意自托管且需要灵活策略的团队
复杂策略支持 A/B 测试和用户细分支持更复杂的自定义策略(如渐进式发布)
边缘计算本地评估减少延迟依赖中心化服务器
动态配置支持远程配置参数仅支持功能开关
特性FlagsmithUnleash
开源版本完全开源(MIT 许可证)完全开源(Apache 2.0)
企业版提供付费 SaaS 和企业支持无官方 SaaS,但有商业支持选项
社区支持活跃的社区和文档社区活跃,文档详细
  • 选择 Flagsmith 如果
    • 需要 SaaS 解决方案或快速启动。
    • 需要内置 A/B 测试或动态配置。
    • 优先考虑本地评估(如移动端或边缘场景)。
  • 选择 Unleash 如果
    • 需要完全自托管和灵活的自定义策略。
    • 专注于功能开关和渐进式发布。
    • 愿意维护自己的基础设施。

什么是unleash

官方文档:https://docs.getunleash.io/
官方仓库:https://github.com/Unleash

Unleash 是一个开源的功能标志(feature flags) 和管理平台,允许您在不中断服务的情况下安全地发布和测试新功能。它提供了一个集中式界面,用于管理和控制哪些用户可以看到哪些功能,以及如何启用这些功能。

Unleash 提供了一个简单的管理平台,我们可以在这个管理后台上进行 Feature Toggle 的管理和查看。

通过使用Unleash,您的团队可以在不依赖分支的情况下并行开发多个特性,实现敏捷开发的最佳实践。这个平台支持15个官方SDK和多个社区贡献的SDK,可与任何语言和框架无缝集成。

总而言之,Unleash 帮助团队安全地发布和管理新功能,提升了开发效率,并降低了发布风险。

Unleash广泛应用于以下场景:

  • 快速迭代:启用或禁用代码以控制新特性的发布速度。
  • 灰度发布:逐步向一小部分用户推出新特性,收集反馈并调整。
  • A/B测试:对不同用户群体实施不同的功能版本,比较效果。
  • 风险控制:若发现新特性有问题,可以通过切换关闭旗标来迅速回滚。

架构

在这里插入图片描述

Unleash Edge

官方文档:https://docs.getunleash.io/reference/unleash-edge
https://github.com/Unleash/unleash-edge/blob/main/docs/concepts.md

Unleash Proxy is in maintenance mode. Use Unleash Edge instead.Unleash Proxy 处于维护模式。请改用 Unleash Edge

Unleash Edge 是 Unleash Proxy 的继任者。如需有关从 Proxy 迁移到 Edge 的帮助,请参阅迁移指南

Unleash Edge 是 Unleash API 和 SDK 之间快速轻量级的代理层。它充当 Unleash 实例的只读副本,旨在帮助您扩展 Unleash。它允许您支持数千个连接的 SDK,而无需增加对 Unleash 实例发出的请求数量。

  • 使用独立于 Unleash 服务器的 Unleash Edge 进行扩展,以支持任意数量的前端客户端,而不会使您的 Unleash 实例过载.
  • 前端 SDK 通过 Unleash Edge 连接,以确保隐私、可扩展性和安全性。

Edge 目前支持 2 种不同的模式:

  • Edge - 连接到上游节点(Unleash 实例或另一个 Edge)。 支持动态令牌、指标和 其他高级功能;
  • 离线 - 没有连接到上游节点。完全控制数据和令牌;

Unleash客户端SDK,可以与Unleash前端APIUnleash代理Unleash Edge一起使用。这使得任何Flutter应用程序使用Unleash变得非常简单。

Fetch toggles
Fetch toggles
Client
Edge
Unleash

主要特性:

  • 性能: Edge 使用内存缓存,可以在靠近最终用户的位置运行。单个实例每秒可以处理成千上万个请求。
  • 弹性:Edge 旨在在重启后继续运行,即使您与 Unleash 服务器断开连接也能保持功能。
  • 安全性: Edge 支持前端应用程序,而不会将敏感数据暴露给最终用户或 Unleash。

您可以在两种不同的模式下运行 Edge:edgeoffline。要了解有关不同模式和其他 Edge 概念的信息,请访问 Concepts

安装和使用

参照官方文档 进行安装。

要在本地设置 Unleash,您需要在您的机器上安装 git 和 docker。
执行以下命令:

git clone git@github.com:Unleash/unleash.git

cd unleash
docker compose -f docker-compose-enterprise.yml up -d

这会拉取 unleashorg/unleash-enterprise Docker 镜像,并使用 Docker Compose 文件来配置 Unleash 服务器及其数据库。

然后将您的浏览器指向 localhost:4242 并使用以下信息登录:

username: admin
password: unleash4all

Unleash SDKs

官方github:https://github.com/Unleash/unleash?tab=readme-ov-file#unleash-sdks

To connect your application to Unleash you’ll need to use a client SDK for your programming language.要将您的应用程序连接到 Unleash,您需要使用适用于您的编程语言的客户端 SDK。

官方服务端 SDK:

官方前端 SDK:

The front-end SDKs connect via Unleash Edge in order to ensure privacy, scalability and security.前端 SDK 通过 Unleash Edge 连接,以确保隐私、可扩展性和安全性。

开放API Tokens访问

官方文档:https://docs.getunleash.io/reference/api-tokens-and-client-keys

  • 后端服务(如 Go) → 选择 Server-side SDK (CLIENT) Token。
  • 前端/移动端 → 选择 Client-side SDK (FRONTEND) Token。

Server-side SDK (CLIENT) Token 默认具有 读取权限,可以查询所有 Toggles 的配置。

Client-side SDK (FRONTEND) Token 可能无法访问某些敏感接口(如 /admin/evaluate)。

default:production.5050d6c03962ca79170b3360fc8bf0bb3ccc36e1e50ffe5dc88c7257

Unleash 中创建 Token 时,选择 Token 类型 取决于你的使用场景。根据你的描述,你正在调试一个 Go 语言后端服务(通过 curl 调用 Unleash API),因此应该选择:

  • curl 调用的是 Unleash 的 Server API(如 /api/client/features),属于后端调试行为。
  • 需要读取 Feature Toggles 的完整配置(包括 enabled 状态、variantspayload 等)。

Server-side SDK (CLIENT)

  • 用于 后端服务(如 Go、Node.js、Java 等)连接 Unleash。
  • 你的代码中通过 unleash.GetVariant 调用 Unleash,属于 Server-side SDK 的使用方式。

查询所有 Feature Toggles

curl -X GET \
  -H "Authorization: YOUR_SERVER_SIDE_TOKEN" \
  "http://unleash.example.com/api/client/features"

查询特定 Toggle

curl -X GET \
  -H "Authorization: Bearer YOUR_SERVER_SIDE_TOKEN" \
  "http://unleash.example.com/api/client/features/FEATURE_NAME"

API token types

官方文档:https://docs.getunleash.io/reference/api-tokens-and-client-keys

Client tokens

客户端 token 的作用域限定为一个或多个项目和一个环境。创建客户端 token 时,您可以授予其对特定项目列表或所有当前或未来项目的访问权限。客户端 token 是机密信息,不得向最终用户公开。

Client tokens cannot be used in frontend SDKs; use frontend tokens instead.

客户端 token 不能在前端 SDK 中使用;请改用 前端 token

Frontend tokens

使用前端 token 将 前端 SDK 通过 Unleash Frontend APIUnleash Edge 连接到 Unleash。它们授予用户以下权限:

  • Reading enabled flags for a given context针对给定上下文的读取启用标志
  • Registering applications with the Unleash server向 Unleash 服务器注册应用程序
  • Sending usage metrics

前端令牌的作用域限定为一个或多个项目以及单个环境。创建前端令牌时,您可以授予其对特定项目列表的访问权限,或授予其对所有当前或未来项目的访问权限。前端令牌不被认为是秘密的,可以安全地暴露在客户端。

前端令牌不能在服务器端 SDK 中使用;请改用 客户端令牌

Personal access tokens

个人访问令牌反映了创建它们的用户所拥有的权限。如果用户的权限发生更改(例如通过添加自定义角色),令牌会自动更新以匹配新的权限。 您可以使用个人访问令牌进行测试、调试或为自动化工具提供临时访问权限。

当您使用个人访问令牌修改资源时,事件会记录该操作的令牌创建者的姓名。

具有生命周期的个人访问令牌会在过期后失效并停止工作。虽然您可以将令牌设置为永不过期,但我们建议使用具有过期日期的令牌,以遵循安全最佳实践。

个人访问令牌不适用于客户端 SDK,因为它们未绑定到环境,可能会过期或其权限可能会更改。请改用 客户端令牌

Service account tokens

服务帐户令牌为集成和自动化工具提供 API 访问权限。 要了解更多信息,请访问服务帐户

使用 Edge 将客户端 SDK 连接到 Unleash

To connect a client-side SDK to Unleash using Unleash Edge, you need both a client and frontend token:要想使用 Unleash Edge 将客户端 SDK 连接到 Unleash,你需要一个 客户端 token 和一个 前端 token

  • 客户端 SDK 需要一个前端 token 才能与 Edge 通信。
  • Edge 需要一个客户端 token 才能与 Unleash 服务器通信。

Diagram showing the types of tokens needed to connect a client-side SDK with Edge, and Edge with Unleash

go sdk demo

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/Unleash/unleash-client-go/v3"
	"github.com/Unleash/unleash-client-go/v3/context"
)

func main() {
	// 初始化 Unleash 客户端
	err := unleash.Initialize(
		unleash.WithAppName("my-app"),
		unleash.WithUrl("http://127.0.0.1:4242/api"),
		unleash.WithCustomHeaders(http.Header{
			"Authorization": []string{"x:x.xxx"},
		}),
		unleash.WithRefreshInterval(5*time.Second),
		unleash.WithMetricsInterval(5*time.Second),
		unleash.WithListener(&unleash.DebugListener{}),
	)

	if err != nil {
		log.Fatalf("初始化失败: %v", err)
	}

	// 设置超时等待
	ready := make(chan struct{})
	go func() {
		unleash.WaitForReady()
		close(ready)
	}()

	// 等待就绪或超时
	select {
	case <-ready:
		fmt.Println("Unleash client is ready")
	case <-time.After(10 * time.Second):
		log.Fatal("Timeout waiting for Unleash client to be ready")
	}

	// 测试用例: 基于参考代码的请求上下文
	testContext("测试请求", context.Context{
		UserId: "123",
		Properties: map[string]string{
			"UserId":        "123"

		},
	})

	// 保持程序运行一段时间以观察结果
	time.Sleep(15 * time.Second)
}

func testContext(name string, ctx context.Context) {
	isEnabled := unleash.IsEnabled("someToggle", unleash.WithContext(ctx))

	fmt.Printf("\n=== %s ===\n", name)
	fmt.Printf("Feature Enabled: %v\n", isEnabled)
	fmt.Printf("Context:\n")
	fmt.Printf("  UserId: %s\n", ctx.UserId)
	fmt.Printf("  Properties:\n")
	for k, v := range ctx.Properties {
		fmt.Printf("    %s: %s\n", k, v)
	}

	// 获取变体信息
	variant := unleash.GetVariant("someToggle", unleash.WithVariantContext(ctx))
	if variant != nil {
		fmt.Printf("\nVariant Information:\n")
		fmt.Printf("  Name: %s\n", variant.Name)
		fmt.Printf("  Enabled: %v\n", variant.Enabled)
		if variant.Enabled {
			fmt.Printf("  Payload Type: %s\n", variant.Payload.Type)
			fmt.Printf("  Payload Value: %s\n", variant.Payload.Value)
		}
	} else {
		fmt.Println("\nNo variant returned")
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值