不懂就问,使用 redis 的 list 类型做消息队列,通过这个队列将要写到 mysql 的数据延后批量写入
遇到的问题是,使用 jmeter 测并发的时候发现,10000 线程的时候,写到 redis 的数据会丢失,而且丢失数量是不规则的; 5000 线程以内则一切正常,主要想知道这是什么原因?单机如何去优化?替代方案比如 MQ 暂时不考虑。
使用语言是 Go,代码如下,其实也很简单,只是往 redis 队列中推入数据,用 Redis Manager 观察:
func Testt(c *gin.Context) {
// 这是测试数据,数据长度小得到的也是一样的结果
//x := `{"Dateline":"2020-08-31 13:34:59","Error":200002,"Id":"ee0da19f-eb05-4728-8e23-107336043ede","Ip":"192.168.2.150","Method":"POST","Resp":"null"}`
// 这是封装的 LPush 函数
dbhelper.Lpush("testttt", "_api", "1")
c.JSON(200, gin.H{
"e": 0,
"msg": "success",
})
}
10000 线程的测试结果,只存进去 1542 个数据:
5000 线程的测试结果,5000 个数据全部写进队列了:
感谢大家的回答,问题找到了,测试代码没有严谨对待,没有抛出错误信息,饶了弯路 =_= ,一直在钻redis配置的牛角尖,加上后抛出的错误是"connection pool timeout",然后修改代码,在建立连接客户端的时候在"redis.Options"中配置连接池大小等属性后问题解决,因为默认的"PoolSize"只有10,一个进程内10000的并发量自然是不够用了。
配置连接数上也发现了问题,修改"redis.conf"连接数后发现数量怎么都不会增加,因为之前有解决mysql连接数问题的经验,很快就找到还有一个隐藏的"limit.conf"中一个"LimitNOFILE"参数限制了最大连接数,修改后连接数修改就能生效了。
1
useben 2020-08-31 17:40:27 +08:00
查看下 redis 连接是否有错误, 调大连接数
|
2
saturn7 2020-08-31 17:53:46 +08:00
看 demo 代码象只是复用单实例连接到 Redis Server,典型的写 PHP 思维。解决要用连接池 + 并发锁。
|
3
micean 2020-08-31 18:02:51 +08:00
lpush 的结果不观察一下吗?
|
5
fanpei0121 2020-08-31 18:06:39 +08:00
经测试 并发 10 万条 redis 插入,没有漏数据,测试代码不要太在意细节。
func Test(c *gin.Context) { // 这是测试数据,数据长度小得到的也是一样的结果 x := `{"Dateline":"2020-08-31 13:34:59","Error":200002,"Id":"ee0da19f-eb05-4728-8e23-107336043ede","Ip":"192.168.2.150","Method":"POST","Resp":"null"}` // 这是封装的 LPush 函数 rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", DB: 0, }) dataChan := make(chan string, 1000) go func() { for i := 1; i <= 100000; i++ { dataChan <- x } }() for j := 1; j < 20; j++ { go func() { for { data := <-dataChan err := rdb.RPush("test111", data).Err() logs.Error(err) } }() } c.JSON(200, gin.H{ "e": 0, "msg": "success", }) } |
6
huntcool001 2020-08-31 18:07:46 +08:00
没看明白. 你是怎么知道 lpush 结果正常的.. redis 返回值是什么, 异常有 catch 住打印没?
另外,消息队列最好用 Redis Stream 来做. |
7
Citrus 2020-08-31 18:10:34 +08:00 via iPhone
你写请求发出去就不管了是咋知道这成功了呢?
|
8
90928yao 2020-08-31 18:13:45 +08:00
打个 redis 返回啊。肯定很多报错 拿不到链接
|
9
th00000 2020-08-31 18:20:59 +08:00
猜测一下: Redis 的写入是单线程的, 假设你的 dbhelper 是有缓存的, 每次去写的时候会等待前面写入之后再去写
但是你并发比较高, 导致前面的这个 dbhelper 还没来得及写入, 就被拎出来又存了数据, 继续排队, 导致只有最终数据写进去了 |
10
ZehaiZhang 2020-08-31 18:28:06 +08:00
之前 trycatch 发现了一些因为数据格式问题导致的 push 失败
|
11
PiersSoCool 2020-08-31 19:57:54 +08:00
大哥你这用异步跑,又没有同步措施,协程没跑完,主进程就退出了,肯定有问题啊
|
12
securityCoding 2020-09-01 10:01:05 +08:00
@PiersSoCool 加个 waitGroup 或者 chan
|