IOREDIS - 尝试从 Redis 迁移到 KeyDB 时出错
IOREDIS - Error Trying to Migrate from Redis to 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 remains fully compatible with Redis modules API and protocol. As such a migration from Redis to KeyDB is very simple and would be similar to what you would expect migrating in a Redis to Redis scenario. https://docs.keydb.dev/docs/migration/
在同一页面中,他们提供了与 KeyDB 兼容的 Redis 客户端列表。该列表包含我正在使用的 ioredis。
KeyDB is compatible with all Redis clients as listed here so this should not be a concern. Simply use your client as you would with Redis.
https://docs.keydb.dev/docs/migration/
问题
如文档中所述。我应该能够在几个小时内轻松迁移到 KeyDB。好吧,事实并非如此!至少不适合我!我花了最后 3 天时间在互联网上搜索解决方案。我得出的结论是我应该写信给 Whosebug :)
这个问题有点有趣。客户端实际上正在使用 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
我几乎在整个互联网上搜索了这个错误,但没有人提供解决方案,也没有人解释发生了什么问题。
幸运的是,进程 "sometimes" 显示了错误的堆栈。它指向 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 的,这不是我使用的东西。)
总结
这东西怎么了?
因为没有人在赏金结束时写下答案。我正在为以后会遇到此错误的人写下解决问题的经验。
请注意,这不是规范的答案。但这是一种解决方法
我开始分享发生的事情。
我们试图从托管近 600 000 个密钥的 Redis 服务器迁移。标准迁移过程需要花费大量时间将大量密钥从 Redis 传输到 keyDB。所以我遇到了一个不同的解决方案。
我们的 KeyDB 在 2 个双活副本服务器上运行。我会向那些想知道这个系统如何工作的人提供 link。
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 分钟内成功迁移。
我认为这不是真正的答案。但这对一些专家找出问题所在应该是有用的。
我们使用 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 remains fully compatible with Redis modules API and protocol. As such a migration from Redis to KeyDB is very simple and would be similar to what you would expect migrating in a Redis to Redis scenario. https://docs.keydb.dev/docs/migration/
在同一页面中,他们提供了与 KeyDB 兼容的 Redis 客户端列表。该列表包含我正在使用的 ioredis。
KeyDB is compatible with all Redis clients as listed here so this should not be a concern. Simply use your client as you would with Redis. https://docs.keydb.dev/docs/migration/
问题
如文档中所述。我应该能够在几个小时内轻松迁移到 KeyDB。好吧,事实并非如此!至少不适合我!我花了最后 3 天时间在互联网上搜索解决方案。我得出的结论是我应该写信给 Whosebug :)
这个问题有点有趣。客户端实际上正在使用 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
我几乎在整个互联网上搜索了这个错误,但没有人提供解决方案,也没有人解释发生了什么问题。
幸运的是,进程 "sometimes" 显示了错误的堆栈。它指向 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 的,这不是我使用的东西。)
总结
这东西怎么了?
因为没有人在赏金结束时写下答案。我正在为以后会遇到此错误的人写下解决问题的经验。
请注意,这不是规范的答案。但这是一种解决方法
我开始分享发生的事情。
我们试图从托管近 600 000 个密钥的 Redis 服务器迁移。标准迁移过程需要花费大量时间将大量密钥从 Redis 传输到 keyDB。所以我遇到了一个不同的解决方案。
我们的 KeyDB 在 2 个双活副本服务器上运行。我会向那些想知道这个系统如何工作的人提供 link。
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 分钟内成功迁移。
我认为这不是真正的答案。但这对一些专家找出问题所在应该是有用的。