클라이언트 라이브러리 코드 샘플

이 페이지에서는 클러스터 모드 사용 설정 및 클러스터 모드 사용 중지 모드가 모두 있는 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 클라이언트 라이브러리

Valkey GLIDE 외에도 Memorystore for Valkey는 다음 Valkey OSS 클라이언트 라이브러리와 호환됩니다.

시스템 및 서비스

Spring Boot, PostgreSQL, 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

go-redis 버전 9.11.0 이상을 사용하는 것이 좋습니다.

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

버전 1.24.5 이상의 Go를 사용하는 것이 좋습니다.

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)
}