perf(queue): BullMQ + DragonflyDB で Hashtag を使用しすべてをロックしないようにする (MisskeyIO#838)
This commit is contained in:
parent
18f354c58f
commit
8c81bb9b6a
11 changed files with 34 additions and 23 deletions
|
@ -24,7 +24,7 @@ services:
|
||||||
DFLY_snapshot_cron: '* * * * *'
|
DFLY_snapshot_cron: '* * * * *'
|
||||||
DFLY_version_check: false
|
DFLY_version_check: false
|
||||||
DFLY_tcp_backlog: 2048
|
DFLY_tcp_backlog: 2048
|
||||||
DFLY_default_lua_flags: allow-undeclared-keys
|
DFLY_lock_on_hashtags: true
|
||||||
DFLY_pipeline_squash: 0
|
DFLY_pipeline_squash: 0
|
||||||
DFLY_multi_exec_squash: false
|
DFLY_multi_exec_squash: false
|
||||||
DFLY_conn_io_threads: 4
|
DFLY_conn_io_threads: 4
|
||||||
|
|
4
.github/workflows/test-backend.yml
vendored
4
.github/workflows/test-backend.yml
vendored
|
@ -38,7 +38,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
DFLY_version_check: false
|
DFLY_version_check: false
|
||||||
DFLY_tcp_backlog: 2048
|
DFLY_tcp_backlog: 2048
|
||||||
DFLY_default_lua_flags: allow-undeclared-keys
|
DFLY_lock_on_hashtags: true
|
||||||
DFLY_pipeline_squash: 0
|
DFLY_pipeline_squash: 0
|
||||||
DFLY_multi_exec_squash: false
|
DFLY_multi_exec_squash: false
|
||||||
DFLY_conn_io_threads: 4
|
DFLY_conn_io_threads: 4
|
||||||
|
@ -99,7 +99,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
DFLY_version_check: false
|
DFLY_version_check: false
|
||||||
DFLY_tcp_backlog: 2048
|
DFLY_tcp_backlog: 2048
|
||||||
DFLY_default_lua_flags: allow-undeclared-keys
|
DFLY_lock_on_hashtags: true
|
||||||
DFLY_pipeline_squash: 0
|
DFLY_pipeline_squash: 0
|
||||||
DFLY_multi_exec_squash: false
|
DFLY_multi_exec_squash: false
|
||||||
DFLY_conn_io_threads: 4
|
DFLY_conn_io_threads: 4
|
||||||
|
|
|
@ -44,8 +44,8 @@ spec:
|
||||||
value: false
|
value: false
|
||||||
- name: DFLY_tcp_backlog
|
- name: DFLY_tcp_backlog
|
||||||
value: 2048
|
value: 2048
|
||||||
- name: DFLY_default_lua_flags
|
- name: DFLY_lock_on_hashtags
|
||||||
value: allow-undeclared-keys
|
value: true
|
||||||
- name: DFLY_pipeline_squash
|
- name: DFLY_pipeline_squash
|
||||||
value: 0
|
value: 0
|
||||||
- name: DFLY_multi_exec_squash
|
- name: DFLY_multi_exec_squash
|
||||||
|
|
|
@ -12,7 +12,7 @@ services:
|
||||||
DFLY_snapshot_cron: '* * * * *'
|
DFLY_snapshot_cron: '* * * * *'
|
||||||
DFLY_version_check: false
|
DFLY_version_check: false
|
||||||
DFLY_tcp_backlog: 2048
|
DFLY_tcp_backlog: 2048
|
||||||
DFLY_default_lua_flags: allow-undeclared-keys
|
DFLY_lock_on_hashtags: true
|
||||||
DFLY_pipeline_squash: 0
|
DFLY_pipeline_squash: 0
|
||||||
DFLY_multi_exec_squash: false
|
DFLY_multi_exec_squash: false
|
||||||
DFLY_conn_io_threads: 4
|
DFLY_conn_io_threads: 4
|
||||||
|
|
|
@ -32,7 +32,7 @@ services:
|
||||||
DFLY_snapshot_cron: '* * * * *'
|
DFLY_snapshot_cron: '* * * * *'
|
||||||
DFLY_version_check: false
|
DFLY_version_check: false
|
||||||
DFLY_tcp_backlog: 2048
|
DFLY_tcp_backlog: 2048
|
||||||
DFLY_default_lua_flags: allow-undeclared-keys
|
DFLY_lock_on_hashtags: true
|
||||||
DFLY_pipeline_squash: 0
|
DFLY_pipeline_squash: 0
|
||||||
DFLY_multi_exec_squash: false
|
DFLY_multi_exec_squash: false
|
||||||
DFLY_conn_io_threads: 4
|
DFLY_conn_io_threads: 4
|
||||||
|
|
|
@ -17,6 +17,7 @@ export type RedisOptionsSource = Partial<RedisOptions> & {
|
||||||
pass: string;
|
pass: string;
|
||||||
db?: number;
|
db?: number;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
|
queueNameSuffix?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
import { Inject, Module, OnApplicationShutdown } from '@nestjs/common';
|
import { Inject, Module, OnApplicationShutdown } from '@nestjs/common';
|
||||||
import * as Bull from 'bullmq';
|
import * as Bull from 'bullmq';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config, RedisOptionsSource } from '@/config.js';
|
||||||
import { QUEUE, baseQueueOptions } from '@/queue/const.js';
|
import { QUEUE, baseQueueOptions, formatQueueName } from '@/queue/const.js';
|
||||||
import { allSettled } from '@/misc/promise-tracker.js';
|
import { allSettled } from '@/misc/promise-tracker.js';
|
||||||
import { Queues } from '@/misc/queues.js';
|
import { Queues } from '@/misc/queues.js';
|
||||||
import type { Provider } from '@nestjs/common';
|
import type { Provider } from '@nestjs/common';
|
||||||
|
@ -36,13 +36,13 @@ const $endedPollNotification: Provider = {
|
||||||
|
|
||||||
const $deliver: Provider = {
|
const $deliver: Provider = {
|
||||||
provide: 'queue:deliver',
|
provide: 'queue:deliver',
|
||||||
useFactory: (config: Config) => new Queues(config.redisForDeliverQueues.map(queueConfig => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(queueConfig, config.bullmqQueueOptions, QUEUE.DELIVER)))),
|
useFactory: (config: Config) => createQueues(QUEUE.DELIVER, config.redisForDeliverQueues, config.bullmqQueueOptions),
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
const $inbox: Provider = {
|
const $inbox: Provider = {
|
||||||
provide: 'queue:inbox',
|
provide: 'queue:inbox',
|
||||||
useFactory: (config: Config) => new Queues(config.redisForInboxQueues.map(queueConfig => new Bull.Queue(QUEUE.INBOX, baseQueueOptions(queueConfig, config.bullmqQueueOptions, QUEUE.INBOX)))),
|
useFactory: (config: Config) => createQueues(QUEUE.INBOX, config.redisForInboxQueues, config.bullmqQueueOptions),
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ const $db: Provider = {
|
||||||
|
|
||||||
const $relationship: Provider = {
|
const $relationship: Provider = {
|
||||||
provide: 'queue:relationship',
|
provide: 'queue:relationship',
|
||||||
useFactory: (config: Config) => new Queues(config.redisForRelationshipQueues.map(queueConfig => new Bull.Queue(QUEUE.RELATIONSHIP, baseQueueOptions(queueConfig, config.bullmqQueueOptions, QUEUE.RELATIONSHIP)))),
|
useFactory: (config: Config) => createQueues(QUEUE.RELATIONSHIP, config.redisForRelationshipQueues, config.bullmqQueueOptions),
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,6 +70,10 @@ const $webhookDeliver: Provider = {
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function createQueues(name: typeof QUEUE[keyof typeof QUEUE], config: RedisOptionsSource[], queueOptions: Partial<Bull.QueueOptions>): Queues {
|
||||||
|
return new Queues(config.map(queueConfig => new Bull.Queue(formatQueueName(queueConfig, name), baseQueueOptions(queueConfig, queueOptions, name))));
|
||||||
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
],
|
],
|
||||||
|
|
|
@ -42,7 +42,7 @@ import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMu
|
||||||
import { CleanProcessorService } from './processors/CleanProcessorService.js';
|
import { CleanProcessorService } from './processors/CleanProcessorService.js';
|
||||||
import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js';
|
import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js';
|
||||||
import { QueueLoggerService } from './QueueLoggerService.js';
|
import { QueueLoggerService } from './QueueLoggerService.js';
|
||||||
import { QUEUE, baseWorkerOptions } from './const.js';
|
import { QUEUE, baseWorkerOptions, formatQueueName } from './const.js';
|
||||||
|
|
||||||
// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019
|
// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019
|
||||||
function httpRelatedBackoff(attemptsMade: number) {
|
function httpRelatedBackoff(attemptsMade: number) {
|
||||||
|
@ -208,7 +208,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
//#region deliver
|
//#region deliver
|
||||||
this.deliverQueueWorkers = this.config.redisForDeliverQueues
|
this.deliverQueueWorkers = this.config.redisForDeliverQueues
|
||||||
.filter((_, index) => process.env.QUEUE_WORKER_INDEX == null || index === Number.parseInt(process.env.QUEUE_WORKER_INDEX, 10))
|
.filter((_, index) => process.env.QUEUE_WORKER_INDEX == null || index === Number.parseInt(process.env.QUEUE_WORKER_INDEX, 10))
|
||||||
.map(config => new Bull.Worker(QUEUE.DELIVER, (job) => this.deliverProcessorService.process(job), {
|
.map(config => new Bull.Worker(formatQueueName(config, QUEUE.DELIVER), (job) => this.deliverProcessorService.process(job), {
|
||||||
...baseWorkerOptions(config, this.config.bullmqWorkerOptions, QUEUE.DELIVER),
|
...baseWorkerOptions(config, this.config.bullmqWorkerOptions, QUEUE.DELIVER),
|
||||||
autorun: false,
|
autorun: false,
|
||||||
concurrency: this.config.deliverJobConcurrency ?? 128,
|
concurrency: this.config.deliverJobConcurrency ?? 128,
|
||||||
|
@ -236,7 +236,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
//#region inbox
|
//#region inbox
|
||||||
this.inboxQueueWorkers = this.config.redisForInboxQueues
|
this.inboxQueueWorkers = this.config.redisForInboxQueues
|
||||||
.filter((_, index) => process.env.QUEUE_WORKER_INDEX == null || index === Number.parseInt(process.env.QUEUE_WORKER_INDEX, 10))
|
.filter((_, index) => process.env.QUEUE_WORKER_INDEX == null || index === Number.parseInt(process.env.QUEUE_WORKER_INDEX, 10))
|
||||||
.map(config => new Bull.Worker(QUEUE.INBOX, (job) => this.inboxProcessorService.process(job), {
|
.map(config => new Bull.Worker(formatQueueName(config, QUEUE.INBOX), (job) => this.inboxProcessorService.process(job), {
|
||||||
...baseWorkerOptions(config, this.config.bullmqWorkerOptions, QUEUE.INBOX),
|
...baseWorkerOptions(config, this.config.bullmqWorkerOptions, QUEUE.INBOX),
|
||||||
autorun: false,
|
autorun: false,
|
||||||
concurrency: this.config.inboxJobConcurrency ?? 16,
|
concurrency: this.config.inboxJobConcurrency ?? 16,
|
||||||
|
@ -288,7 +288,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
//#region relationship
|
//#region relationship
|
||||||
this.relationshipQueueWorkers = this.config.redisForRelationshipQueues
|
this.relationshipQueueWorkers = this.config.redisForRelationshipQueues
|
||||||
.filter((_, index) => process.env.QUEUE_WORKER_INDEX == null || index === Number.parseInt(process.env.QUEUE_WORKER_INDEX, 10))
|
.filter((_, index) => process.env.QUEUE_WORKER_INDEX == null || index === Number.parseInt(process.env.QUEUE_WORKER_INDEX, 10))
|
||||||
.map(config => new Bull.Worker(QUEUE.RELATIONSHIP, (job) => {
|
.map(config => new Bull.Worker(formatQueueName(config, QUEUE.RELATIONSHIP), (job) => {
|
||||||
switch (job.name) {
|
switch (job.name) {
|
||||||
case 'follow': return this.relationshipProcessorService.processFollow(job);
|
case 'follow': return this.relationshipProcessorService.processFollow(job);
|
||||||
case 'unfollow': return this.relationshipProcessorService.processUnfollow(job);
|
case 'unfollow': return this.relationshipProcessorService.processUnfollow(job);
|
||||||
|
|
|
@ -18,7 +18,12 @@ export const QUEUE = {
|
||||||
WEBHOOK_DELIVER: 'webhookDeliver',
|
WEBHOOK_DELIVER: 'webhookDeliver',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function formatQueueName(config: RedisOptionsSource, queueName: typeof QUEUE[keyof typeof QUEUE]): string {
|
||||||
|
return typeof config.queueNameSuffix === 'string' ? `${queueName}-${config.queueNameSuffix}` : queueName;
|
||||||
|
}
|
||||||
|
|
||||||
export function baseQueueOptions(config: RedisOptions & RedisOptionsSource, queueOptions: Partial<Bull.QueueOptions>, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions {
|
export function baseQueueOptions(config: RedisOptions & RedisOptionsSource, queueOptions: Partial<Bull.QueueOptions>, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions {
|
||||||
|
const name = formatQueueName(config, queueName);
|
||||||
return {
|
return {
|
||||||
...queueOptions,
|
...queueOptions,
|
||||||
connection: {
|
connection: {
|
||||||
|
@ -33,11 +38,12 @@ export function baseQueueOptions(config: RedisOptions & RedisOptionsSource, queu
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
prefix: config.prefix ? `${config.prefix}:queue:${queueName}` : `queue:${queueName}`,
|
prefix: config.prefix ? `{${config.prefix}:queue:${name}}` : `{queue:${name}}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function baseWorkerOptions(config: RedisOptions & RedisOptionsSource, workerOptions: Partial<Bull.WorkerOptions>, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.WorkerOptions {
|
export function baseWorkerOptions(config: RedisOptions & RedisOptionsSource, workerOptions: Partial<Bull.WorkerOptions>, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.WorkerOptions {
|
||||||
|
const name = formatQueueName(config, queueName);
|
||||||
return {
|
return {
|
||||||
...workerOptions,
|
...workerOptions,
|
||||||
connection: {
|
connection: {
|
||||||
|
@ -52,6 +58,6 @@ export function baseWorkerOptions(config: RedisOptions & RedisOptionsSource, wor
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
prefix: config.prefix ? `${config.prefix}:queue:${queueName}` : `queue:${queueName}`,
|
prefix: config.prefix ? `{${config.prefix}:queue:${name}}` : `{queue:${name}}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,13 +245,13 @@ export class ClientServerService {
|
||||||
queues: [
|
queues: [
|
||||||
this.systemQueue,
|
this.systemQueue,
|
||||||
this.endedPollNotificationQueue,
|
this.endedPollNotificationQueue,
|
||||||
|
...this.deliverQueue.queues,
|
||||||
|
...this.inboxQueue.queues,
|
||||||
this.dbQueue,
|
this.dbQueue,
|
||||||
|
...this.relationshipQueue.queues,
|
||||||
this.objectStorageQueue,
|
this.objectStorageQueue,
|
||||||
this.webhookDeliverQueue,
|
this.webhookDeliverQueue,
|
||||||
].map(q => new BullMQAdapter(q))
|
].map(q => new BullMQAdapter(q)),
|
||||||
.concat(this.deliverQueue.queues.map((q, index) => new BullMQAdapter(q, { prefix: `${index}-` })))
|
|
||||||
.concat(this.inboxQueue.queues.map((q, index) => new BullMQAdapter(q, { prefix: `${index}-` })))
|
|
||||||
.concat(this.relationshipQueue.queues.map((q, index) => new BullMQAdapter(q, { prefix: `${index}-` }))),
|
|
||||||
serverAdapter,
|
serverAdapter,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
DFLY_version_check: false
|
DFLY_version_check: false
|
||||||
DFLY_tcp_backlog: 2048
|
DFLY_tcp_backlog: 2048
|
||||||
DFLY_default_lua_flags: allow-undeclared-keys
|
DFLY_lock_on_hashtags: true
|
||||||
DFLY_pipeline_squash: 0
|
DFLY_pipeline_squash: 0
|
||||||
DFLY_multi_exec_squash: false
|
DFLY_multi_exec_squash: false
|
||||||
DFLY_conn_io_threads: 4
|
DFLY_conn_io_threads: 4
|
||||||
|
|
Loading…
Reference in a new issue