Nuxt.js + JavaScript로 익스포넨셜 백 오프 구현

익스포넨셜 백오프란?



알고리즘 중 하나입니다.
직역하면 「지수함수적 후퇴」로, 이른바 리트라이 처리의 간격을 지수함수적으로 증가시키는 방식입니다.

재시도 간격 예: 1초, 2초, 4초, 8초...

AWS에서 오류 재시도 및 익스포넨셜 백오프

사용 사례



주로 네트워크 오류에 대한 재시도 방법으로 사용됩니다.
일시적인 부하의 에러에 관해서는 리트라이로 성공할 가능성이 높습니다만, 일반적인 「n초 후에 리트라이」를 실시하는 방식이라고 n초마다 같은 양의 부하가 계속 걸리는 것이 우려됩니다 .
익스포넨셜 백오프 방식을 사용하여 지수적으로 리트라이 간격을 증가시킴으로써 효율적으로 부하 분산을 수행할 수 있습니다.

할 일


  • 재시도 버튼을 누를 때마다 지수 함수로 재시도 처리까지의 간격을 증가시킵니다.

    주제



    Nuxt.js + Vuetify를 사용하여 만들어갑니다.

    프로젝트 만들기



    yarn create nuxt-app에서 바삭바삭하게 만듭니다.

    Nuxt.js 설치
    yarn create nuxt-app exponential-backoff-sample
    yarn create v1.22.4
    [1/4] Resolving packages...
    warning create-nuxt-app > sao > micromatch > snapdragon > source-map-resolve > [email protected]: https://github.com/lydell/resolve-url#deprecated
    warning create-nuxt-app > sao > micromatch > snapdragon > source-map-resolve > [email protected]: Please see https://github.com/lydell/urix#deprecated
    [2/4] Fetching packages...
    [3/4] Linking dependencies...
    [4/4] Building fresh packages...
    success Installed "[email protected]" with binaries:
          - create-nuxt-app
    
    create-nuxt-app v2.15.0
    ✨  Generating Nuxt.js project in exponential-backoff-sample
    ? Project name exponential-backoff-sample
    ? Project description My praiseworthy Nuxt.js project
    ? Author name author
    ? Choose programming language JavaScript     
    ? Choose the package manager Yarn     
    ? Choose UI framework Vuetify.js
    ? Choose custom server framework None (Recommended)
    ? Choose Nuxt.js modules (Press <space> to select, <a> to toggle all, <i> to invert selection)
    ? Choose linting tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
    ? Choose test framework None
    ? Choose rendering mode Universal (SSR)
    ? Choose development tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
    
    �  Successfully created project exponential-backoff-sample
    
      To get started:
    
            cd exponential-backoff-sample
            yarn dev
    
      To build & start for production:
    
            cd exponential-backoff-sample
            yarn build
            yarn start
    

    구현



    pages/index.vue
    
    <template>
      <v-layout column justify-center align-center>
        <v-flex xs12 sm8 md6>
          <div class="text-center">
            <logo />
            <vuetify-logo />
          </div>
          <v-card>
            <v-card-title class="headline">
              exponential-backoff-sample
            </v-card-title>
            <v-card-text>
              正:{{ judgeBaseNum }}<br />
              ランダム数字{{ judgeNum }}<br /><br />
              最大リトライ回数:{{ maxRetryNum }}<br />
              リトライ回数:{{ retryNum }}<br />
              リトライ間隔:{{ retryInterval }}
            </v-card-text>
            <v-card-actions>
              <v-spacer />
              <v-btn color="primary" @click="retry">
                Retry
              </v-btn>
            </v-card-actions>
          </v-card>
        </v-flex>
      </v-layout>
    </template>
    <script>
    import Logo from "~/components/Logo.vue";
    import VuetifyLogo from "~/components/VuetifyLogo.vue";
    
    export default {
      data() {
        return {
          retryNum: 0,
          retryInterval: 100,
          judgeBaseNum: 1,
          judgeNum: 0,
          maxRetryNum: 5
        };
      },
      components: {
        Logo,
        VuetifyLogo
      },
      methods: {
        // メイン処理
        async retry() {
          // 進捗リセット
          this.retryNum = 0;
          this.retryInterval = 100;
          while (this.retryNum < this.maxRetryNum) {
            this.retryNum++;
            this.judge();
            if (this.judgeNum === this.judgeBaseNum) {
              break;
            }
            // スリープ処理
            this.retryInterval = this.retryNum * 100 + this.retryInterval;
            await this.sleep(this.retryInterval);
          }
        },
        // ランダム数字生成
        judge() {
          const random = Math.ceil(Math.random() * 6);
          this.judgeNum = random;
        },
        // スリープ
        sleep(milliseconds) {
          return new Promise(resolve => setTimeout(resolve, milliseconds));
        }
      }
    };
    </script>
    

    재시도 처리



    중요한 것은 이 부분입니다.
    // スリープ処理
    this.retryInterval = this.retryNum * 100 + this.retryInterval;
    await this.sleep(this.retryInterval);
    

    재시도 간격을 재시도 횟수 * 재시도 간격 기준값을 현재의 재시도 간격에 더합니다.
    이 부분이 익스포넨셜 백 오프라고 불리는 방식입니다.

    보충입니다만, 슬립 처리는 이하를 참고로 했습니다.

    자바 스크립트로 루프 중에 잠을 자고 싶습니다. 그것도 읽기 쉬운 코드로 - Qiita

    동작 확인



    동작 확인해 봅시다.
    yarn dev
    yarn run v1.22.4
    $ nuxt
    
       ╭─────────────────────────────────────────────╮
       │                                             │
       │   Nuxt.js v2.12.2                           │
       │   Running in development mode (universal)   │
       │                                             │
       │   Listening on: http://localhost:3000/      │
       │                                             │
       ╰─────────────────────────────────────────────╯
    
    i Preparing project for development
    i Initial build may take a while
    √ Builder initialized
    √ Nuxt files generated
    
    √ Client
      Compiled successfully in 10.40s
    
    √ Server
      Compiled successfully in 9.19s
    
    i Waiting for file changes
    i Memory usage: 348 MB (RSS: 443 MB)
    i Listening on: http://localhost:3000/
    

    http://localhost:3000/ 로 이동합니다.



    RETRY 버튼을 클릭해 봅니다.
    랜덤 숫자의 표시가 전환되고, 랜덤 숫자가 1이 되거나 리트라이 횟수가 5회가 될 때까지 리트라이 처리가 계속됩니다.
    이 때, 재시도 간격의 표시가 증가하는 것과, 실제로 재시도되기까지의 간격이 증가하는 것을 확인할 수 있습니다.

    결론



    JavaScript에서 익스포넨셜 백오프 방식을 구현해 보았습니다.
    AWS는 물론 다양한 API 호출 등에서 범용적으로 필요한 개념이 됩니다.
    여러가지 실현 방식을 자신 안에서 확립해 두고 싶네요.
  • 좋은 웹페이지 즐겨찾기