クライアント ライブラリのコードサンプル

このページでは、クラスタモードが有効なモードとクラスタモードが無効なモードの両方を備えた Memorystore for Valkey インスタンスのコードサンプルを提供します。

クラスタ モードが有効になっている場合のコードサンプル

Memorystore for Valkey は、Memorystore for Redis Cluster のすべてのクライアント コードサンプルと互換性があります。

Valkey GLIDE について

Valkey General Language Independent Driver for the Enterprise(GLIDE)はオープンソースのクライアント ライブラリで、すべての Valkey コマンドをサポートしています。

Valkey GLIDE を使用して、アプリケーションを Memorystore for Valkey インスタンスに接続できます。Valkey GLIDE は、信頼性、最適化されたパフォーマンス、高可用性を実現するように設計されています。

アプリケーションの開発と運用の整合性を確保するため、Valkey GLIDE は、言語固有の拡張機能を使用して Rust で記述されたコア ドライバ フレームワークを使用して実装されています。この設計により、言語間で機能の一貫性が確保され、複雑さが軽減されます。

Valkey GLIDE は、Valkey のバージョン 7.2 と 8.0 をサポートしています。以下の言語でご利用いただけます。

その他の Valkey OSS クライアント ライブラリ

Memorystore for Valkey は、Valkey GLIDE に加えて、次の Valkey OSS クライアント ライブラリと互換性があります。

システムとサービス

Spring BootPostgreSQL、Memorystore for Valkey を使用して、次のシステムとサービスを作成できます。

  • セッション管理システム: セッション管理は、最新のウェブ アプリケーションの重要な部分であり、複数のリクエストにわたってユーザーの操作の一貫性と安全性を確保します。キャッシュ保存レイヤを使用すると、アプリケーションはユーザー セッションを効率的に管理しながら、データベースの負荷を軽減し、スケーラビリティを確保できます。
  • スケーラブルなリーダーボード システム: リーダーボードは、アプリでランキング データを表示するのに便利な方法です。キャッシュ保存レイヤを使用すると、データベースの負荷を軽減しながら、リアルタイムのリーダーボード ランキングを提供できます。
  • 高性能キャッシュ保存サービス: 最新のアプリケーションは、高速で応答性の高いユーザー エクスペリエンスを大規模に提供する必要があります。このキャッシュ サービスを構築することで、レイテンシとデータベースの負荷の両方を軽減できます。

クラスタモードが無効の場合のコードサンプル

Memorystore for Valkey クラスタモードが無効になっている場合、クラスタモードが有効になっている場合のコードサンプルに記載されているすべての Redis および Valkey OSS クライアント ライブラリと互換性があります。

Memorystore for Valkey でクラスタモードが無効になっているインスタンスを使用する場合は、次の操作を行います。

  • ライブラリが提供する RedisCluster または ValkeyCluster クライアント オブジェクトの代わりに、Redis または Valkey クライアント オブジェクトを使用します。
  • プライマリ エンドポイントの IP アドレスを使用して、ライター クライアントを作成します。
  • リーダー エンドポイントの IP アドレスを使用して、リーダー クライアントを作成します。

redis-py

バージョン 5.1 以降の redis-py を使用することをおすすめします。

import redis
primaryEndpoint = PRIMARY_ENDPOINT_IP
readerEndpoint = READER_ENDPOINT_IP

primary_client = redis.Redis(host=primaryEndpoint, port=6379, db=0, decode_responses=True)
reader_client = redis.Redis(host=readerEndpoint, port=6379, db=0, decode_responses=True)

primary_client.set("key","value")
print(reader_client.get("key"))

go-redis

バージョン 9.11.0 以降の go-redis を使用することをおすすめします。

package main

import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)

func main() {
primary_endpoint := PRIMARY_ENDPOINT_IP
reader_endpoint := READER_ENDPOINT_IP

primary_client := redis.NewClient(&redis.Options{
  Addr:     primary_endpoint,
  Password: "", // no password set
  DB:       0,  // use default DB
})

reader_client := redis.NewClient(&redis.Options{
  Addr:     reader_endpoint,
  Password: "", // no password set
  DB:       0,  // use default DB
})

ctx := context.Background()

err := primary_client.Set(ctx, "foo", "bar", 0).Err()
if err != nil {
  panic(err)
}

val, err := reader_client.Get(ctx, "foo").Result()
if err != nil {
  panic(err)
}
fmt.Println("foo", val)
}

ジェダイ

Jedis バージョン 4.4.0 以降を使用することをおすすめします。


package org.example;

import java.io.*;
import java.time.LocalDateTime;
import java.lang.Thread;
import java.util.HashMap;
import java.util.Map;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class Main
{
public static void main( String[] args )
{
  primaryEndpoint = PRIMARY_ENDPOINT_IP

  JedisPool pool = new JedisPool(primaryEndpoint, 6379);

  try (Jedis jedis = pool.getResource()) {
    jedis.set("foo", "bar");
    System.out.println(jedis.get("foo")); // prints bar

    Map hash = new HashMap<>();;
    hash.put("name", "John");
    hash.put("surname", "Smith");
    hash.put("company", "Redis");
    hash.put("age", "29");
    jedis.hset("user-session:123", hash);
    System.out.println(jedis.hgetAll("user-session:123"));
    // Prints: {name=John, surname=Smith, company=Redis, age=29}
  } catch (Exception e) {
    System.out.println("Error setting or getting  key: " + e.getMessage());
  }
}
}

Node.js

Node.js バージョン 24.4.1 以降を使用することをおすすめします。

import { createClient } from 'redis';
import * as fs from 'fs';

const primaryEndpoint = PRIMARY_ENDPOINT_IP

const primary_endpoint_url ='redis://primaryEndpoint:6379'

const client = createClient({
url: primary_endpoint_url
});

await client.connect();
await client.set(key, value);
const retval = await client.get(key);
console.log(retval)

IAM 認証と転送中の暗号化の両方のコードサンプル

このセクションでは、さまざまなクライアント ライブラリで IAM 認証転送中の暗号化の両方を使用して、Memorystore for Valkey インスタンスを認証して接続する方法の例を示します。

redis-py

バージョン 5.1 以降の redis-py を使用することをおすすめします。

from google.cloud import iam_credentials_v1
from redis.backoff import ConstantBackoff
from redis.retry import Retry
from redis.exceptions import (
ConnectionError,
AuthenticationWrongNumberOfArgsError,
AuthenticationError
)
from redis.utils import (str_if_bytes)

import redis

service_account="projects/-/serviceAccounts/<TO-DO-1: your service account that used to authenticate to Valkey>""

host=<TO-DO-2: your Redis Cluster discovery endpoint ip>
ssl_ca_certs=<TO-DO-3, your trusted server ca file name>

def generate_access_token():
  # Create a client
  client = iam_credentials_v1.IAMCredentialsClient()

  # Initialize request argument(s)
  request = iam_credentials_v1.GenerateAccessTokenRequest(
      name=service_account,
      scope=['https://www.googleapis.com/auth/cloud-platform'],
  )

  # Make the request
  response = client.generate_access_token(request=request)
  print(str(response.access_token))

  # Handle the response
  return str(response.access_token)

class ValkeyTokenProvider(redis.CredentialProvider):

    # Generated IAM tokens are valid for 15 minutes
    def get_credentials(self):
        token= generate_access_token()
        return "default",token

creds_provider = ValkeyTokenProvider()
client = redis.Redis(host=host, port=6379, credential_provider=creds_provider, ssl=True, ssl_ca_certs=caFilePath)
client.set('foo',"bar")
print(client.get('foo'))

Go

Go バージョン 1.24.5 以降を使用することをおすすめします。

package main

import (
  "context"
  "crypto/tls"
  "crypto/x509"
  "flag"
  "fmt"
  "io/ioutil"
  "log"
  "sync"
  "time"

  credentials "google.golang.org/genproto/googleapis/iam/credentials/v1"

  "github.com/golang/protobuf/ptypes"
  "github.com/redis/go-redis/v9"
  "google.golang.org/api/option"
  gtransport "google.golang.org/api/transport/grpc"
)

var (
  svcAccount               = flag.String("a", "projects/-/serviceAccounts/example-service-account@example-project.iam.gserviceaccount.com", "service account email")
  lifetime                 = flag.Duration("d", time.Hour, "lifetime of token")
  refreshDuration          = flag.Duration("r", 5*time.Minute, "token refresh duration")
  checkTokenExpiryInterval = flag.Duration("e", 10*time.Second, "check token expiry interval")
  lastRefreshInstant       = time.Time{}
  errLastSeen              = error(nil)
  token                    = ""
  mu                       = sync.RWMutex{}
  err                      = error(nil)
)

func retrieveToken() (string, error) {
  ctx := context.Background()
  conn, err := gtransport.Dial(ctx,
    option.WithEndpoint("iamcredentials.googleapis.com:443"),
    option.WithScopes("https://www.googleapis.com/auth/cloud-platform"))

  if err != nil {
    log.Printf("Failed to dial API, error: %v", err)
    return token, err
  }
  client := credentials.NewIAMCredentialsClient(conn)
  req := credentials.GenerateAccessTokenRequest{
    Name:     *svcAccount,
    Scope:    []string{"https://www.googleapis.com/auth/cloud-platform"},
    Lifetime: ptypes.DurationProto(*lifetime),
  }
  rsp, err := client.GenerateAccessToken(ctx, &req)
  if err != nil {
    log.Printf("Failed to call GenerateAccessToken with request: %v, error: %v", req, err)
    return token, err
  }
  return rsp.AccessToken, nil
}

func refreshTokenLoop() {
  if *refreshDuration > *lifetime {
    log.Fatal("Refresh should not happen after token is already expired.")
  }
  for {
    mu.RLock()
    lastRefreshTime := lastRefreshInstant
    mu.RUnlock()
    if time.Now().After(lastRefreshTime.Add(*refreshDuration)) {
      var err error
      retrievedToken, err := retrieveToken()
      mu.Lock()
      token = retrievedToken
      if err != nil {
        errLastSeen = err
      } else {
        lastRefreshInstant = time.Now()
      }
      mu.Unlock()
    }
    time.Sleep(*checkTokenExpiryInterval)
  }
}

func retrieveTokenFunc() (string, string) {
  mu.RLock()
  defer mu.RUnlock()
  if time.Now().After(lastRefreshInstant.Add(*refreshDuration)) {
    log.Printf("Token is expired. last refresh instant: %v, refresh duration: %v, error that was last seen: %v", lastRefreshInstant, *refreshDuration, errLastSeen)
    return "", ""
  }
  username := "default"
  password := token
  return username, password
}

func main() {
  caFilePath := CA_FILE_PATH
  clusterDicEpAddr := PRIMARY_ENDPOINT_IP_ADDRESS_AND_PORT
  caCert, err := ioutil.ReadFile(caFilePath)
  if err != nil {
    log.Fatal(err)
  }
  caCertPool := x509.NewCertPool()
  caCertPool.AppendCertsFromPEM(caCert)
  token, err = retrieveToken()
  if err != nil {
    log.Fatal("Cannot retrieve IAM token to authenticate to the cluster, error: %v", err)
  }
  token, err = retrieveToken()
  fmt.Printf("token : %v", token)
  if err != nil {
    log.Fatal("Cannot retrieve IAM token to authenticate to the cluster, error: %v", err)
  }
  lastRefreshInstant = time.Now()
  go refreshTokenLoop()

  client := redis.NewClient(&redis.Options{
    Addr:                clusterDicEpAddr,
    CredentialsProvider: retrieveTokenFunc,
    TLSConfig: &tls.Config{
      RootCAs: caCertPool,
    },
  })

  ctx := context.Background()
  err = client.Set(ctx, "foo", "bar", 0).Err()
  if err != nil {
    log.Fatal(err)
  }
  val, err := client.Get(ctx, "foo").Result()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Printf("\nGot the value for key: key, which is %s \n", val)
}