我的程序如下,目的就是为了测试,高并发下读取 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 的可用连接数不够了导致的问题,有理解的比较深入的大佬给个仔细的讲解吗?最好能给上解决方案,谢谢!
1
raynor2011 2019-06-24 08:31:10 +08:00 1
这种情况瓶颈是在 redis 那边,你要去分析 redis 机器的瓶颈,另外 redis 本身是单线程,异步客户端的话,不需要那么多连接
|
2
wewin OP @raynor2011 要是有种场景下,就是有很大的并发请求来操作 redis,并且 redis 服务器已经做了相应的优化,这种情况下如何避免不出现这种问题?
|
3
ebingtel 2019-06-24 08:39:01 +08:00
1. 需要 netstat 看一下 tcp 连接的状态、再看一下 redislog, 才好说
2. 另外,根据他人的经验 https://www.jianshu.com/p/85cff688d02b,这个 redis 库的连接 不会自动释放,可能是这个问题导致的 |
4
raynor2011 2019-06-24 08:53:37 +08:00
@wewin redis 本身是单线程,你那么多请求发过去也是顺序执行的
|
5
2kCS5c0b0ITXE5k2 2019-06-24 08:55:57 +08:00
redis 连接池?
|
6
abccccabc 2019-06-24 09:04:09 +08:00
tweproxy 代理多个 redis,试下??
当前因为单个 redis 已经顶不住了,那就多个一块顶。 |
7
q13859601 2019-06-24 09:40:56 +08:00
MaxActive: 0,这个是代表不限制么,是不是可以设置一下连接池的等待时间参数
|
8
petelin 2019-06-24 09:43:32 +08:00 via iPhone
如果真有并发链接的需求 也可以转化为异步队列读写
我估摸着应该是 Redis 有个配置最大连接数的东西 |
9
Leigg 2019-06-24 10:04:24 +08:00 via iPhone
你并发有多少??连接池最大数量限制为 redis 最大连接数以内不就行了。问题不在这
|
10
rrfeng 2019-06-24 10:16:19 +08:00
redis-server 默认有最大连接数限制( 10000 ),你这个 redis.Pool{ maxActive: 0} 不限制活跃连接数,瞬间就超了,超了之后就被 redis-server 断了。
把 maxActive 限制一下就可以。 |
11
judeng 2019-06-24 10:26:43 +08:00
config get maxclients 看看限制连接数多少
|
12
wewin OP @Leigg 问题就是没有限制活跃连接数的问题。本来想法是 1000 个 goroutine 最多也就一个 1000 个连接,redis 的 maxclients 是 10000。所以没有想到是这里的问题。
|
13
wewin OP @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' |
14
petelin 2019-06-24 13:52:20 +08:00 via iPhone
如果是 Redis 是 10000 不应该出现这个问题 还得接着查
|
16
feelinglucky 2019-06-24 14:10:20 +08:00
Redis 并发的问题:1、检查 Redis 的配置,本身 Redis 是单线程的,所以再多的请求都是顺序发送的 2、本地客户端发那么多并发的话,流量也是量级的了,就应该考虑其他方式了。
|
17
Mirana 2019-06-24 14:52:18 +08:00
tcp 连接被对端关了,tcpdump 抓包看看
|
18
Hellert 2019-06-24 14:57:45 +08:00
你是不是开了 ss ?另外,是不是设置了 http_proxy 环境变量?
你把 http_proxy 和 https_proxy 环境变量删除掉,然后关掉 ss 试试。 我之前遇到过类似的问题,是因为 go 写的网络程序默认是走代理的,这个错误是 ss 那边报的。 |
19
dafsic 2019-06-24 15:45:50 +08:00
改为短链接,防止重用 tcp 连接
|
20
stone1342006 2019-06-24 18:34:12 +08:00
系统 somaxconn 设置大一点试试
|
21
onepunch 2019-06-24 21:10:55 +08:00
redis 管道技术了解一下,最近面试都在问这个 -,- 目前没碰到一个会的
|
22
freestyle 2019-06-24 22:12:03 +08:00 via iPhone
redigo: connection pool exhaustet 是 redigo 包返回的错误,和初始化 pool 的选项有关,你设置 maxActive 的同时把 wait=true 再试试效果
|
23
wewin OP @freestyle redigo: connection pool exhaustet 是和 maxActive 有关的,maxActive 需要设置和操作 redis 的 goroutine 数量差不多,或者多余 goroutine 的数量就不会出现 redigo: connection pool exhaustet 的错误
|
24
freestyle 2019-06-25 09:40:58 +08:00 via iPhone
@wewin 你得的结论不太严谨 不知道你没有有看 redigo 的 pool 的详细注释 wait 是表示当 pool 中没有可用的连接时是报错还是等待 .
|
25
SmartKeyerror 2019-06-25 11:08:31 +08:00
Redis 内部使用 epoll 事件驱动模型, 只要 redis-server 所在的服务器能够打开的文件描述符以及内存足够, 一般是不会出现连接数不够用的。 在我的机子上跑你这个代码,goroutine 的数量开到 10000 也不会有任何报错, 但是当同时运行的 goroutine 数量超过了 redis-server 默认的 maxClients(10000)数量之后, 会抛出 id incr error: ERR max number of clients reached, 但是这也是意料之中的问题。 所以我建议你看一下是不是 redigo 的版本或者是服务器的问题, 检查下服务器 TCP 最大连接数, 能够打开的最大文件数这些。
|