Koaサービスの電流制限方法例

小云云
小云云オリジナル
2018-05-15 10:47:532010ブラウズ

電流制限の要件は、同時実行数を制限することです。この数を超えた後は、キューにキャッシュする必要があります。この記事では主に Koa サービスの電流制限方法の実践方法を紹介します。これが非常に優れていると思いますので、参考にしてください。編集者をフォローして見てみましょう。皆さんのお役に立てれば幸いです。

最近リクエストを受け取りました。サーバーをセットアップし、リクエストを受信したときに提供されたインターフェイスを呼び出し、結果を返すだけです。このインターフェイスのパフォーマンスの問題のため、同時にリクエストの数は一定の数を超えることができず、サービス内の電流を制限する必要があります。

koa ミドルウェアは next を呼び出しません

本来のアイデアは、koa ミドルウェアでカウントし、6 つ以上の関数がある場合に次の関数をキャッシュすることです。進行中のタスクが終了したら、next を呼び出して他のリクエストを続行します。

その後、koa ミドルウェアでは、次の関数リクエストが実行されないと停止せず、後続のミドルウェアが呼び出されなくなり、コンテンツが直接返されることがわかりました。

const Koa = require('koa');
const app = new Koa();
app.use((ctx, next) => {
 console.log('middleware 1');
 setTimeout(() => {
  next();
 }, 3000);
 ctx.body = 'hello';
});
app.use((ctx, next) => {
 console.log('middleware 2');
});
app.listen(8989);

上記のコードは、まずコンソールに「ミドルウェア 1」を出力します => ブラウザは「hello」を受信します => コンソールは「ミドルウェア 2」を出力します。

ここでもう 1 つ注意すべき点は、リクエストが終了 (終了) した後も、その次のメソッドを呼び出すことができ、後続のミドルウェアは引き続き実行されるということです (ただし、リクエストが返されているため、ctx への変更は有効になりません) )。同様に、クローズ要求 (close) も同様に動作します。

awaitを使ってリクエストを待たせる

次の関数の実行を遅らせても目的は達成できません。次に考えられるのは、現在のリクエストを待つために await を使用することです。 await 関数は Promise を返します。この Promise 内のsolve 関数をキューに格納し、呼び出しを遅延させます。

const Koa = require('koa');
const app = new Koa();
const queue = [];
app.use(async (ctx, next) => {
 setTimeout(() => {
  queue.shift()();
 }, 3000);
 await delay();
 ctx.body = 'hello';
});
function delay() {
 return new Promise((resolve, reject) => {
  queue.push(resolve);
 });
}
app.listen(8989);

上記のコードは、Delay関数でPromiseを返し、そのPromiseのresolve関数がキューに格納されます。リクエストの実行を継続できるように、キュー内の解決関数を 3 秒後に実行するようにタイマーを設定します。

フローはルーティングまたはリクエストに対して制限されていますか?

電流制限の基本原理が実装された後、次の問題は、電流制限コードをどこに記述すべきかということです。基本的に、次の 2 つの立場があります:

インターフェースの電流制限

ニーズにより、電流制限は、要求されたインターフェースの制限されたパフォーマンスによるものです。したがって、このリクエストのフローを個別に制限できます:

async function requestSomeApi() {
 // 如果已经超过了最大并发
 if (counter > maxAllowedRequest) {
  await delay();
 }
 counter++;
 const result = await request('http://some.api');
 counter--;
 queue.shift()();
 return result;
}

以下に便利な再利用可能なバージョンもあります。

async function limitWrapper(func, maxAllowedRequest) {
 const queue = [];
 const counter = 0;
 return async function () {
  if (counter > maxAllowedRequest) {
   await new Promise((resolve, reject) => {
    queue.push(resolve);
   });
  }
  counter++;
  const result = await func();
  counter--;
  queue.shift()();
  return result;
 }
}

ルートの電流制限

この方法は、koa ミドルウェアを作成し、ミドルウェアの電流を制限することです:

async function limiter(ctx, next) => {
 // 如果超过了最大并发数目
 if (counter >= maxAllowedRequest) {
  // 如果当前队列中已经过长
  await new Promise((resolve, reject) => {
   queue.push(resolve);
  });
 }
 store.counter++;
 await next();
 store.counter--;
 queue.shift()();
};

その後、ルーターでこのミドルウェアをさまざまなルートに使用するだけです:

router.use('/api', rateLimiter);

比較

インターフェイスに電流制限を実装しましたが、ロジックが少し複雑だと思ったので、ルーティングの電流制限に切り替えました。すべてが完璧に動作しました。

別のリクエストを受け取るまで、このインターフェイスを 3 回リクエストし、3 つのリクエストの結果配列を返したいと考えていました。ここで問題が発生します。電流が制限されているため、インターフェイスを直接呼び出すことができません。現在の制限はルーティングに基づいているため、リクエスト インターフェイスの関数を直接呼び出すことはできません。それではどうすればいいでしょうか?このルートは自分たちでリクエストしてリクエストするしかありません。 。 。

注意事項

closeイベントをリッスンして、キューからリクエストを削除してください
キューに格納されたリクエストは、ユーザーによってキャンセルされる可能性があります。前述したように、koa でリクエストがキャンセルされても、後続のミドルウェアは実行され続けるため、電流制限が必要なインターフェイスも実行されてしまい、無駄が発生します。

この目的を達成するには、各リクエストをハッシュ値でマークする必要があります:

ctx.res.on('close', () => {
 const index = queue.findIndex(item => item.hash === hash);
 if (index > -1) {
  queue.splice(index, 1);
 }
});

タイムアウトを設定します

ユーザーが長時間待機しないようにするには、 koa では簡単な timeout 実装:

const server = app.listen(config.port);
server.timeout = DEFAULT_TIMEOUT;

現在のキューが長すぎます

現在のキューが長すぎる場合は、キューに参加してもタイムアウトになります。したがって、キューが長すぎる状況にも対処する必要があります:

if (queue.length > maxAllowedRequest) {
 ctx.body = 'error message';
 return;
}

関連する推奨事項:

Java アーキテクトの道 - 電流制限技術とさまざまなプログラミング言語

nginx 電流制限アルゴリズム

Redisを使用して電流制限を行います

以上がKoaサービスの電流制限方法例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。