

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 適用於 Go 的 DAX 軟體開發套件
<a name="DAX.client.run-application-go-2"></a>

請按照此程序操作，在 Amazon EC2 執行個體上執行 Amazon DynamoDB Accelerator (DAX) 適用於 Go 的開發套件範例應用程式。

**為 DAX 執行適用於 Go 的開發套件範例**

1. 在您的 Amazon EC2 執行個體上設定適用於 Go 的開發套件：

   1. 安裝 Go 程式設計語言 (`Golang`)。

      ```
      sudo yum install -y golang
      ```

   1. 測試 Golang 是否已安裝並正常運作。

      ```
      go version
      ```

      這類的訊息應會出現。

      ```
      go version go1.23.4 linux/amd64
      ```

1. 安裝範例 Golang 應用程式。

   ```
   go get github.com/aws-samples/sample-aws-dax-go-v2
   ```

1. 執行下列 Golang 程式。第一個程式會建立名為 `TryDaxGoTable` 的 DynamoDB 資料表。第二個程式會將資料寫入資料表。

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command create-table
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command put-item
   ```

1. 執行下列 Golang 程式。

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command get-item
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command query
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command scan
   ```

   記下計時資訊：`GetItem`、`Query` 和 `Scan` 測試所需要的毫秒數。

1. 在先前的步驟中，您已針對 DynamoDB 端點執行程式。現在，請再次執行程式，但這一次 `GetItem`、`Query` 和 `Scan` 操作會由您的 DAX 叢集處理。

   若要判斷您 DAX 叢集的端點，請選擇下列其中一個項目：
   + **使用 DynamoDB 主控台**：選擇您的 DAX 叢集。叢集端點會在主控台上顯示，如以下範例。

     ```
     dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com
     ```
   + **使用 AWS CLI** ：輸入下列命令。

     ```
     aws dax describe-clusters --query "Clusters[*].ClusterDiscoveryEndpoint"
     ```

     如下列範例所示，叢集端點會在輸出上顯示。

     ```
     {
         "Address": "my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com",
         "Port": 8111,
         "URL": "dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com"
     }
     ```

   現在重新執行程式，但這一次，請將叢集端點做為命令列參數指定。

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command get-item -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command query -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command scan -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command paginated-scan -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command paginated-query -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command paginated-batch-get -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   查看輸出的剩餘部分，並記下計時資訊。使用 DAX 的 `GetItem`、`Query` 和 `Scan` 已耗用時間應遠低於使用 DynamoDB 的已耗用時間。

1. 執行以下 Golang 程式，刪除 `TryDaxGoTable`。

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command delete-table
   ```

## 功能與 適用於 Go 的 AWS SDK V2 不相同
<a name="DAX.client.run-application-go-features-not-in-parity"></a>

中介軟體堆疊：DAX Go V2 不支援透過 APIoptions 使用中介軟體堆疊。如需詳細資訊，請參閱[使用 Middleware 自訂 適用於 Go 的 AWS SDK v2 用戶端請求](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/middleware.html#:~:text=You%20can%20customize%20AWS%20SDK,step's%20input%20and%20output%20types)。

範例：

```
// Custom middleware implementation
type customSerializeMiddleware struct{}
// ID returns the identifier for the middleware
func (m *customSerializeMiddleware) ID() string {
    return "CustomMiddleware"
}
// HandleSerialize implements the serialize middleware handler
func (m *customSerializeMiddleware) HandleSerialize(
    ctx context.Context,
    in middleware.SerializeInput,
    next middleware.SerializeHandler,
) (
    out middleware.SerializeOutput,
    metadata middleware.Metadata,
    err error,
) {
    // Add your custom logic here before the request is serialized
    fmt.Printf("Executing custom middleware for request: %v\n", in)
    // Call the next handler in the middleware chain
    return next.HandleSerialize(ctx, in)
}

func executeGetItem(ctx context.Context) error {
    client, err := initItemClient(ctx)
    if err != nil {
        os.Stderr.WriteString(fmt.Sprintf("failed to initialize client: %v\n", err))
        return err
    }

    st := time.Now()
    for c := 0; c < iterations; c++ {
        for i := 0; i < pkMax; i++ {
            for j := 0; j < skMax; j++ {
                // Create key using attributevalue.Marshal for type safety
                pk, err := attributevalue.Marshal(fmt.Sprintf("%s_%d", keyPrefix, i))
                if err != nil {
                    return fmt.Errorf("error marshaling pk: %v", err)
                }
                sk, err := attributevalue.Marshal(fmt.Sprintf("%d", j))
                if err != nil {
                    return fmt.Errorf("error marshaling sk: %v", err)
                }
                key := map[string]types.AttributeValue{
                    "pk": pk,
                    "sk": sk,
                }
                in := &dynamodb.GetItemInput{
                    TableName: aws.String(table),
                    Key:       key,
                }

                // Custom middleware option
                customMiddleware := func(o *dynamodb.Options) {
                    o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error {
                        // Add custom middleware to the stack
                        return stack.Serialize.Add(&customSerializeMiddleware{}, middleware.After)
                    })
                }

                // Apply options to the GetItem call
                out, err := client.GetItem(ctx, in, customMiddleware)
                if err != nil {
                    return err
                }
                writeVerbose(out)
            }
        }
    }
    d := time.Since(st)
    os.Stdout.WriteString(fmt.Sprintf("Total Time: %v, Avg Time: %v\n", d, d/iterations))
    return nil
}
```

輸出：

```
failed to execute command: custom middleware through APIOptions is not supported in DAX client
exit status 1
```

# Go 的預設用戶端組態
<a name="DAX-client-config-Go"></a>

本指南將逐步解說組態選項，協助您微調 DAX 用戶端效能、連線管理和日誌記錄行為。了解預設設定以及如何自訂這些設定後，您就可以最佳化 Go 應用程式與 DAX 的互動。

**Topics**
+ [DAX Go SDK 用戶端預設值](#DAX-client-config-Go-sdk-client-defaults)
+ [建立用戶端](#DAX-client-config-Go-client-creation)

## DAX Go SDK 用戶端預設值
<a name="DAX-client-config-Go-sdk-client-defaults"></a>


| 參數 | 類型 | 說明 | 
| --- | --- | --- | 
|  `Region` 必要  |  `string`  |   AWS 區域 用於 DAX 用戶端的 (example- 'us-east-1')。如果未透過環境提供，則此為必要參數。  | 
|  `HostPorts` 必要  |  `[] string`  |  SDK 連線的 DAX 叢集端點清單。 例如： 未加密：dax：//my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com 加密：daxs：//my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com  | 
|  `MaxPendingConnectionsPerHost` 預設 10  |  `number`  | 並行連線嘗試次數 (可同時建立的連線。)  | 
|  `ClusterUpdateThreshold` 預設 125 \$1 time.Millisecond  |  `time.Duration`  | 叢集重新整理之間必須經過的最短時間。  | 
|  `ClusterUpdateInterval` 預設 4 \$1 time.Second  |  `time.Duration`  | 用戶端自動重新整理 DAX 叢集資訊的間隔。  | 
|  `IdleConnectionsReapDelay` 預設 30 \$1 time.Second  |  `time.Duration`  | 用戶端在 DAX 用戶端中關閉閒置連線的間隔。  | 
|  `ClientHealthCheckInterval` 預設 5 \$1 time.Second  |  `time.Duration`  | 用戶端在 DAX 叢集端點執行運作狀態檢查的間隔。  | 
|  `Credentials` 預設  |  `aws.CredentialsProvider`  | DAX 用戶端用來驗證 DAX 服務請求的 AWS 登入資料。請參閱[憑證和憑證供應者](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/migrate-gosdk.html#credentials--credential-providers)。  | 
|  `DialContext` 預設  |  `func`  | DAX 用戶端用來建立 DAX 叢集連線的自訂函式。  | 
|  `SkipHostnameVerification` 預設 false  |  bool  |  略過 TLS 連線的主機名稱驗證。此設定只會影響加密的叢集。設定為 True 時，會停用主機名稱驗證。停用驗證表示您無法驗證所連線叢集的身分，會造成安全風險。預設會啟用主機名稱驗證。  | 
|  `RouteManagerEnabled` 預設 false  |  `bool`  | 此旗標用於移除面向網路的路由錯誤。  | 
|  `RequestTimeout` 預設 60 \$1 time.Second  |  `time.Duration`  | 這用於定義用戶端等待 DAX 回應的時間上限。 優先順序：內容逾時 (如果設定) > `RequestTimmeout` (如果設定) > 預設 60 秒 `RequestTimeout`。  | 
|  `WriteRetries` 預設 2  |  `number`  |  寫入請求失敗時的重試次數。  | 
|  `ReadRetries` 預設 2  |  `number`  | 讀取請求失敗時的重試次數。  | 
|  `RetryDelay` 預設 0  |  `time.Duration`  | 請求失敗重試時的非限流錯誤延遲 (以秒為單位)。  | 
|  `Logger` 選擇性  |  `logging.Logger`  | Logger 是以日誌記錄特定分類項目的介面。  | 
|  `LogLevel` 預設 utils.LogOff  |  `number`  | 此日誌層級僅針對 DAX 定義。您可以使用 [github.com/aws/aws-dax-go-v2/tree/main/dax/utils](https://github.com/aws/aws-dax-go-v2/tree/main/dax/utils) 匯入。 <pre>const (    <br /> LogOff LogLevelType = 0   <br /> LogDebug LogLevelType = 1   <br /> LogDebugWithRequestRetries<br /> LogLevelType = 2<br />)</pre>  | 

**注意**  
對於 `time.Duration`，預設單位為奈秒。如果我們沒有為任何參數指定任何單位，則會將其視為奈秒：`daxCfg.ClusterUpdateInterval = 10` 表示 10 奈秒。(`daxCfg.ClusterUpdateInterval = 10 * time.Millisecond` 表示 10 毫秒)。

## 建立用戶端
<a name="DAX-client-config-Go-client-creation"></a>

**如欲建立 DAX 用戶端：**
+ 建立 DAX 組態，然後使用 DAX 組態建立 DAX 用戶端。您可使用此功能視需要覆寫 DAX 組態。

  ```
  import (
  "github.com/aws/aws-dax-go-v2/dax/utils"
  "github.com/aws/aws-dax-go-v2/dax"
  )
  
  // Non - Encrypted : 'dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com'.
  // Encrypted : daxs://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com'.
  
  config := dax.DefaultConfig()
  config.HostPorts = []string{endpoint}
  config.Region = region
  config.LogLevel = utils.LogDebug
  daxClient, err := dax.New(config)
  ```

# 移轉至 DAX Go SDK V2
<a name="DAX.client.run-application-go-migrating"></a>

此移轉指南將協助您轉換現有的 DAX Go 應用程式。

## 使用 V1 DAX Go SDK
<a name="DAX.client.run-application-go-V1-usage"></a>

```
package main

import (
    "fmt"
    "os"

    "github.com/aws/aws-dax-go/dax"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
)

func main() {
    region := "us-west-2"
    endpoint := "dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com"
    
    // Create session
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String(region),
    })
    if err != nil {
        fmt.Printf("Failed to create session: %v\n", err)
        os.Exit(1)
    }
    
    // Configure DAX client
    cfg := dax.DefaultConfig()
    cfg.HostPorts = []string{endpoint} 
    cfg.Region = region

    // Create DAX client
    daxClient, err := dax.New(cfg)
    if err != nil {
        fmt.Printf("Failed to create DAX client: %v\n", err)
        os.Exit(1)
    }
    defer daxClient.Close() // Don't forget to close the client

    // Create GetItem input
    input := &dynamodb.GetItemInput{
        TableName: aws.String("TryDaxTable"),
        Key: map[string]*dynamodb.AttributeValue{
            "pk": {
                N: aws.String("1"),
            },
            "sk": {
                N: aws.String("1"),
            },
        },
    }

    // Make the GetItem call
    result, err := daxClient.GetItem(input)
    if err != nil {
        fmt.Printf("Failed to get item: %v\n", err)
        os.Exit(1)
    }

    // Print the result
    fmt.Printf("GetItem succeeded: %+v\n", result)
}
```

## 使用 V2 DAX Go SDK
<a name="DAX.client.run-application-go-V2-usage"></a>

```
package main

import (
    "context"
    "fmt"
    "os"

    "github.com/aws/aws-dax-go-v2/dax"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
    "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
    "github.com/aws/aws-sdk-go-v2/aws"
)

func main() {
    ctx := context.Background()
    region := "us-west-2"
    endpoint := "dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com"
   
    // Create DAX config
    config := dax.DefaultConfig()
    // Specify Endpoint and Region
    config.HostPorts = []string{endpoint}
    config.Region = region
    // Enabling logging
    config.LogLevel = utils.LogDebug
    // Create DAX client
    daxClient, err := dax.New(config) 
    if err != nil {
        fmt.Printf("Failed to create DAX client: %v\n", err)
        os.Exit(1)
    }
    defer daxClient.Close() // Don't forget to close the client

    // Create key using attributevalue.Marshal for type safety
    pk, err := attributevalue.Marshal(fmt.Sprintf("%s_%d", keyPrefix, i))
    if err != nil {
        return fmt.Errorf("error marshaling pk: %v", err)
    }
    sk, err := attributevalue.Marshal(fmt.Sprintf("%d", j))
    if err != nil {
        return fmt.Errorf("error marshaling sk: %v", err)
    }
                
    // Create GetItem input
    input := &dynamodb.GetItemInput{
        TableName: aws.String("TryDaxTable"),
        Key: map[string]types.AttributeValue{
             "pk": pk,
             "sk": sk,
        },
    }

    // Make the GetItem call
    result, err := daxClient.GetItem(ctx, input)
    if err != nil {
        fmt.Printf("Failed to get item: %v\n", err)
        os.Exit(1)
    }

    // Print the result
    fmt.Printf("GetItem succeeded: %+v\n", result)
}
```

如需 API 使用詳細資訊，請參閱 [AWS 範例](https://github.com/aws-samples/sample-aws-dax-go-v2)。