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

时间:2020-06-16 10:11:30

标签: javascript node.js redis ioredis keydb

我们使用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与列出的here的所有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的错误,这不是我所使用的。)

总结

这东西怎么了?

1 个答案:

答案 0 :(得分:0)

由于没有人在赏金结束时写下答案。我将自己的解决经验写给以后会遇到此错误的人们。

请注意,这不是一个规范的答案。但这是一种解决方法

我开始分享正在发生的事情。

我们正试图从托管了将近60万个密钥的Redis服务器进行迁移。标准迁移过程需要大量时间才能将大量密钥从Redis转移到keyDB。所以我遇到了一个不同的解决方案。

我们的KeyDB可在2个Active-Active副本服务器上工作。我将提供那些想知道该系统如何工作的人的链接。

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

该解决方案是使用一些MongoDB数据库聚合并在KeyDB上执行一些批处理操作来重建我们的Redis数据。

这是一个模拟(来源不确切。我也没有测试语法错误)

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版本上的某些权限错误引起的。因此,我要求我们的服务器管理员进行检查,并在可能的情况下删除docker版本并从rpm存储库安装。

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

做到了,它奏效了。所有错误均消失,并在20分钟内成功迁移。

我不认为这是真正的答案。但这对于某些专家找出问题所在很有用。