Golang Go语言中高并发下操作 Redis 出现 read: connection reset by peer 的问题

Golang Go语言中高并发下操作 Redis 出现 read: connection reset by peer 的问题

我的程序如下,目的就是为了测试,高并发下读取 redis 会出现什么问题:

package main

import (
	"fmt"
	"time"

	"github.com/garyburd/redigo/redis"
)

var pool *redis.Pool

type User struct {
	ID       int    `json:"id"`
	Name     string `json:"name"`
	Password string `json:"password"`
}

func init() {
	pool = &redis.Pool{
		// 初始化链接数量
		MaxIdle:     16,
		MaxActive:   0,
		IdleTimeout: 300 * time.Second,
		Dial: func() (redis.Conn, error) {
			return redis.Dial("tcp", "127.0.0.1:6379")
		},
	}
}

func idIncr(conn redis.Conn) (id int, err error) {
	res, err := conn.Do("incr", "users_id_for_test")
	if err != nil {
		fmt.Printf("id incr error: %v\n", err)
		return
	}
	id = int(res.(int64))
	fmt.Printf("id: %v\n", id)
	return
}

func Register() (err error) {
	conn := pool.Get()
	defer conn.Close()

	// id 自增 1,作为下个用户 id
	id, err := idIncr(conn)
	if err != nil {
		return
	}

	_, err = conn.Do("rpush", "usersList", id)
	if err != nil {
		fmt.Printf("set user to reids error: %v", err)
		return
	}
	return
}

// 测试高并发下操作 redis
func main() {
	for i := 0; i < 1000; i++ {
		go Register()
	}
	time.Sleep(10 * time.Second)
}

这种情况下会有大量的报错

id incr error: read tcp 127.0.0.1:54156->127.0.0.1:6379: read: connection reset by peer

减少 goroutine 的数量不会有问题

应该是在高并发下 redis 的可用连接数不够了导致的问题,有理解的比较深入的大佬给个仔细的讲解吗?最好能给上解决方案,谢谢!


更多关于Golang Go语言中高并发下操作 Redis 出现 read: connection reset by peer 的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

26 回复

这种情况瓶颈是在 redis 那边,你要去分析 redis 机器的瓶颈,另外 redis 本身是单线程,异步客户端的话,不需要那么多连接

更多关于Golang Go语言中高并发下操作 Redis 出现 read: connection reset by peer 的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


要是有种场景下,就是有很大的并发请求来操作 redis,并且 redis 服务器已经做了相应的优化,这种情况下如何避免不出现这种问题?

  1. 需要 netstat 看一下 tcp 连接的状态、再看一下 redislog, 才好说
    2. 另外,根据他人的经验 https://www.jianshu.com/p/85cff688d02b,这个 redis 库的连接 不会自动释放,可能是这个问题导致的

redis 本身是单线程,你那么多请求发过去也是顺序执行的

redis 连接池?

tweproxy 代理多个 redis,试下??

当前因为单个 redis 已经顶不住了,那就多个一块顶。

MaxActive: 0,这个是代表不限制么,是不是可以设置一下连接池的等待时间参数

如果真有并发链接的需求 也可以转化为异步队列读写
我估摸着应该是 Redis 有个配置最大连接数的东西

你并发有多少??连接池最大数量限制为 redis 最大连接数以内不就行了。问题不在这

redis-server 默认有最大连接数限制( 10000 ),你这个 redis.Pool{ maxActive: 0} 不限制活跃连接数,瞬间就超了,超了之后就被 redis-server 断了。

把 maxActive 限制一下就可以。

config get maxclients 看看限制连接数多少

问题就是没有限制活跃连接数的问题。本来想法是 1000 个 goroutine 最多也就一个 1000 个连接,redis 的 maxclients 是 10000。所以没有想到是这里的问题。




问题就是没有限制活跃连接数的问题。本来想法是 1000 个 goroutine 最多也就一个 1000 个连接,而 redis 的 maxclients 是 10000,所以没有想到是这里的问题。

通过 runtime.NumGoroutine() 查到 goroutine 的峰值是 1001。也就是一个主 goroutine + 1000 个 ‘Register’ goroutine。

经过测试, maxActive 最好限制到 1000 左右,太少会报错 ‘redigo: connection pool exhausted’,不限制就是报错 ‘read: connection reset by peer’

如果是 Redis 是 10000 不应该出现这个问题 还得接着查

他不才连了 1000 个吗 为什么说瞬间就超了?

Redis 并发的问题:1、检查 Redis 的配置,本身 Redis 是单线程的,所以再多的请求都是顺序发送的 2、本地客户端发那么多并发的话,流量也是量级的了,就应该考虑其他方式了。

tcp 连接被对端关了,tcpdump 抓包看看

你是不是开了 ss ?另外,是不是设置了 http_proxy 环境变量?
你把 http_proxy 和 https_proxy 环境变量删除掉,然后关掉 ss 试试。

我之前遇到过类似的问题,是因为 go 写的网络程序默认是走代理的,这个错误是 ss 那边报的。

改为短链接,防止重用 tcp 连接

系统 somaxconn 设置大一点试试

redis 管道技术了解一下,最近面试都在问这个 -,- 目前没碰到一个会的

redigo: connection pool exhaustet 是 redigo 包返回的错误,和初始化 pool 的选项有关,你设置 maxActive 的同时把 wait=true 再试试效果

redigo: connection pool exhaustet 是和 maxActive 有关的,maxActive 需要设置和操作 redis 的 goroutine 数量差不多,或者多余 goroutine 的数量就不会出现 redigo: connection pool exhaustet 的错误

你得的结论不太严谨 不知道你没有有看 redigo 的 pool 的详细注释 wait 是表示当 pool 中没有可用的连接时是报错还是等待 .

Redis 内部使用 epoll 事件驱动模型, 只要 redis-server 所在的服务器能够打开的文件描述符以及内存足够, 一般是不会出现连接数不够用的。 在我的机子上跑你这个代码,goroutine 的数量开到 10000 也不会有任何报错, 但是当同时运行的 goroutine 数量超过了 redis-server 默认的 maxClients(10000)数量之后, 会抛出 id incr error: ERR max number of clients reached, 但是这也是意料之中的问题。 所以我建议你看一下是不是 redigo 的版本或者是服务器的问题, 检查下服务器 TCP 最大连接数, 能够打开的最大文件数这些。

在Golang中,高并发场景下操作Redis时遇到“read: connection reset by peer”错误,通常表明Redis服务器或中间网络设备(如负载均衡器、防火墙)主动关闭了连接。这个问题可能由以下几个原因引起:

  1. Redis连接池配置不当:在高并发下,如果连接池中的连接数不足或连接复用率不高,频繁创建和销毁连接可能导致服务器压力增大,从而主动断开连接。建议优化连接池配置,如增加最大连接数、调整连接超时时间等。

  2. Redis服务器负载过高:当Redis服务器处理请求的能力达到极限时,可能会主动断开一些连接以减轻负载。监控Redis服务器的性能指标,如CPU使用率、内存占用、网络I/O等,确保服务器资源充足。

  3. 网络问题:网络不稳定或网络设备故障也可能导致连接被重置。检查网络连接稳定性,以及网络设备(如交换机、路由器)的健康状态。

  4. 客户端超时设置:客户端设置的读写超时时间过短,也可能导致在操作过程中连接被服务器断开。适当增加超时时间设置,以应对网络延迟或服务器处理延迟。

解决这类问题,通常需要综合考虑以上因素,逐步排查并优化。同时,确保Redis客户端库(如go-redis)版本与Redis服务器版本兼容,也是避免此类问题的重要一环。

回到顶部