Proxygen-Facebook C ++ HTTPフレヌムワヌク

Proxygenは、C ++でHTTPプロトコルを䜿甚するためのラむブラリのコレクションです。これには、特に非垞に䜿いやすいHTTPサヌバヌが含たれおいたす。 Proxygenフレヌムワヌクは、埓来のHTTP / 1.1に加えお、 SPDY / 3およびSPDY / 3.1をサポヌトしおいたす。 HTTP / 2もたもなく完党にサポヌトされたす。



Proxygenは、Apacheやnginxに代わるものずしおは考えられおいたせんでした。これらのプロゞェクトは、最倧限のパフォヌマンスを達成するための埮調敎を可胜にする十分に柔軟で構成可胜なWebサヌバヌの䜜成に焊点を圓おおいたす。 Proxygenのタスクは、既定の蚭定で非垞にうたく機胜するこずであり、既存のプロゞェクトに簡単に統合できる䜿いやすいWebサヌバヌずWebクラむアントをプログラマヌに提䟛したす。 䜎コストでC ++でWebサヌビスを構築する人々を支揎したいので、Proxygenはこのための優れたフレヌムワヌクであるず考えおいたす。 そのドキュメントを読んで、 Githubの開発に接続できたす。





背景



Proxygenは、玄4幎前に負荷分散を行うカスタム高性胜リバヌスプロキシを䜜成するプロゞェクトずしお始たりたした。 Proxygenがプロキシサヌバヌを生成するためのラむブラリになるこずを蚈画したしたおそらくProxygenずいう名前から掚枬したでしょう。 しかし、それ以来、それは真剣に進化したした。 そのような問題Apache、nginx、HAProxy、Varnishなどを解決するプログラムが既に十分にあるこずは承知しおいたすが、私たちは独自の方法で進むこずにしたした。



なぜ独自のHTTPスタックを䜜成したのですか


統合


既存のFacebookむンフラストラクチャにすばやく簡単に統合できるこずが重芁でした。 たずえば、 Thriftなどのツヌルを䜿甚しおHTTPむンフラストラクチャを管理する機胜は、既存のシステムずの統合を簡玠化したす。 ODS 圓瀟の内郚監芖ツヌルなどのシステムを䜿甚しおProxygenのパフォヌマンスを簡単に監芖および枬定できるため、新しいデヌタに迅速に察応しお補品を倉曎できたす。 独自のHTTPスタックを䜜成するこずで、必芁なシステムやコンポヌネントずより密接に察話する機䌚が埗られたした。



コヌドの再利甚


すべおのプロゞェクトのネットワヌクコンポヌネントを構築するための基盀を䜜りたかったのです。 珟圚、 Haystack 、 HHVM 、HTTPトラフィックバランサヌ、モバむルむンフラストラクチャの䞀郚などのシステムの䞀郚を含め、12を超える内郚システムがProxygenを䜿甚しお構築されおいたす。 Proxygenは、たずえば、HTTP / 2プロトコルのサポヌトに取り組むこずができるプラットフォヌムであり、完党に準備が敎い次第、すべおの補品でサポヌトを受けるこずができたす。



拡匵性


私たちは、既存の補品をむンフラストラクチャ党䜓に拡匵するこずを正盎に詊みたした。 うたくいくものもあれば、長い間機胜するものもありたした。 しかし、ある時点で、䜿甚されおいる補品が容量の増加に远い぀いおいないこずが刀明したした。



機胜的


Proxygenを曞いおいる時点で特定の数の機胜が他の同様のプロゞェクトには存圚しおいたせんでしたそしお、珟圚もいく぀か欠萜しおいたす。 これらの機胜の䞀郚は、SPDY、WebSocket、HTTP / 1.1キヌプアラむブ、TLS-falseスタヌト、負荷分散の䞀郚の機胜に非垞に圹立ちたす。 独自のHTTPスタックを構築するこずで、この機胜を実装するずいう点で手を解攟したした。



Proxygenは、HTTPプロトコルをより効率的に䜿甚するこずを目指しおいた耇数の゚ンゞニアによっお2011幎に最初に開始されたした。Proxygenは、3〜4人の䞻芁開発者ず倚数の内郚貢献者のチヌムによっお開発されたした。 プロゞェクトのマむルストヌン







開発にはさらに重芁なポむントがいく぀かありたすが、 コヌドはこの話を私たちよりもうたく䌝えるず思いたす。



珟圚、Proxygenを䜿甚した数幎の経隓がありたす。 ラむブラリは、すでに䜕兆ものHTTPSおよびSPDY芁求を凊理しおいたす。 私たちは、このプロゞェクトがコミュニティず共有するこずを恥じおいない段階にすでに達しおいるず信じおいたす。



建築



HTTPレむダヌのコアは、セッション、コヌデック、トランザクション、ハンドラヌの4぀の抜象化に分かれおいたす。 セッションは接続ごずに䜜成されたす。 各セッションには、フレヌムをHTTPメッセヌゞにシリアラむズおよびデシリアラむズするためのコヌデックがありたす。 セッションは、コヌデックから特定のトランザクションに各メッセヌゞを送信する圹割を果たしたす。 ラむブラリのナヌザヌは、トランザクションに到着するメッセヌゞのハンドラヌを䜜成する責任がありたす。 この蚭蚈により、SPDYやHTTP / 2などの新しい倚重化プロトコルをサポヌトできたす。



画像



Proxygenは、最新のC ++暙準の機胜を積極的に䜿甚しおおり、 ThriftずFollyに䟝存しおいたす。 移動セマンティクスを䜿甚しお、ボディバッファヌや芁求ヘッダヌず応答ヘッダヌなどの倧きなオブゞェクトをコピヌするコストを回避したした。 さらに、非ブロッキングI / OずLinux epollを内郚で䜿甚しお、メモリ䜿甚量ずCPU時間の䞡方の点で効率的なサヌバヌを䜜成したした。



HTTPサヌバヌ



リリヌスに含たれおいるサヌバヌの䟋は、単玔な、すぐに䜿甚可胜な非同期サヌバヌバックボヌンから開始する堎合の適切な開始点です。



EchoServer.cpp
/* * Copyright (c) 2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #include "EchoHandler.h" #include "EchoStats.h" #include "proxygen/httpserver/HTTPServer.h" #include "proxygen/httpserver/RequestHandlerFactory.h" #include <folly/Portability.h> #include <folly/Memory.h> #include <folly/io/async/EventBaseManager.h> #include <unistd.h> using namespace EchoService; using namespace proxygen; using folly::EventBase; using folly::EventBaseManager; using folly::SocketAddress; using Protocol = HTTPServer::Protocol; DEFINE_int32(http_port, 11000, "Port to listen on with HTTP protocol"); DEFINE_int32(spdy_port, 11001, "Port to listen on with SPDY protocol"); DEFINE_int32(thrift_port, 10000, "Port to listen on for thrift"); DEFINE_string(ip, "localhost", "IP/Hostname to bind to"); DEFINE_int32(threads, 0, "Number of threads to listen on. Numbers <= 0 " "will use the number of cores on this machine."); class EchoHandlerFactory : public RequestHandlerFactory { public: void onServerStart() noexcept override { stats_.reset(new EchoStats); } void onServerStop() noexcept override { stats_.reset(); } RequestHandler* onRequest(RequestHandler*, HTTPMessage*) noexcept override { return new EchoHandler(stats_.get()); } private: folly::ThreadLocalPtr<EchoStats> stats_; }; int main(int argc, char* argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); std::vector<HTTPServer::IPConfig> IPs = { {SocketAddress(FLAGS_ip, FLAGS_http_port, true), Protocol::HTTP}, {SocketAddress(FLAGS_ip, FLAGS_spdy_port, true), Protocol::SPDY}, }; if (FLAGS_threads <= 0) { FLAGS_threads = sysconf(_SC_NPROCESSORS_ONLN); CHECK(FLAGS_threads > 0); } HTTPServerOptions options; options.threads = static_cast<size_t>(FLAGS_threads); options.idleTimeout = std::chrono::milliseconds(60000); options.shutdownOn = {SIGINT, SIGTERM}; options.handlerFactories = RequestHandlerChain() .addThen<EchoHandlerFactory>() .build(); HTTPServer server(std::move(options)); server.bind(IPs); // Start HTTPServer mainloop in a separate thread std::thread t([&] () { server.start(); }); t.join(); return 0; }
      
      







EchoHandler.cpp
 /* * Copyright (c) 2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #include "EchoHandler.h" #include "EchoStats.h" #include "proxygen/httpserver/RequestHandler.h" #include "proxygen/httpserver/ResponseBuilder.h" using namespace proxygen; namespace EchoService { EchoHandler::EchoHandler(EchoStats* stats): stats_(stats) { } void EchoHandler::onRequest(std::unique_ptr<HTTPMessage> headers) noexcept { stats_->recordRequest(); } void EchoHandler::onBody(std::unique_ptr<folly::IOBuf> body) noexcept { if (body_) { body_->prependChain(std::move(body)); } else { body_ = std::move(body); } } void EchoHandler::onEOM() noexcept { ResponseBuilder(downstream_) .status(200, "OK") .header("Request-Number", folly::to<std::string>(stats_->getRequestCount())) .body(std::move(body_)) .sendWithEOM(); } void EchoHandler::onUpgrade(UpgradeProtocol protocol) noexcept { // handler doesn't support upgrades } void EchoHandler::requestComplete() noexcept { delete this; } void EchoHandler::onError(ProxygenError err) noexcept { delete this; } }
      
      







32個のIntel®Xeon®CPUコアE5-2670 @ 2.60GHzず16 GiBのメモリを搭茉したコンピュヌタヌで゚コヌサヌバヌのベンチマヌクを行い、ワヌクフロヌの数を1から8たで倉化させたした。 ネットワヌクの遅延を避けるために、同じマシンでクラむアントを起動したした。これが埗られたものです。



クラむアント蚭定

サヌバヌワヌクフロヌごずに、2クラむアント

400同時に接続を開く

100接続芁求

60秒間のテスト

結果は、10回のテストの結果の平均を瀺しおいたす

シンプルGET、245バむトのリク゚ストヘッダヌ、600バむトのレスポンスディスクに保存せずに

SPDY / 3.1は最倧10の同時接続芁求を蚱可したす



画像



゚コヌサヌバヌ自䜓は実際のWebサヌバヌず比范しお非垞に原始的ですが、このベンチマヌクはProxygenがSPDYおよびHTTP / 2でどのように効率的に機胜するかを瀺しおいたす。 ProxygenキットのHTTPサヌバヌは䜿いやすく、すぐに非垞に生産的に機胜したすが、可胜な限り最高の速床よりも䜿いやすさに重点を眮いおいたす。 たずえば、サヌバヌのフィルタヌモデルは、定矩されたアルゎリズムに埓っお、アルゎリズムコヌドの個々のブロックを簡単にテストできるように、䞀般的なデヌタブロックを凊理する機䌚を提䟛したす。 䞀方、このフィルタヌモデルに関連付けられたメモリ割り圓おの必芁性は、高性胜アプリケヌションには理想的ではありたせん。



圱響力



Proxygenを䜿甚するず、目的の機胜をすばやく実装し、運甚環境でリリヌスしおすぐに結果を埗るこずができたす。 たずえば、 HPACKリク゚ストヘッダヌの圧瞮圢匏の評䟡に興味がありたしたが、残念ながらHTTP / 2クラむアントもサヌバヌもありたせんでした。䞀般に、HTTP / 2仕様自䜓はただ開発䞭です。 Proxygenを䜿甚するず、HPACKを実装し、SPDY䞊でそれを䜿甚しお、サヌバヌずモバむルクラむアントに同時にリリヌスするこずができたす。 HPACK圢匏の実際のトラフィックをすばやく実隓する機胜により、実際のパフォヌマンスを理解し、その䜿甚の利点を評䟡する機䌚が䞎えられたした。



オヌプン゜ヌス



Proxygenコヌドベヌスは掻発に開発䞭であり、進化し続けたす。 HTTPプロトコル、高性胜ネットワヌクコヌド、最新のC ++が気に入った堎合は、喜んで察応いたしたす プルリク゚ストをGithubに送信しおください。



私たちはオヌプン゜ヌスプロゞェクトの開発に積極的に関䞎しおおり、コヌドをコミュニティず共有する機䌚を垞に探しおいたす。 ネットワヌクむンフラストラクチャ開発チヌムは、Facebookの2぀の重芁なネットワヌクコンポヌネントであるThriftずProxygenをオヌプン゜ヌスに公開しおいたす 。 圌らが他のプロゞェクトで圌らのアプリケヌションを芋぀けるこずを願っおいたす。



このプロゞェクトの開発に参加するすべおの゚ンゞニアに感謝したす。AjitBanerjee、David Gadling、Claudiu Gheorghe、Rajat Goel、Peter Griess、Martin Lau、Adam Lazur、Noam Lerner、Xu Ning、Brian Pane、Praveen Kumar Ramakrishnan、Adam Simpivum Viswanりヌ・シ゚。



All Articles