ioredis-尝试从redis迁移到keydb时出错

bvpmtnay  于 2021-06-09  发布在  Redis
关注(0)|答案(1)|浏览(678)

我们使用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。但事实并非如此!至少对我来说不是!我花了我的最后3天在互联网上寻找解决方案。我得出结论,我应该写信给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

我在几乎所有的互联网上都搜索了这个错误,但没有人提供解决方案,也没有人解释到底出了什么问题。
幸运的是,进程“有时”会显示错误的堆栈。它指向 lib/redis/index.ts:711 在ioredis代码中。我不知道它是干什么的。

(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的,我不使用它)
总结
这东西怎么了?

yxyvkwin

yxyvkwin1#

因为没有人在悬赏结束时写下答案。我正在写我的经验,解决问题的人谁会得到这个错误以后。
请注意,这不是一个规范的答案。但这是一个解决办法
我从分享发生的事情开始。
我们试图从一个拥有近60万个密钥的redis服务器迁移。标准的迁移过程花费了大量的时间将redis中的大量密钥传输到keydb。所以我找到了一个不同的解决方案。
我们的keydb在两个活动副本服务器上工作。我将提供链接到那些想知道这个系统是如何工作的。
https://medium.com/faun/failover-redis-like-cluster-from-two-masters-with-keydb-9ab8e806b66c
解决方案是使用一些mongodb数据库聚合重新构建redis数据,并在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);
}

使用在16个进程上运行此代码 pm2 在大约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版本上的一些权限错误造成的。所以我要求我们的服务器管理员检查,如果可能的话,删除docker版本并从rpm存储库中安装。

https://download.keydb.dev/packages/rpm/centos7/x86_64/

做了那件事就成功了。所有的错误都消失了,并在20分钟内成功地进行了迁移。
我不认为这是一个真正的答案。但这对于一些Maven找出问题所在应该是有用的。

相关问题