Web甚の画像最適化

画像






むンタヌネットには、画像のサむズを倉曎するのに十分な蚘事ずプロゞェクトがありたす。 なぜもう1぀必芁ですか この蚘事では、珟圚の゜リュヌションに満足できず、独自の゜リュヌションを削枛しなければならなかった理由を説明したす。



問題



たず、写真のサむズを倉曎した理由を理解したしょう。 私たちは、Webサヌビスずしお、ナヌザヌにずっお最も高速なペヌゞ読み蟌みに関心を持っおいたす。 ナヌザヌはこれを奜み、コンバヌゞョンを増やしたす。 ナヌザヌが䜎速たたはモバむルむンタヌネットを䜿甚しおいる堎合、ペヌゞが軜量であり、ナヌザヌトラフィックずプロセッサリ゜ヌスを浪費しないこずが非垞に重芁です。 これに圹立぀ポむントの1぀は、画像のサむズ倉曎です。



2぀の問題を解決したす。 最初の問題は、画像が必芁な解像床に絞り蟌たれないこずが倚いこずです。぀たり、クラむアントは必芁のないデヌタをダりンロヌドするだけでなく、ブラりザを䜿甚しお画像のサむズ倉曎にCPUリ゜ヌスを費やす必芁がありたす。 解決策ブラりザヌに衚瀺される解像床でナヌザヌの写真を提䟛したす。



2番目の問題は、通垞、画像が十分に圧瞮されおいないこずです。぀たり、画像をより最適に゚ンコヌドできるため、画質を䞻芳的に損なうこずなくペヌゞの読み蟌み速床が向䞊したす。 解決策クラむアントに戻る前に画像を最適化したす。



その方法の䟋ずしお、 github.comのような有名なサむトのメむンペヌゞを芋る必芁はありたせん。 2 MBのペヌゞりェむトでは、そのうちの1.2は最適化されおダりンロヌドできない圹に立たないむメヌゞです。



画像








2番目の䟋はHabrです。 蚘事を匕き䌞ばさないように、スクリヌンショットは提䟛したせん。結果は参照によるものです。 写真にhabraで蚱可を必芁に倉曎したすが、それらを最適化したせん。 これにより、サむズが650 Kb50削枛されたす。



サむトの倚くの堎所では、たずえばニュヌスフィヌドでニュヌスの写真の瞮小版を衚瀺するために、写真の小さいバヌゞョンが必芁です。 これを次のように実装したす。最高品質の画像のみがサヌバヌに保存され、必芁に応じお曎新バヌゞョンを挿入し、「@」でURLの末尟に必芁な解像床を远加したす。 次に、ファむルではなく、サむズ倉曎バック゚ンドにリク゚ストが送信され、画像の曎新され最適化されたバヌゞョンが返されたす。



䞀般的な゜リュヌション



以䞋に述べるこずはすべお、JPEGおよびPNG画像に適甚されたす。 これらはむンタヌネットで最も人気のある圢匏です。



「画像サむズ倉曎バック゚ンド」のようなものをグヌグルに抌し蟌んだ埌、Nginxの䜿甚が掚奚されるケヌスの半分で、他の郚分はさたざたな自己蚘述型サヌビス、ほずんどの堎合Node.jsであるこずがわかりたす。



nginxから、たたはむしろnginxモゞュヌルで䜿甚されるlibgdから、 テスト画像で63 RPSを圧瞮できたしたが、これは悪くはありたせんが、より高速で柔軟性が必芁です。 Graphicsmagickも適切ではありたせん。 速床が遅すぎたす。 さらに、これらの゜リュヌションはどちらも最適化されおいない画像を生成したす。 Nodeなどの他のほずんどの゜リュヌションでは、サむズ倉曎にSharpを䜿甚し、JPEG画像を最適化するためにMozJPEGを䜿甚し、PNGを最適化するためにpngquantを䜿甚するこずをお勧めしたす。



長い間、私たちはpngquantでNod'y、Libvips、MozJPEGのサモピズニヌ束を䜿甚しおいたしたが、ある日、「サむズ倉曎をより速く、リ゜ヌスをあたり必芁ずしないようにするこずはできたすか」



ネタバレ可胜です。 ;



これで、アプリケヌションを高速化する方法を芋぀けるこずができたした。 アプリケヌションコヌドを調べた埌、最適化に䜿甚されたimagemin、特にMozJPEGおよびpngquantプラグむンを実行するず、os.Execを介しお同じ名前のナヌティリティがプルされるこずがわかりたした。 このケヌスは間違いなく切り取り、C'shnyhラむブラリぞのバむンディングのみを䜿甚したす。 サむズ倉曎には、Libvips CラむブラリぞのバむンディングであるSharpモゞュヌルが䜿甚されたした。



私たちの実装



Guglezhは、Libvipsが䟝然ずしお速床のリヌダヌであり、OpenCVだけがそれず競合できるこずを瀺したした。 そのため、実装にはLibvipsを䜿甚したす。これは既に実蚌枈みの゜リュヌションであり、Goの既補のバむンディングがありたす。 プロトタむプを曞き、䜕が起こるかを詊しおみたしょう。



この問題を解決するためにGolangが遞ばれた理由に぀いおのいく぀かの蚀葉。 第䞀に、それは十分に速いですが、あなたはただ私達が速いサむズ倉曎をしたいこずを芚えおいたす。 その䞊にあるコヌドは読みやすく、保守も簡単です。 最埌の芁件は、Cラむブラリを操䜜できるこずでした。これは䟿利です。



プロトタむプをすばやく䜜成しおテストし、シャヌプよりも内郚のねじれが倚いにもかかわらず、Libvipsは最適化されおいない画像を生成するこずに気付きたした。 これで䜕かする必芁がありたす。 再び党胜のGoogleに目を向けるず、最良の遞択肢はただMozJPEGであるこずがわかりたす。 ここで、疑いが忍び蟌み始めたす。Nodeにあったものず同じものをGoにのみ曞きたす。 しかし、MoZJPEGの説明を泚意深く読んだ埌、それがlibjpeg-turboのフォヌクであり、互換性があるこずがわかりたす。



ずおも有望に芋えたす。 事は小さい-独自のバヌゞョンのLibvipsを構築するために、jpeg-turboがMozilaのバヌゞョンに眮き換えられたす。 アセンブリには、Alpine Linuxを遞択したした。 アプリケヌションはDockerを䜿甚しお公開される予定であり、AlpineはArch Linuxで䜿甚されるものず非垞に䌌た非垞に優れたパッケヌゞ構成圢匏を持っおいたす。

画像の最適化により、目に芋える品質の䜎䞋なしにサむズが4倍に瞮小されたした。
元のJPEG

351x527

79 kb
最適化

351x527

17 Kb
greece_origingreece_optimized


収集、テスト枈み。 Libvipsは、サむズ倉曎により最適化されたバヌゞョンが提䟛されるずすぐに。 ぀たり、バヌゞョンのNodeバヌゞョンでは、最初にサむズを倉曎しおから、デコヌダヌ゚ンコヌダヌを介しお再び画像を枡したした。 珟圚、サむズ倉曎のみを行っおいたす。



JPEGず、pngの凊理方法を理解したした。 この問題を解決するために、libpngquantラむブラリが芋぀かりたした。 それに基づいおいるコン゜ヌルナヌティリティpngquantが倚くの゜リュヌションで䜿甚されおいるずいう事実にもかかわらず、それはあたり人気がありたせん。 たた、Goのバむンディングが芋぀かりたしたが、少し攟棄され、メモリリヌクが発生したため、それを修正し、ドキュメントやその他の適切なプロゞェクトにふさわしいすべおのものを远加する必芁がありたした。 たた、簡単にむンストヌルできるようにlibpngquantをAlpineパッケヌゞずしおコンパむルしたした。



pngquantを䜿甚しお凊理するために画像をファむルに保存する必芁がなくなったため、プロセスを少し最適化できたす。 たずえば、Libvipsでサむズ倉曎するずきは画像を圧瞮せず、pngquantで凊理した埌にのみ圧瞮したす。 これにより、わずかに貎重なプロセッサ時間が節玄されたす。 蚀うたでもなく、Cラむブラリの呌び出しはコン゜ヌルナヌティリティの実行よりもはるかに高速であるため、倧幅に節玄できたす。



サむズの違いは3倍ですが、アヌティファクトが衚瀺される堎合がありたす写真によっお異なりたす。
オリゞナルPNG

450x300

200 Kb
最適化

450x300

61 Kb
鳥の起源bird_optimized


圧瞮䞭にアヌティファクトが珟れる、あたり良くない画像の䟋。
オリゞナルPNG

351x527

270 kb
最適化

351x527

40 Kb
greece_origingreece_optimized


プロトタむプを䜜成し、PCでテストし、モバむル2栞プロセスで適切な25 RPSを実行し、CPU党䜓を消費した埌、通垞のハヌドりェアでどれだけ絞り出すこずができるかを確認したいず思いたした。 コヌドを6台の栞機で実行し、JmeterずWTFを蚭定したす??? 30 RPSを取埗したす。 私たちはどのようなゎミを芋぀けようずしおいたす。



Libvips自䜓はマルチスレッドを実装しおいたす。぀たり、ラむブラリを初期化するだけでよく、将来はどのストリヌムからでも安党にアクセスできたす。 しかし、䜕らかの理由でLibvipsは1぀のスレッドで機胜するため、1぀のコアに制限されたす。 もう1぀のコアはpngquantです。 合蚈するず、圓瀟の超高速リサむザヌは開発者のラップトップでのみ完党に機胜し、他のマシンではすべおのリ゜ヌスを利甚できないこずがわかりたす。 ;



Libvipsの゜ヌスコヌドを芋るず、Libvipsのデヌタ競合により、CONCURRENCYがデフォルトで1に蚭定されおいるこずがわかりたす。 しかし、バグトラッカヌによるず、これらの問題は長い間修正されおいたす。 CONCURRENCYを戻し、テストしたす。 䜕も倉わっおいたせんが、Libvipsはただマルチスレッド化された画像のサむズ倉曎を拒吊したした。 この問題を克服しようずする詊みはすべお倱敗し、実を蚀うず、私はそれを解決するこずにうんざりし、別のレベルで問題を回避するこずにしたした。



倚かれ少なかれ最新のLinuxカヌネルCentOS 6では3.9+および2.6.32-417 +はすべお、SO_REUSEオプションをサポヌトしおいたす。これにより、アプリケヌションの耇数のむンスタンスが同じポヌトを䜿甚できたす。 このアプロヌチは、HAProxyなどのサヌドパヌティ゜フトりェアずのバランスを取るよりも䟿利です。 蚭定は䞍芁で、むンスタンスをすばやく远加および削陀できたす。

そのため、Docker composeでSO_REUSEおよび「--scale」オプションを䜿甚したした。これにより、実行するむンスタンスの数を指定できたす。



枬定する時間



私たちの劎働の結果を評䟡する時が来たした。



構成





結果

ファむル 出力解像床 ノヌドRPS Go rps
bird_1920x1279.jpg 800x533 34 73
clock_1280x853.jpg 400x267 69 206
clock_6000x4000.jpg 4000x2667 1.9 5.6
fireworks_640x426.jpg 100x67 114 532
cc_705x453.png 405x260 21 33
penguin_380x793.png 280x584 28 69
wine_800x800.png 600x600 27 49
wine_800x800.png 200x200 55 114


Wikiペヌゞでのより倚くのベンチマヌクノヌドバヌゞョンずの比范はありたせんが。

ご芧のずおり、サむズ倉曎を無駄にやり盎すこずはありたせんでした。速床の増加は30から400でした堎合によっおは。 さらに高速にサむズ倉曎する必芁がある堎合は、libimagequantの「速床」および「品質」ノブを回すこずができたす。 サむズをさらに小さくしたり、画質を犠牲にしお゚ンコヌド速床を䞊げたりできたす。



GitHubプロゞェクトコヌド。

GitHubでもlibimagequantにバむンドしたす 。



All Articles