请教大佬一个高并发下操作 Reids 出现 read: connection reset by peer 的问题

2019-06-24 08:15:06 +08:00
 wewin

我的程序如下,目的就是为了测试,高并发下读取 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 的可用连接数不够了导致的问题,有理解的比较深入的大佬给个仔细的讲解吗?最好能给上解决方案,谢谢!

10260 次点击
所在节点    Go 编程语言
25 条回复
raynor2011
2019-06-24 08:31:10 +08:00
这种情况瓶颈是在 redis 那边,你要去分析 redis 机器的瓶颈,另外 redis 本身是单线程,异步客户端的话,不需要那么多连接
wewin
2019-06-24 08:38:06 +08:00
@raynor2011 要是有种场景下,就是有很大的并发请求来操作 redis,并且 redis 服务器已经做了相应的优化,这种情况下如何避免不出现这种问题?
ebingtel
2019-06-24 08:39:01 +08:00
1. 需要 netstat 看一下 tcp 连接的状态、再看一下 redislog, 才好说
2. 另外,根据他人的经验 https://www.jianshu.com/p/85cff688d02b,这个 redis 库的连接 不会自动释放,可能是这个问题导致的
raynor2011
2019-06-24 08:53:37 +08:00
@wewin redis 本身是单线程,你那么多请求发过去也是顺序执行的
emeab
2019-06-24 08:55:57 +08:00
redis 连接池?
abccccabc
2019-06-24 09:04:09 +08:00
tweproxy 代理多个 redis,试下??

当前因为单个 redis 已经顶不住了,那就多个一块顶。
q13859601
2019-06-24 09:40:56 +08:00
MaxActive: 0,这个是代表不限制么,是不是可以设置一下连接池的等待时间参数
petelin
2019-06-24 09:43:32 +08:00
如果真有并发链接的需求 也可以转化为异步队列读写
我估摸着应该是 Redis 有个配置最大连接数的东西
Leigg
2019-06-24 10:04:24 +08:00
你并发有多少??连接池最大数量限制为 redis 最大连接数以内不就行了。问题不在这
rrfeng
2019-06-24 10:16:19 +08:00
redis-server 默认有最大连接数限制( 10000 ),你这个 redis.Pool{ maxActive: 0} 不限制活跃连接数,瞬间就超了,超了之后就被 redis-server 断了。

把 maxActive 限制一下就可以。
judeng
2019-06-24 10:26:43 +08:00
config get maxclients 看看限制连接数多少
wewin
2019-06-24 12:57:00 +08:00
@Leigg 问题就是没有限制活跃连接数的问题。本来想法是 1000 个 goroutine 最多也就一个 1000 个连接,redis 的 maxclients 是 10000。所以没有想到是这里的问题。
wewin
2019-06-24 13:02:27 +08:00
@rrfeng
@judeng

问题就是没有限制活跃连接数的问题。本来想法是 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'
petelin
2019-06-24 13:52:20 +08:00
如果是 Redis 是 10000 不应该出现这个问题 还得接着查
petelin
2019-06-24 13:54:02 +08:00
@rrfeng 他不才连了 1000 个吗 为什么说瞬间就超了?
feelinglucky
2019-06-24 14:10:20 +08:00
Redis 并发的问题:1、检查 Redis 的配置,本身 Redis 是单线程的,所以再多的请求都是顺序发送的 2、本地客户端发那么多并发的话,流量也是量级的了,就应该考虑其他方式了。
Mirana
2019-06-24 14:52:18 +08:00
tcp 连接被对端关了,tcpdump 抓包看看
Hellert
2019-06-24 14:57:45 +08:00
你是不是开了 ss ?另外,是不是设置了 http_proxy 环境变量?
你把 http_proxy 和 https_proxy 环境变量删除掉,然后关掉 ss 试试。

我之前遇到过类似的问题,是因为 go 写的网络程序默认是走代理的,这个错误是 ss 那边报的。
dafsic
2019-06-24 15:45:50 +08:00
改为短链接,防止重用 tcp 连接
stone1342006
2019-06-24 18:34:12 +08:00
系统 somaxconn 设置大一点试试

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/576766

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX