Dragonfly(dragonflydb)とGrafana,PrometheusでRedis Exporter不要の監視

# 1.はじめに

- 2022年に発表されたインメモリキャッシュ製品のDragonflyを立ち上げてみます。
  - 箱から出してすぐに動作するGrafana+Prometheusで監視環境も構築します。
  - redisクライアント(golang)から呼び出して動作確認します。

# 2.Dragonflyとは

2022年に発表されたインメモリキャッシュ製品です。Redisのドロップイン代替品を目指しています。

https://dragonflydb.io/

- Redisよりも最大25倍高速(公称)
  - [LRFU evictionキャッシュ](https://dragonflydb.io/blog/2022/06/23/cache_design/)
  - [io_uringを利用した非同期IO]()
  - [シェアードナッシングアーキテクチャ](https://dragonflydb.io/blog/2021/11/28/redis_analysis/)
- Redis Exporter無しでメトリクスを監視


# 3.環境構築

## grafana,prometheus設定

- 公式リポジトリからgrafana,prometheus設定を取得する

https://github.com/dragonflydb/dragonfly/tree/main/tools/local/monitoring

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161516/8ec733ed-9592-5693-789d-0f64753997a2.png)

## compose.yml作成

```yaml:compose.yml
services:
  dragonfly:
    image: 'docker.dragonflydb.io/dragonflydb/dragonfly'
    container_name: dragonfly
    restart: unless-stopped
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - "6579:6379"
    volumes:
      - dragonfly_data:/data

  prometheus:
    image: prom/prometheus:v2.39.1
    container_name: prometheus_df
    restart: unless-stopped
    command:
      - '--config.file=/etc/prometheus/prometheus.yaml'
    expose:
      - 9090
    configs:
      - source: prometheus
        target: /etc/prometheus/prometheus.yaml
        mode: 440
    volumes:
      - prometheus_data:/prometheus

  grafana:
    image: grafana/grafana:9.2.1
    container_name: grafana_df
    restart: unless-stopped
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=Grafana
      - GF_USERS_DEFAULT_THEME=light
    ports:
      - 9000:3000
    configs:
      - source: grafana-datasource
        target: /etc/grafana/provisioning/datasources/datasource.yaml
        mode: 440
      - source: grafana-dashboard-json
        target: /etc/grafana/provisioning/dashboards/dashboard.json
        mode: 440
      - source: grafana-dashboard-yaml
        target: /etc/grafana/provisioning/dashboards/dashboard.yaml
        mode: 440
    volumes:
      - grafana_data:/var/lib/grafana

configs:
  prometheus:
    # https://github.com/dragonflydb/dragonfly/blob/main/tools/local/monitoring/prometheus/prometheus.yml
    file: ./prometheus/prometheus.yml
  grafana-datasource:
    # https://github.com/dragonflydb/dragonfly/blob/main/tools/local/monitoring/grafana/provisioning/datasources/datasource.yml
    file: ./grafana/datasource.yml
  grafana-dashboard-json:
    # https://github.com/dragonflydb/dragonfly/blob/main/tools/local/monitoring/grafana/provisioning/dashboards/dashboard.json
    file: ./grafana/dashboard.json
  grafana-dashboard-yaml:
    # https://github.com/dragonflydb/dragonfly/blob/main/tools/local/monitoring/grafana/provisioning/dashboards/dashboard.yml
    file: ./grafana/dashboard.yml

volumes:
  dragonfly_data:
  prometheus_data:
  grafana_data:
```

## 実行

```
docker compose up -d
```

# 4.テスト実施

```golang:main_test.go
package main

import (
	"context"
	"testing"

	"github.com/go-redis/redis/v9"
	"github.com/stretchr/testify/assert"
)

func TestExampleClient(t *testing.T) {

	ctx := context.Background()

	tests := []struct {
		name         string
		key          string
		expected     string
		expected_err error
	}{
		{
			name:         "test",
			key:          "key",
			expected:     "value",
			expected_err: redis.Nil,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(ti *testing.T) {

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

			for i := 0; i < 10_000; i++ {
				errB := rdb.Set(ctx, "key", "value", 0).Err()
				assert.NoError(ti, errB, "they should NoError")

				val, err := rdb.Get(ctx, tt.key).Result()
				assert.Equal(ti, val, tt.expected, "they should be equal")
				assert.NoError(ti, err, "they should be ok")

				val, err = rdb.Get(ctx, "will-empty").Result()
				assert.Empty(ti, val, "they should be equal")
				assert.Equal(ti, err, tt.expected_err, "they should be redis.Nil")
				assert.EqualError(ti, err, tt.expected_err.Error(), "they should be redis.Nil")
			}
		})
	}
}

```

## 結果

- テストを通過できた。
- 性能監視できた。

```
>go test -timeout 30s -run ^TestExampleClient$ github.com/my/repo
ok  	github.com/my/repo	16.905s
```

![localhost_9009_d_xDLNRKUWz_dragonfly-dashboard_orgId=1&from=now-5m&to=now(pcdisplay).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161516/a1f89ec2-d1c5-c5a1-32af-5a5c058b5caa.png)

# 参考情報

https://docs.docker.com/compose/compose-file/