Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"ClusterClient.Ping().Result() error: got 4 elements in cluster info address, expected 2 or 3" when used for accessing redis cluster #2085

Closed
yuantingzhong opened this issue May 4, 2022 · 15 comments · Fixed by #2110

Comments

@yuantingzhong
Copy link

Issue tracker is used for reporting bugs and discussing new features. Please use
stackoverflow for supporting issues.

go-redis reports error when it is used to access redis-cluster

Expected Behavior

go-redis/redis should works well with redis cluster

Current Behavior

go-redis/redis ClusterClient.Ping().Result() reports error "got 4 elements in cluster info address, expected 2 or 3" (my redis cluster has six nodes)

Possible Solution

Steps to Reproduce

  1. I build my redis cluster with docker and the redis's version is
"GOSU_VERSION=1.14",
"REDIS_VERSION=7.0.0",
"REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-7.0.0.tar.gz",

and my go version is

# go version
go version go1.18.1 linux/amd64
  1. I am sure my redis cluster works well, for example, I make a test with redis-cli as follows
root@hecs-18053-0002:/home/root/code/redis-cluster/cmd# docker run -it --rm redis redis-cli -c -h 192.168.0.28 -p 6700 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.0.28:6700> cluster nodes
27bfce46e99d870f7ca4ae5c51df30737581e0cf 192.168.0.180:6901@16901 master - 0 1651637749193 7 connected 0-5460
d93f9f77dc49e7177f6cadf6f32cd27e1ed4ead0 192.168.0.28:6900@16900 slave 27139ca982574acfb125a9d0421d99c47789f7c4 0 1651637750196 3 connected
c3c553a61c78fcdfd07ba6c72402f1d0a23bc006 192.168.0.141:6902@16902 slave f366d818f6c5cdf4ab7843ca8a14f39d58e0fa9d 0 1651637748189 2 connected
27139ca982574acfb125a9d0421d99c47789f7c4 192.168.0.141:6702@16702 master - 0 1651637748000 3 connected 10923-16383
fab30d84431b0e7cebdf0ed257b99e3192ba2d8d 192.168.0.28:6700@16700 myself,slave 27bfce46e99d870f7ca4ae5c51df30737581e0cf 0 1651637749000 7 connected
f366d818f6c5cdf4ab7843ca8a14f39d58e0fa9d 192.168.0.180:6701@16701 master - 0 1651637751199 2 connected 5461-10922
192.168.0.28:6700> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:7
cluster_stats_messages_ping_sent:45321
cluster_stats_messages_pong_sent:45740
cluster_stats_messages_sent:91061
cluster_stats_messages_ping_received:45740
cluster_stats_messages_pong_received:45321
cluster_stats_messages_update_received:5
cluster_stats_messages_received:91066
total_cluster_links_buffer_limit_exceeded:0
192.168.0.28:6700>
192.168.0.28:6700> keys *
1) "add"
2) "abb"
3) "bbb"
4) "kkkkkk"
5) "age"
6) "aac"
192.168.0.28:6700>

When I set or get key with redis-cli, it works well.
3. Then I test with a simple go program, as follows

package main

import (
        "context"
        "encoding/json"
        "fmt"
        "github.com/go-redis/redis/v8"
        "time"
)

func main() {
        rdb := redis.NewClusterClient(&redis.ClusterOptions{
                Password: "123456",
                Addrs: []string{"192.168.0.28:6700", "192.168.0.180:6701", "192.168.0.141:6702", "192.168.0.28:6900", "192.168.0.180:6901", "192.168.0.141:6902"},
        })

        _, err := rdb.Ping(context.Background()).Result()
        if err != nil {
                panic(err)
        }

        err = testString(rdb)
        if err != nil {
                panic(err)
        }
}

func testString(client *redis.ClusterClient) error {
        key := "mykey"
        err := client.Set(context.Background(), key, "myvalue", time.Minute).Err()
        if err != nil {
                fmt.Println("set err", err)
                return err
        }

        fmt.Println("--------------------------------------")
        for i := 0; i < 6; i++ {
                keyCnt, err := client.Exists(context.Background(), key).Result()
                if err != nil {
                        fmt.Println("client.Exists error: ", err)
                }
                fmt.Println("client.Exists val: ", keyCnt)

                val, err := client.Get(context.Background(), key).Result()
                if err != nil {
                        if err == redis.Nil { // key does not exist
                                fmt.Println("key not exist")
                        } else {
                                fmt.Println("Get err", err)
                                return err
                        }
                } else {
                        fmt.Printf("key: %v, value:%v\n", key, val)
                }

                time.Sleep(15 * time.Second)
        }

        return nil
}

build and run this program, it report error, as follows

# ./main
panic: got 4 elements in cluster info address, expected 2 or 3

goroutine 1 [running]:
main.main()
        /home/root/code/redis-cluster/cmd/main.go:19 +0x171

I think this is a bug, please check and fix it. Thank you very much!

Context (Environment)

Detailed Description

Possible Implementation

@UpwardGrowth
Copy link

Did you solve it, I have this problem too

@UpwardGrowth
Copy link

I guess you are using the latest redis version(7.x), I downgrade back to 6.x version solved the problem.

@md185331
Copy link

md185331 commented May 6, 2022

Hi what is the solution to this issue? What specific version tag works?

@lintanghui
Copy link
Contributor

cluster slots cmd is not backwards-incompatible in redis-7.0, see detail at Clusterbus extensions and hostname support . the same issue #2082

@yuantingzhong
Copy link
Author

Did you solve it, I have this problem too
Please downgrade back to redis 6.x version, I have tested with 6.2.7 and it works well.

@yuantingzhong
Copy link
Author

I guess you are using the latest redis version(7.x), I downgrade back to 6.x version solved the problem.

Yes, you are right. Thank you.

@yuantingzhong
Copy link
Author

Hi what is the solution to this issue? What specific version tag works?

I replaced redis 7.x with redis 6.x ,and it worked well.

@xs0910
Copy link

xs0910 commented May 30, 2022

我也遇到了,降回6.2.5就OK了

yqlu added a commit to yqlu/kubernetes-engine-samples that referenced this issue Jun 17, 2022
Following the codelab https://cloud.google.com/kubernetes-engine/docs/tutorials/upgrading-stateful-workload today yields an error: 
```
500 - Error due to redis cluster broken!
got 4 elements in cluster info address, expected 2 or 3
```

This seems to be because redis version 7 was released April of this year and is currently incompatible with go-redis. See 
redis/go-redis#2085 .

For now, we should fix redis in the codelab at 6.2 for it to continue working. Once a stable go-redis is released (v9 currently in beta -- https://github.com/go-redis/redis/tree/v9.0.0-beta.1), we can fix this to v7 instead, rebuild the image used in the app-deployment to the latest go-redis version as an alternative fix.
mathieu-benoit pushed a commit to GoogleCloudPlatform/kubernetes-engine-samples that referenced this issue Jun 17, 2022
Following the codelab https://cloud.google.com/kubernetes-engine/docs/tutorials/upgrading-stateful-workload today yields an error: 
```
500 - Error due to redis cluster broken!
got 4 elements in cluster info address, expected 2 or 3
```

This seems to be because redis version 7 was released April of this year and is currently incompatible with go-redis. See 
redis/go-redis#2085 .

For now, we should fix redis in the codelab at 6.2 for it to continue working. Once a stable go-redis is released (v9 currently in beta -- https://github.com/go-redis/redis/tree/v9.0.0-beta.1), we can fix this to v7 instead, rebuild the image used in the app-deployment to the latest go-redis version as an alternative fix.
@highsea
Copy link

highsea commented Jul 11, 2022

我从 redis:7.0.2-alpine 回退到 6.2 ,确实不报错了,谢谢
docker pull redis:6.2-alpine3.16

PS:
redis7集群有报错: Unable to connect to redis cluster got 4 elements in cluster info address, expected 2 or 3

@vmihailenco
Copy link
Collaborator

Please use github.com/go-redis/redis/v9 with Redis 7

jonyig added a commit to jonyig/docker-own that referenced this issue Jul 13, 2022
@mikhail-khalizev
Copy link

mikhail-khalizev commented Jul 18, 2022

  • post by mistake *

@SunGeolSong
Copy link

SunGeolSong commented Nov 9, 2023

hello
in source

parse.go

info := ClusterSlotInfo{
Start: int(start),
End: int(end),
Addrs: make([]string, addrsn),
}

	fmt.Printf("clusterSlotInfoSliceParser info.Addrs %v \n", info.Addrs)

	for i := int64(0); i < addrsn; i++ {

		fmt.Printf("clusterSlotInfoSliceParser loop i: %d \n", i)

		n, err := readArrayHeader(cn)
		if err != nil {
			return nil, err
		}

		fmt.Printf("clusterSlotInfoSliceParser loop i: %d, n: %d \n", i, n)

		if n != 2 && n != 3 && n != 4 {
			err := fmt.Errorf("clusterSlotInfoSliceParser got222 %d elements in cluster info address, expected 2 or 3 o 4", n)
			return nil, err
		}

		ip, err := readStringReply(cn)
		if err != nil {
			return nil, err
		}

		fmt.Printf("clusterSlotInfoSliceParser loop i: %d, ip: %s \n", i, ip)

		port, err := readIntReply(cn)
		if err != nil {
			return nil, err
		}

		fmt.Printf("clusterSlotInfoSliceParser loop i: %d, port: %d \n", i, port)

		if n >= 3 {
			// TODO: expose id in ClusterSlotInfo
			_, err := readStringReply(cn)
			if err != nil {
				return nil, err
			}
                            // redis 7.2 show master cluster address : 5d1a898d77d...
		}

		if n == 4 {
                 
			s2, err := readArrayHeader(cn)
			if err != nil {
				fmt.Printf("clusterSlotInfoSliceParser loop i: %d, err: %v \n", i, err)

				return nil, err
			}

			fmt.Printf("clusterSlotInfoSliceParser loop i: %d, s2: %d \n", i, s2) // *0 mean 7.2 maybe end of array
		}

		info.Addrs[i] = net.JoinHostPort(ip, strconv.FormatInt(port, 10))
	}

reloadSlots begin
Process begin + CLUSTER info:
Process end
reloadSlots 1
ClusterSlots begin
ClusterSlots cmd : CLUSTER slots: []
Process begin + CLUSTER slots: []
parseArrayHeader line: [42 51], line: *3
parseArrayHeader line[1:]: [51], line: 3, n: 3
clusterSlotInfoSliceParser begin
clusterSlotInfoSliceParser begin infos: []
readArrayHeader begin
readArrayHeader line [42 51], str: *3
readArrayHeader line[0] 42, str: *
parseArrayHeader line: [42 51], line: *3
parseArrayHeader line[1:]: [51], line: 3, n: 3
clusterSlotInfoSliceParser 1 n: 3
clusterSlotInfoSliceParser 2 start: 0
clusterSlotInfoSliceParser 3 end: 5460
clusterSlotInfoSliceParser addrsn: 1
clusterSlotInfoSliceParser info.Addrs []
clusterSlotInfoSliceParser loop i: 0
readArrayHeader begin
readArrayHeader line [42 52], str: *4
readArrayHeader line[0] 42, str: *
parseArrayHeader line: [42 52], line: *4
parseArrayHeader line[1:]: [52], line: 4, n: 4
clusterSlotInfoSliceParser loop i: 0, n: 4
readStringReply - b : [49 56 51 46 49 49 49 46 49 54 52 46 49 57]
clusterSlotInfoSliceParser loop i: 0, ip: 127.0.0.1
clusterSlotInfoSliceParser loop i: 0, port: 6381
readArrayHeader begin
readArrayHeader line [42 48], str: *0 <-- n: 4 mean
readArrayHeader line[0] 42, str: *
parseArrayHeader line: [42 48], line: *0
parseArrayHeader line[1:]: [48], line: 0, n: 0
clusterSlotInfoSliceParser loop i: 0, s2: 0

@SunGeolSong
Copy link

info := ClusterSlotInfo{
Start: int(start),
End: int(end),
Addrs: make([]string, addrsn),
}

	for i := int64(0); i < addrsn; i++ {
		n, err := readArrayHeader(cn)
		if err != nil {
			return nil, err
		}
		//if n != 2 && n != 3 {
		if n != 2 && n != 3 && n != 4 {
			err := fmt.Errorf("got %d elements in cluster info address, expected 2 or 3 or 4", n)
			return nil, err
		}

		ip, err := readStringReply(cn)
		if err != nil {
			return nil, err
		}

		port, err := readIntReply(cn)
		if err != nil {
			return nil, err
		}

		//if n == 3 {
		if n >= 3 {
			// TODO: expose id in ClusterSlotInfo
			_, err := readStringReply(cn)
			if err != nil {
				return nil, err
			}
		}

		if n == 4 {
			// TODO: expose id in ClusterSlotInfo
			_, err := readArrayHeader(cn) // *0 end
			if err != nil {
				return nil, err
			}
		}

		info.Addrs[i] = net.JoinHostPort(ip, strconv.FormatInt(port, 10))
	}

@liudonghua123
Copy link

I also got panic: got 4 elements in cluster info address, expected 2 or 3 when I tried to use go-redis with the latest redis 7.2.3.
Since this is a known issues, why not update it or it has bean fixed?

@yangbodong22011
Copy link

The real fix PR for this issue is: #2108

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.