IOREDIS - 尝试从 Redis 迁移到 KeyDB 时出现错误。

7

我们一直使用Redis,直到得出结论:由于其功能,转向使用KeyDB可能是一个不错的选择。

环境

OS: Centos 7
NodeJs: v12.18.0
Redis: v6.0.5
Targeted KeyDB: v0.0.0 (git:1069d0b4) //  keydb-cli -v showed this. Installed Using Docker.
ioredis: v4.17.3
pm2: v4.2.1 // used for clustering my application. 

背景

根据KeyDB文档,KeyDB兼容最新版的Redis。

KeyDB仍然完全兼容Redis模块API和协议。因此,从Redis迁移到KeyDB非常简单,类似于在Redis到Redis情况下迁移的操作。 https://docs.keydb.dev/docs/migration/

在同一页面上,他们提供了一个兼容KeyDB的redis客户端列表。该列表包括我正在使用的ioredis。

KeyDB兼容所有Redis客户端,如此处所列,因此这不应该成为问题。只需像在Redis中一样使用您的客户端即可。 https://docs.keydb.dev/docs/migration/

问题

正如文档中所说,我应该能够在几个小时内轻松地迁移到KeyDB。但对于我来说并非如此!我花了过去的三天时间在互联网上搜索解决方案。我得出结论,我应该写给stackoverflow :)

问题有点有趣。客户端实际上正在使用KeyDb,并且该过程实际上正在设置和检索密钥(不确定但可能会在错误期间丢失一些数据)。但是有10%的时间会给我以下错误,并在一段时间后继续工作。由于我在生产环境中使用Redis存储会话和其他内容,所以我不能冒着忽略这种坚持出现的错误的风险。

error:  message=write EPIPE, stack=Error: write EPIPE
./app-error-1.log:37:    at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:92:16), errno=EPIPE, code=EPIPE, syscall=write

我在互联网上搜索了几乎所有与此错误有关的内容,但没有人提供解决方案或对出错原因进行解释。

幸运的是,该过程“有时”会显示一个错误栈。它指向 ioredis 代码中的 lib/redis/index.ts:711,但我不知道它的作用。

(stream || this.stream).write(command.toWritable());

https://github.com/luin/ioredis/blob/master/lib/redis/index.ts#L711

我在 ioredis 的 GitHub 存储库上发现了一些问题,其中提到了 EPIPE 错误。但是大部分都是关于错误处理的问题,并且已经标记为已解决。

我还在 Google 上发现了一些关于 EPIPE 错误的通用问题(大多数是关于我不使用的 socket.io 的内容)。

总结

这个东西有什么问题吗?


请问能否请管理员在stackoverflow上添加keydbkey-db标签? - Peshraw H. Ahmed
我成功地解决了这个问题,但仍然不知道为什么会发生。如果在悬赏结束时没有人回答,我将把我的经验作为答案发布给可能遇到此问题的任何人。 - Peshraw H. Ahmed
你之所以会遇到这个错误,是因为流被某种方式关闭了,可能是写入了null,在实例上调用了.end(),或者发生了一些致命的流错误。这是我在没有看到你的应用程序代码的情况下的最佳猜测。 - EddieDean
@EddieDean在服务器上执行了DEBUG=ioredis:* node app.js,但没有注意到任何错误。我认为一切都指向在Docker内部安装的问题。 - Peshraw H. Ahmed
如果是这样的话,提供有关您的技术栈和Docker使用的更多信息将会很有帮助。无论如何,如果您已经使其正常工作,那就太好了。我很想看看您的解决方案是什么。 - EddieDean
@EddieDean 写作为答案。 - Peshraw H. Ahmed
1个回答

2
由于没有人在赏金结束时写下答案,我将分享我的解决问题经验,以帮助那些以后会遇到这个错误的人。
请注意,这不是一个权威的答案,而是一个解决方法。
首先,我想分享一下出现了什么情况。
我们试图从一个Redis服务器迁移到一个存储近60万个键的KeyDB。标准的迁移过程需要很长时间才能将这么多的键从Redis转移到KeyDB。因此,我找到了一个不同的解决方案。
我们的KeyDB运行在两个活动-活动副本服务器上。我将提供链接,让那些想知道这个系统如何工作的人了解更多。

https://medium.com/faun/failover-redis-like-cluster-from-two-masters-with-keydb-9ab8e806b66c

重新构建Redis数据的解决方案是使用一些MongoDB数据库聚合,并对KeyDB进行一些批处理操作。
以下是一个模拟(不完全与源代码相同。我也没有测试语法错误)。
const startPoint =
            (Number.parseInt(process.env.NODE_APP_INSTANCE) || 0) * 40000;
let skip = 0 + startPoint;
let limit = 1000;
let results = await SomeMongooseSchema.find({someQueries}).limit(1000).skip(skip);

let counter = 0;
while (results.length){
   if(counter > 39) break;
   for(const res of results){
      const item = {
         key: '',
         value: ''
      };
      // do some build ups on item
      ...
      // end n
      app.ioRedisClient.set(item.key, item.value);
   }
   counter++;
   skip = i * limit + startPoint;
   results = await SomeMongooseSchema.find({someQueries}).limit(limit).skip(skip);
}

使用pm2在16个进程上运行此代码,大约需要45分钟将所有键设置为keyDB。(相比于4-5小时)

   pm2 start app.js -i 16 

当我们在Redis服务器上运行代码时,它可以正常工作,但在KeyDB上会出现以下错误。
error:  message=write EPIPE, stack=Error: write EPIPE
./app-error-1.log:37:    at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:92:16), errno=EPIPE, code=EPIPE, syscall=write

首先,我通过创建事务而不是逐个设置键来调整代码。并在每1000次操作之间设置了1秒的间隔。代码如下所示。

const startPoint =
            (Number.parseInt(process.env.NODE_APP_INSTANCE) || 0) * 40000;
let skip = 0 + startPoint;
let limit = 1000;
let results = await SomeMongooseSchema.find({someQueries}).limit(1000).skip(skip);

const batch = app.ioredisClient.multi();
let counter = 0;
while (results.length){
   if(counter > 39) break;
   for(const res of results){
      const item = {
         key: '',
         value: ''
      };
      // do some build ups on item
      ...
      // end n
      batch.set(item.key, item.value);
   }
   counter++;
   await batch.exec();
   await sleep();
   skip = i * limit + startPoint;
   results = await SomeMongooseSchema.find({someQueries}).limit(limit).skip(skip);
}


这样做将错误率降低到20分钟的操作时间内。但错误仍然存在。
我怀疑这个错误可能是由于docker版本的某些权限错误引起的。所以我请求我们的服务器管理员检查,并如果可能的话从rpm存储库中删除docker版本并重新安装。
https://download.keydb.dev/packages/rpm/centos7/x86_64/

我这样做了,它起作用了。所有的错误都消失了,成功地在20分钟内完成了迁移。

我不认为这是一个真正的答案。但对于一些专家来说,这应该是有用的,可以找出问题出在哪里。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接