ホームページ バックエンド開発 Golang Go アプリをターボチャージ: TCP 経由での超高速の静的ファイルの提供をマスターする

Go アプリをターボチャージ: TCP 経由での超高速の静的ファイルの提供をマスターする

Sep 09, 2024 am 06:34 AM

ホリネズミさんたち?!

Go で TCP を使用して静的ファイルをより高速に提供するための最良の方法を考えたことはありますか?単純なファイル サービス タスクでジョブを実行する http.ServeFile などの組み込み関数がありますが、これらの関数は、非常に大きなファイルの場合や、かなりの負荷の下で実行される場合に障害となります。この記事では、一般的な Go 開発レベルを超えたい人に喜んでもらえるように、このプロセスの高度な問題領域に取り組みたいと考えています。

問題

トラフィックが多い場合にはファイルの処理速度が特に重要となるため、特に注意を払う必要があります。 http.ServeFile などのソリューションを通じて静的コンテンツを提供する場合、次のような解決すべき問題があります。

  • 1 層のバッファリング: データは最初にメモリにロードされ、その後ネットワーク経由で送信されるため、不必要なメモリ フットプリントと遅延が生じます。

  • I/O のブロック: ファイルに対してブロック操作を実行すると、特にファイルが数メガバイトの場合、速度に悪影響を及ぼす可能性があります。

  • 負荷バランスが悪い: ファイル転送をより並行して実行するための機能がありません。これは、速度が失われることを意味します。

新しいソリューション: さらなる最適化

これらの制約を回避してパフォーマンスを向上させる方法は次のとおりです。

ゼロコピーのファイル転送

syscall パッケージの sendfile システム コールを使用してゼロコピー ファイル転送を実行することで、メモリ消費を削減し、転送速度を向上させます。ユーザー空間のメモリは関与せず、データはファイル記述子からソケットに直接「送信」されます。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

import (

    "syscall"

    "net"

    "os"

)

 

func serveFile(conn net.Conn, filePath string) error {

    file, err := os.Open(filePath)

    if err != nil {

        return err

    }

    defer file.Close()

 

    fileStat, err := file.Stat()

    if err != nil {

        return err

    }

 

    // Directly transfer file content to the connection socket

    _, err = syscall.Sendfile(int(conn.(*net.TCPConn).File().Fd()), int(file.Fd()), nil, int(fileStat.Size()))

    return err

}

ログイン後にコピー

外部非同期 I/O メカニズムとしてのグルーチン

ファイル転送を非同期部分に分割することで、Go の同時実行フレームワークを利用します。 I/O 呼び出しが完了するまでの待ち時間を短縮するために、ゴルーチンを使用してこれらの部分を並行してオフロードします。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

func asyncServeFile(conn net.Conn, filePath string) error {

    file, err := os.Open(filePath)

    if err != nil {

        return err

    }

    defer file.Close()

 

    buf := make([]byte, 32*1024) // 32KB buffer

    var wg sync.WaitGroup

 

    for {

        n, err := file.Read(buf)

        if n > 0 {

            wg.Add(1)

            go func(data []byte) {

                defer wg.Done()

                conn.Write(data)

            }(buf[:n])

        }

        if err != nil {

            if err == io.EOF {

                break

            }

            return err

        }

    }

 

    wg.Wait()

    return nil

}

ログイン後にコピー

重要なセクションに焦点を当てる

ファイルのすべてのセクションの価値が同等であるとは限りません。たとえば、再生を開始できるビデオ ファイルにはビデオ メタデータが必要な場合があります。ユーザー インターフェイス内の体感速度を高めるために、そのようなセクションに焦点を当ててください。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

func serveCriticalSections(conn net.Conn, filePath string, criticalSections []fileRange) error {

    file, err := os.Open(filePath)

    if err != nil {

        return err

    }

    defer file.Close()

 

    for _, section := range criticalSections {

        buf := make([]byte, section.length)

        _, err := file.ReadAt(buf, section.offset)

        if err != nil {

            return err

        }

        conn.Write(buf)

    }

 

    return nil

}

ログイン後にコピー

結論

Go での TCP 経由の静的ファイル転送の処理を最適化するには、単に組み込み機能を利用するだけではありません。アプリケーションのパフォーマンスの向上は、ファイルのゼロコピー転送、非同期ファイル I/O、ファイルの重要なセグメントの管理を利用することで実現できます。これらの方法により、ユーザーの満足度を損なうことなく、高トラフィックと巨大ファイルの処理が可能になります。

これでコーディングは楽しく終わりました。次回ファイルを転送するときに問題が発生しないことを願っています。そして常にそれを倒すことを忘れないでください

Turbocharge Your Go App: Mastering Blazing-Fast Static File Serving Over TCP

以上がGo アプリをターボチャージ: TCP 経由での超高速の静的ファイルの提供をマスターするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットな記事タグ

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Go Language Packのインポート:アンダースコアとアンダースコアなしの違いは何ですか? Go Language Packのインポート:アンダースコアとアンダースコアなしの違いは何ですか? Mar 03, 2025 pm 05:17 PM

Go Language Packのインポート:アンダースコアとアンダースコアなしの違いは何ですか?

GOでテスト用のモックオブジェクトとスタブを書くにはどうすればよいですか? GOでテスト用のモックオブジェクトとスタブを書くにはどうすればよいですか? Mar 10, 2025 pm 05:38 PM

GOでテスト用のモックオブジェクトとスタブを書くにはどうすればよいですか?

Beegoフレームワークのページ間で短期情報転送を実装する方法は? Beegoフレームワークのページ間で短期情報転送を実装する方法は? Mar 03, 2025 pm 05:22 PM

Beegoフレームワークのページ間で短期情報転送を実装する方法は?

トレースツールを使用して、GOアプリケーションの実行フローを理解するにはどうすればよいですか? トレースツールを使用して、GOアプリケーションの実行フローを理解するにはどうすればよいですか? Mar 10, 2025 pm 05:36 PM

トレースツールを使用して、GOアプリケーションの実行フローを理解するにはどうすればよいですか?

GOのジェネリックのカスタムタイプ制約を定義するにはどうすればよいですか? GOのジェネリックのカスタムタイプ制約を定義するにはどうすればよいですか? Mar 10, 2025 pm 03:20 PM

GOのジェネリックのカスタムタイプ制約を定義するにはどうすればよいですか?

Go言語でファイルを便利に書く方法は? Go言語でファイルを便利に書く方法は? Mar 03, 2025 pm 05:15 PM

Go言語でファイルを便利に書く方法は?

MySQLクエリ結果リストをGO言語のカスタム構造スライスに変換する方法は? MySQLクエリ結果リストをGO言語のカスタム構造スライスに変換する方法は? Mar 03, 2025 pm 05:18 PM

MySQLクエリ結果リストをGO言語のカスタム構造スライスに変換する方法は?

Linterと静的分析ツールを使用して、GOコードの品質と保守性を向上させるにはどうすればよいですか? Linterと静的分析ツールを使用して、GOコードの品質と保守性を向上させるにはどうすればよいですか? Mar 10, 2025 pm 05:38 PM

Linterと静的分析ツールを使用して、GOコードの品質と保守性を向上させるにはどうすればよいですか?

See all articles