redis 并发下写入数据丢失

2020-08-31 16:44:17 +08:00
 shuangdeyu

不懂就问,使用 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 个数据全部写进队列了:

3351 次点击
所在节点    程序员
12 条回复
useben
2020-08-31 17:40:27 +08:00
查看下 redis 连接是否有错误, 调大连接数
saturn7
2020-08-31 17:53:46 +08:00
看 demo 代码象只是复用单实例连接到 Redis Server,典型的写 PHP 思维。解决要用连接池 + 并发锁。
micean
2020-08-31 18:02:51 +08:00
lpush 的结果不观察一下吗?
JJstyle
2020-08-31 18:03:41 +08:00
@saturn7 楼主需要能并发插入数据,你给加一个并发锁,是要解决什么问题?
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",
})
}
huntcool001
2020-08-31 18:07:46 +08:00
没看明白. 你是怎么知道 lpush 结果正常的.. redis 返回值是什么, 异常有 catch 住打印没?


另外,消息队列最好用 Redis Stream 来做.
Citrus
2020-08-31 18:10:34 +08:00
你写请求发出去就不管了是咋知道这成功了呢?
90928yao
2020-08-31 18:13:45 +08:00
打个 redis 返回啊。肯定很多报错 拿不到链接
th00000
2020-08-31 18:20:59 +08:00
猜测一下: Redis 的写入是单线程的, 假设你的 dbhelper 是有缓存的, 每次去写的时候会等待前面写入之后再去写
但是你并发比较高, 导致前面的这个 dbhelper 还没来得及写入, 就被拎出来又存了数据, 继续排队, 导致只有最终数据写进去了
ZehaiZhang
2020-08-31 18:28:06 +08:00
之前 trycatch 发现了一些因为数据格式问题导致的 push 失败
PiersSoCool
2020-08-31 19:57:54 +08:00
大哥你这用异步跑,又没有同步措施,协程没跑完,主进程就退出了,肯定有问题啊
securityCoding
2020-09-01 10:01:05 +08:00
@PiersSoCool 加个 waitGroup 或者 chan

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

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

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

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

© 2021 V2EX