オープンソース ツールを使用して機能フラグを備えたスケーラブルな API を構築する
機能のフラグ設定により、バックエンド開発者が構築したものをテストおよび変更する方法のパラダイムが変わりました。機能フラグを使用すると、機能を有効または無効にしたり、ワンクリックでその場で機能を変更したりできます (再デプロイする必要はありません)。
このチュートリアルでは、コード全体を再デプロイすることなく、UI からいつでも機能やコードの一部を有効または無効にするために機能フラグがどのように役立つかを見ていきます。
物事をより深く理解するために、アプリを最初から構築し、機能フラグ機能を確認し、Flagsmith と呼ばれるツールを使用して、作成した機能フラグを 1 つのダッシュボードから管理します。
ここで説明する内容は次のとおりです。
-
前提条件
-
機能フラグとは何ですか?
-
バックエンド開発の機能フラグ
-
オープンソース ツールを使用する理由?
-
コードを書いてみましょう!
-
ツールを初期化しています
-
API のエンドポイントを作成する
-
機能フラグを追加する方法
-
機能フラグのコード ロジックを理解する
-
Flagsmith ダッシュボードで機能フラグを作成する方法
-
レート制限機能フラグ
-
ベータ機能フラグ
-
アクセスキーの取得
-
API の実行
-
rate_limit フラグを更新しています
-
機能フラグを GitHub アプリと統合する方法
-
Flagsmith GitHub アプリのテスト
-
-
結論
前提条件
-
Golang がインストールされており、Golang について中程度の理解がある。
-
実行中の Redis インスタンス (リモートまたはローカル インスタンス)
-
Flagsmith アカウント (無料です。これについては記事の後半で説明します。)
機能フラグとは何ですか?
機能フラグは、チームがソース コードを変更したり再デプロイしたりせずに機能をオンまたはオフにできる開発技術です。
もう少し簡単にするために、これらは条件ステートメント (if-else ステートメントなど) のようなものとして機能すると考えてください。何かが true か false であるかに基づいて、実行されるコード パスが決定されます。
バックエンド開発用の機能フラグ
フロントエンドや Web サイトで機能フラグが使用されているのを見たことがあるかもしれませんが、それだけではありません。これらをサーバー側で使用して、レート制限の変更/設定、API エンドポイントの機能の変更、または完全にオフにするなど、API の機能を変更できます。バックエンド開発者は、機能フラグを使用してテストをレベルアップできます。
これを実証するために、デモ アプリを構築してみましょう。デモ アプリは、オンザフライでの機能 (レート制限) の変更から、ベータ テストや初期ローリング目的での API への新しいエンドポイントの追加まで、機能フラグ機能を示すために厳選されています。途中で完全にオープンソースのツールを使用する予定です!
このアプリの構築にはオープン ソース ツール (Golang、Redis、Flagsmith) を使用します。オープンソースは透明性と信頼性を高め、バックエンド開発者のグローバル コミュニティとのコラボレーションを促進します。
オープンソース ツールを統合することで、構築とテストの際に完全な可視性が得られます。たとえば、機能フラグを GitHub と統合します。これにより、Flagsmith 機能フラグを GitHub のプル リクエストまたは問題にリンクすることで、機能のライフサイクルを追跡できるようになります。これにより、各変更を手動で追跡することなく、機能の変更を常に最新の状態に保つことができます。さまざまな環境にわたる機能のステータスを簡単に追跡できます。
コードを書いてみましょう!
このチュートリアルでは、機能フラグ機構を使用したテストの前後でアプリの機能がどのように変化するかを確認します。使用するツールとフレームワークは、Golang、Docker、Redis、Flagsmith、GitHub です。前述したように、すべてオープンソースであり、テスト用のアカウントを無料で作成できます。
まず、お気に入りの IDE を開いて Golang プロジェクトを初期化し、以下のコードを main.go にコピーします。 ファイル。次に、go mod tidy を実行します。 必要な依存関係をすべてインストールします。
以下のコード スニペットで何が起こっているのかを理解してみましょう。
package main
import (
"context"
"errors"
"fmt"
"log"
"net/http"
"os"
"strconv"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis_rate/v10"
"github.com/joho/godotenv"
"github.com/redis/go-redis/v9"
)
var (
redisClient *redis.Client
limiter *redis_rate.Limiter
)
func initClients() {
redisClient = redis.NewClient(&redis.Options{
Addr: os.Getenv("REDIS_URL"),
})
limiter = redis_rate.NewLimiter(redisClient)
}
func main() {
err := godotenv.Load()
if err != nil {
log.Printf("Loading environment variable from the host system")
} else {
log.Printf("Loading environment from .env file")
}
initClients()
defer redisClient.Close()
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
err, remainingLimit := rateLimitCall(c.ClientIP())
if err != nil {
c.JSON(
http.StatusTooManyRequests,
gin.H{"error": "Rate Limit Hit"})
} else {
c.JSON(
http.StatusOK,
gin.H{"Your left over API request is": remainingLimit})
}
})
r.GET("/beta", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{"message": "This is beta endpoint"})
})
r.Run(":" + os.Getenv("PORT"))
}
func rateLimitCall(ClientIP string) (error, int) {
ctx := context.Background()
rateLimitString := os.Getenv("RATE_LIMIT")
RATE_LIMIT, _ := strconv.Atoi(rateLimitString)
res, err := limiter.Allow(ctx, ClientIP, redis_rate.PerHour(RATE_LIMIT))
if err != nil {
panic(err)
}
if res.Remaining == 0 {
return errors.New("You have hit the Rate Limit for the API. Try again later"), 0
}
fmt.Println("remaining request for", ClientIP, "is", res.Remaining)
return nil, res.Remaining
}
ツールの初期化
func initClients() {
redisClient = redis.NewClient(&redis.Options{
Addr: os.Getenv("REDIS_URL"),
})
limiter = redis_rate.NewLimiter(redisClient)
}
func main() {
err := godotenv.Load()
if err != nil {
log.Printf("Loading environment variable from the host system")
} else {
log.Printf("Loading environment from .env file")
}
initClients()
defer redisClient.Close()
r := gin.Default()
...
})
一番上で、Redis とレート リミッター クライアントを格納する変数を宣言し、再利用して一度初期化します。次に、initClients() でそれらを初期化します。 .
main() で , まず、システムまたは .env ファイルから環境変数を読み込みます。次に、initClients() を呼び出します。 。これによりクライアントが作成され、作成した変数にクライアントが保存されます。
次にジンを作ります。 すべての受信リクエストを処理するルーター。これらは、.env で必要な環境変数です。 ファイル。このデモでは、レート制限機能のすべてのデータを保存するために Redis インスタンスを実行する必要があります。 Docker または任意のリモート マシンを使用できます。REDIS_URL を忘れずに更新してください。 それに応じて。 Docker を使用するつもりです。
さらに進んで、機能フラグからすべての環境変数を取得することもできますが、ここではそれを行いません。
REDIS_URL=localhost:6379
PORT=8080
RATE_LIMIT=10
API のエンドポイントの作成
r.GET("/ping", func(c *gin.Context) {
err, remainingLimit := rateLimitCall(c.ClientIP())
if err != nil {
c.JSON(
http.StatusTooManyRequests,
gin.H{"error": "Rate Limit Hit"})
} else {
c.JSON(
http.StatusOK,
gin.H{"Your left over API request is": remainingLimit})
}
})
r.GET("/beta", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{"message": "This is beta endpoint"})
})
r.Run(":" + os.Getenv("PORT"))
次に、2 つのGET を作成します。 エンドポイント、/ping と /beta 。誰かが /ping を押すたびに rateLimitCall() と呼ばれるエンドポイント 機能。 IP アドレスからの受信リクエストのレート制限をチェックして設定します。 。これらすべては、作成した Redis インスタンスに保存されます。
したがって、ユーザーが /ping を操作したとします。 初めて API エンドポイントを作成すると、1 時間あたり 10 件の制限でエントリが作成されます。 。制限数 10 RATE_LIMIT から来ています 私たちが設定し、時間ごとの更新フォームは redis_rate.PerHour(RATE_LIMIT) から取得されます。 機能。
次に、ユーザーに残りの制限があるかどうかを確認します。 「はい」の場合、残っているリクエストの数を示すメッセージが返されます。それ以外の場合、制限の上限に達した場合は、そのことを知らせるメッセージが返されます。
/ping を除く エンドポイント、別のエンドポイント /beta があります 。単純なメッセージが返されますが、後で (機能フラグを使用して) このエンドポイントの機能を完全にオンまたはオフにする方法を見ていきます。
機能フラグを追加する方法
次に、機能フラグ機能をアプリに追加します。フラッグスミスを使用することにします。 Flagsmith は、ウェブ、モバイル、サーバーサイド アプリケーション全体で機能フラグを簡単に作成および管理できるオープンソース ソフトウェアです。
Flagsmith を使用すると、機能をフラグでラップし、さまざまな環境、ユーザー、またはユーザー セグメントに応じて機能のオンとオフを切り替えることができます。そうすれば、再デプロイすることなく、Flagsmith ダッシュボードからすべてを管理できるようになります。
それでは、以下のコマンドを実行して Flagsmith パッケージをインストールしましょう。
go get github.com/Flagsmith/flagsmith-go-client/v3
次に、flagsmith というエイリアスを付けてパッケージをインポートします。 。以下は、既存のコードに機能フラグを適用した後の更新された機能です。
ここで行った変更を理解しましょう (コード スニペットの下で説明します)。
package main
import (
"context"
"errors"
"fmt"
"log"
"net/http"
"os"
flagsmith "github.com/Flagsmith/flagsmith-go-client/v3"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis_rate/v10"
"github.com/joho/godotenv"
"github.com/redis/go-redis/v9"
)
var (
redisClient *redis.Client
limiter *redis_rate.Limiter
flagsmithClient *flagsmith.Client
)
func initClients() {
redisClient = redis.NewClient(&redis.Options{
Addr: os.Getenv("REDIS_URL"),
})
limiter = redis_rate.NewLimiter(redisClient)
flagsmithClient = flagsmith.NewClient(os.Getenv("FLAGSMITH_ENVIRONMENT_KEY"))
}
func main() {
err := godotenv.Load()
if err != nil {
log.Printf("Loading environment variable from the host system")
} else {
log.Printf("Loading environment from .env file")
}
initClients()
defer redisClient.Close()
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
err, remainingLimit := rateLimitCall(c.ClientIP())
if err != nil {
c.JSON(
http.StatusTooManyRequests,
gin.H{"error": "Rate Limit Hit"})
} else {
c.JSON(
http.StatusOK,
gin.H{"Your left over API request is": remainingLimit})
}
})
r.GET("/beta", func(c *gin.Context) {
flags := getFeatureFlags()
isEnabled, _ := flags.IsFeatureEnabled("beta")
if isEnabled {
c.JSON(
http.StatusOK,
gin.H{"message": "This is beta endpoint"})
} else {
c.String(http.StatusNotFound, "404 page not found")
}
})
r.Run(":" + os.Getenv("PORT"))
}
func rateLimitCall(ClientIP string) (error, int) {
ctx := context.Background()
flags := getFeatureFlags()
rateLimitInterface, _ := flags.GetFeatureValue("rate_limit")
RATE_LIMIT := int(rateLimitInterface.(float64))
fmt.Println("Current Rate Limit is", RATE_LIMIT)
res, err := limiter.Allow(ctx, ClientIP, redis_rate.PerHour(RATE_LIMIT))
if err != nil {
panic(err)
}
if res.Remaining == 0 {
return errors.New("You have hit the Rate Limit for the API. Try again later"), 0
}
fmt.Println("remaining request for", ClientIP, "is", res.Remaining)
return nil, res.Remaining
}
func getFeatureFlags() flagsmith.Flags {
ctx := context.Background()
flags, _ := flagsmithClient.GetEnvironmentFlags(ctx)
return flags
}
機能フラグ コード ロジックを理解する
func getFeatureFlags() flagsmith.Flags {
ctx := context.Background()
flags, _ := flagsmithClient.GetEnvironmentFlags(ctx)
return flags
}
まず、新しい getFeatureFlags() に直接ジャンプしましょう。 一番下に作成した関数。この関数は、GetEnvironmentFlags() を呼び出すことで、Flagsmith ダッシュボードで作成したすべてのフラグを返します。 flagsmithClient のメソッド .
flagsmithClient を開始しました initClients() 内 機能。 Flagsmith クライアントにはアクセス キー (NewClient()) が必要です。 関数)は、Flagsmith ダッシュボードから取得できます。 Redis および Limter クライアントの場合と同様に、再利用可能にするためにクライアントをグローバル変数に保存します。後のステップで、ダッシュボード、フラグの作成、キーの取得について理解します。
func rateLimitCall(ClientIP string) (error, int) {
ctx := context.Background()
flags := getFeatureFlags()
rateLimitInterface, _ := flags.GetFeatureValue("rate_limit")
RATE_LIMIT := int(rateLimitInterface.(float64))
fmt.Println("Current Rate Limit is", RATE_LIMIT)
res, err := limiter.Allow(ctx, ClientIP, redis_rate.PerHour(RATE_LIMIT))
if err != nil {
panic(err)
}
if res.Remaining == 0 {
return errors.New("You have hit the Rate Limit for the API. Try again later"), 0
}
fmt.Println("remaining request for", ClientIP, "is", res.Remaining)
return nil, res.Remaining
}
rateLimitCall() に移ります RATE_LIMIT を取得する代わりに関数を使用します。 環境から、rate_limit から値を取得します。 フラグ (後で作成します)。 getFeatureFlags() と呼びます。 フラグ rate_limit を取得します。 すべてのフラグから値を取り出します。
これらを機能フラグとして設定することで、ダッシュボードからいつでも制限を動的に変更できます。コードの機能を変更したり、RATE_LIMIT を変更する従来の方法で変更したりする必要はありません。 値を変更し、サーバーを再実行して、新しく更新された値をキャッチします。
r.GET("/beta", func(c *gin.Context) {
flags := getFeatureFlags()
isEnabled, _ := flags.IsFeatureEnabled("beta")
if isEnabled {
c.JSON(
http.StatusOK,
gin.H{"message": "This is beta endpoint"})
} else {
c.String(http.StatusNotFound, "404 page not found")
}
})
/beta に進みます エンドポイント、ベータ フラグが有効か無効かに基づいて、このエンドポイントはクエリを処理します。それ以外の場合、到達不能なエンドポイントとして機能し、404 エラー メッセージが返されます。
この例では、どのように機能するかを示すために基本的なプレースホルダー メッセージを追加しましたが、これによりテストと初期リリース (ベータ版) での新しい可能性が開かれます。 API に新しいエンドポイントがある場合は、その機能を機能フラグでラップし、ボタンを 1 回クリックするだけで使用可能または使用不可にすることができます。また、スケジュール設定やカナリア リリースなど、さらに多くのことを実行できます。
また、.env ファイルはこのようになります。 RATE_LIMIT を削除しました FLAGSMITH_ENVIRONMENT_KEY を追加しました .
REDIS_URL=localhost:6379
PORT=8080
FLAGSMITH_ENVIRONMENT_KEY=ser.ZRd***********469
Flasgsmith ダッシュボードで機能フラグを作成する方法
Flagsmith ダッシュボードに移動して、上で使用したフラグを作成し、アクセス キーを取得しましょう。 Flagsmith アカウントをお持ちでない場合は、ここから無料でサインアップできます。
サインアップすると、組織とプロジェクトを作成するように求められます。プロジェクトの分離は、さまざまなプロジェクトのロジックを分離するのに役立つため、優れています。完了すると、以下のスクリーンショットのようなダッシュボードが表示されます。
統合から変更を比較するためのフラグのスケジュール設定まで、さまざまな機能が用意されています。 Go 以外にも、Flagsmith は多くの SDK を提供しています。言語名が書かれている場所をクリックすると、その言語の定型コードが表示されます。

レート制限機能フラグ
次に、レート制限の最初の機能フラグを作成しましょう。 [フィーチャーの作成] をクリックします。 右上隅のボタンをクリックします。サイドバーウィンドウが開きます。名前を設定し、作成中にフラグを適切にオンにするには、デフォルトで有効を選択します。
値セクションでは、フラグの値を設定する必要があります。 Txt、JSON、XML などの形式を使用できます。特徴値は 20、30 などの単純なテキストであるため、Txt (デフォルトのもの) を選択し、ランダムな制限を設定します。20 を使用します。 .
タグや説明を付けることもできます。タグは、機能フラグをフィルタリングするときに役立ちます。たとえば、タグ backend を作成できます。 バックエンドに関連するすべての機能フラグをフィルターで除外します。この説明は、この特定の将来フラグが有効になったときにどのような動作をするかを簡潔に説明したものです (将来の理解に役立ちます)。
以下のスクリーンショットは、詳細を入力した後にどのように表示されるかを示しています。次に、[フィーチャーの作成] をクリックします。 ボタンをクリックしてフラグを作成します。

ベータ機能フラグ
次に、2 番目の beta を作成しましょう。 機能フラグ。最初のプロセスと同じプロセスですが、このプロセスではフラグ値を設定する必要はなく、その列を空のままにします。両方のフラグを作成すると、ダッシュボードは次のようになります。フラグ名、値、現在の状態 (ビュー) などが表示されます。

アクセス キーの取得
アクセス キーを取得するには、SDK キーをクリックします。 サイドバーから [サーバー側環境キーの作成] をクリックします。 ボタンをクリックしてキーを生成します。私たちのアプリはサーバー側であるため、そのアプリのみを使用することをお勧めします。次に、そのキーをコピーして、.env に配置された値に貼り付けます。 FLAGSMITH_ENVIRONMENT_KEY の場合 キー。

API の実行
これですべてが設定されたので、IDE に戻り、go run main.go を実行してサーバーを実行しましょう。 ターミナルでコマンドを実行します。ターミナルにこのメッセージが表示されます。エラーが発生した場合は、パッケージが正しくインストールされていること、変数が正しく設定されていること、アプリが Redis インスタンスにアクセスしていることを確認してください。

ここで、localhost:8080/ping にアクセスすると、 、メッセージ {"Your left over API request is":19} が表示されます。 。制限は 20 でしたが、現在 1 つのリクエストを実行しました。残りは 19 です。

rate_limit を更新しています フラグ
rate_limit を更新しましょう フラグの値を 10 に設定して、何が起こるかを確認してください。これを行うには、もう一度 Flagsmith ダッシュボードにアクセスし、フラグ名をクリックします。サイドメニューバーが開きます。値を 10 に更新し、[特徴値の更新] をクリックします。 ボタン。
更新をスケジュールすることもできます。たとえば、これは、特定の時間枠でトラフィックの急増が予想され、サーバーの負荷を軽減するためにユーザーごとの制限を減らす場合に役立ちます。

ここで localhost:8080/ping にアクセスすると、 、メッセージ {"Your left over API request is":8} が表示されます。 – 合計制限は 10 で、すでに 2 回リクエストしているためです。

/beta をテストしてみましょう。 エンドポイント。 localhost:8080/beta にアクセスすると、メッセージ {"message":"This is beta endpoint"} が表示されます。 .

次に、Flagsmith ダッシュボードに戻り、スイッチを切り替えてこのフラグを無効にします。次に、URL にアクセスします。このエンドポイントは存在しなかったというような 404 メッセージが表示されます。

機能を設定し、機能フラグ機能のデモを行ったので、Flasgsmith GitHub アプリをどのように統合できるかを見てみましょう。
機能フラグを GitHub アプリと統合する方法
まず、アプリを GitHub にプッシュしたことを確認します。その後、GitHub Marketplace から GitHub Flasgsmith アプリをリポジトリにインストールします。
GitHub と Falagsmith を統合することにより、機能フラグ/機能の更新を GitHub の問題とプル リクエストのコメントとして表示できるようになります。これにより、問題の作成から PR のマージ、変更のデプロイに至るまで、機能を簡単に追跡できるようになります。

次に、組織とアプリをインストールするリポジトリを選択します。すべてのリポジトリにインストールすることも、特定のリポジトリを選択することもできます。
インストールすると、Flagmsith ダッシュボードに自動的にリダイレクトされ、統合を構成して完了します。ほとんどのデータは事前に入力されているため、必要なのはプロジェクトを選択して追加し、構成を保存するだけです。

[設定ボタンを保存] をクリックしたら、 をクリックすると、以前に作業していたメインの Flagsmith ダッシュボードにリダイレクトされます。
ここで、既存のフラグの 1 つを GitHub の課題/プル リクエストにリンクしましょう (ダミーの PR/課題を生成してテストします)。または、テストする新しいフラグを作成することもできます。 beta 用にすでに作成したベータ フラグを使用してみましょう。 エンドポイント。
フラグを既存の問題またはプル リクエストにリンクするには、フラグ名をクリックすると、右側からサイド メニューがポップアップします。次に、「リンク」タブを選択します。次に、[プル リクエスト] オプションを選択し、リンクするプル リクエストを選択します。このフラグにリンクされているすべての問題とプル リクエストが以下に表示されます:

フラグが正常にリンクされていることを確認するには、名前の下にある矢印アイコンの付いたハイパーリンクをクリックします。 列見出し。 GitHub 上の特定の Issue/Pull Request に移動します。 Flagsmith GitHub アプリが、環境、有効な値などのすべての詳細を以下にコメントしていることがわかります。

Flagsmith GitHub アプリのテスト
この後、フラグのオン/オフや値の変更など、フラグ設定に変更を加えると、ボットは更新されたすべての詳細をコメントします。
フラグをオフにしてテストしてみましょう。ダッシュボードからフラッシュをオフにするとすぐに、ボットはフラグが無効になったことをコメントするはずです。

それだけです。このようにして、Flagsmith と GitHub を簡単に統合できます。
結論
要約すると、バックエンド開発者として機能フラグを活用してアプリの機能をその場で変更する方法がわかりました。
物事を次のレベルに進めるために、デモ アプリを Flagsmith GitHub アプリと統合しました。これにより、手動で更新しなくても、プル リクエスト/問題の機能フラグのステータスの変更に応じて最新の状態を維持できるようになりました。
こちらの Flagsmith リポジトリをチェックして、これらのプロジェクトのそれぞれにスターを付けてサポートを示すことを忘れないでください。また、素晴らしいコミュニティに参加して技術サポートを受けることもできます。
ここのソーシャル上で私、Pradumna Saraf とつながることができます。
無料でコーディングを学びましょう。 freeCodeCamp のオープンソース カリキュラムは、40,000 人以上の人々が開発者としての職に就くのに役立ちました。始めましょう
-
Redis on Flash:新しいデータエンジンとAmazonEC2I4iインスタンスで3.7倍高速になりました
Redis on Flash(RoF)は、最も人気のあるエンタープライズ機能の1つであり、データセットの最大80%を高価なDRAMではなくSSDに保存し、ミリ秒未満のレイテンシとRedisのハイスループット。通常の展開では、RoFは最大70%のTCO割引を提供します。 2つの新しいエキサイティングなコラボレーションにより、RoFが最大3.7倍のパフォーマンスを提供できるようになったことをお知らせします。 Redisで大規模なデータセットを実行する場合と同じ魅力的な総所有コストを維持しながら。まず、AWSは、第3世代のIntel Xeonスケーラブルプロセッサ(コード名はIce Lake)と
-
Redis と NextAuth を使用して Next.js ブログ用の安全なコメント システムを作成する
このチュートリアルでは、ブログのコメント セクションを作成します。今後の技術スタックは次のとおりです。 NextJS 13 (アプリディレクトリ内) NextAuth (認証用) Upstash Redis (コメントの保存用) SWR (コメントのキャッシュと再検証用) 始めましょう。 NextAuth による認証の処理 まず、誰でもコメントを投稿できるようにすることはできませんよね。誰かがスクリプトを実行して、あなたのブログにコメントをスパム送信する可能性があります。コメントを投稿できるようにする前に、まず認証システムを構築しましょう。 NextAuth を使用します。 next