تعتبر مكتبة Fasthttp بديلاً سريعًا لـ net / http من حزم Golang القياسية.
كيف يتم ترتيبها؟ لماذا هي سريعة جدا؟
أود أن ألفت انتباهكم إلى نسخة من تقرير ألكساندر فاليكالين Fasthttp العملاء الداخلية.
يمكن استخدام أنماط Fasthttp لتسريع تطبيقاتك ورمزك.
من يهتم ، مرحبا بكم في القط.
أنا ألكساندر فاليكالين. أنا أعمل في VertaMedia. لقد وضعت fasthttp لاحتياجاتنا. ويشمل تنفيذ عميل http وخادم http. Fasthttp أسرع بكثير من net / http من حزم Go القياسية.

Fasthttp هو تنفيذ سريع لخادم HTTP والعميل. تقع fasthttp على github.com

أعتقد أن الكثير قد سمعوا عن خادم fasthttp ، إنه سريع جدًا. لكن القليل منهم سمع عن عميل fasthttp. يشارك خادم Fasthttp في المعيار من techempower - المعيار الشهير في دوائر ضيقة لخوادم HTTP. خادم Fasthttp يشارك في الجولات 12 و 13. لم تخرج الجولة 13 بعد (في عام 2016 - تقريبًا).

نتائج أحد اختبارات الجولة 12 ، حيث يكون fasthttp في القمة تقريبًا. توضح الأرقام عدد الاستفسارات التي يقدمها في الثانية في هذا الاختبار. في هذا الاختبار ، تم تقديم طلب لصفحة تُرجع عالم الترحيب. على مرحبا العالم fasthttp سريع جدا.

النتائج الأولية للجولة التالية ، والتي لم يتم إصدارها بعد (في عام 2016 - تقريبا. إد.). 4 من تطبيقات fasthttp تأخذ المراكز الأولى في المؤشر ، وهو الأمر الذي لا يعطيه عالم hello فحسب ، بل يزحف أيضًا إلى قاعدة البيانات ويشكل صفحة html استنادًا إلى القالب.

قلة قليلة من الناس يعرفون عن عميل fasthttp. ولكن في الواقع هو أيضا بارد. سأخبرك في هذا التقرير عن عميل fasthttp للجهاز الداخلي ولماذا تم تطويره.

يوجد بالفعل العديد من العملاء في fasthttp: Client و HostClient و PipelineClient. كذلك سوف أخبركم أكثر عن كل منهم.

Fasthttp.Client هو عميل HTTP للأغراض العامة العادية. مع ذلك ، يمكنك تقديم طلبات إلى أي موقع على الإنترنت ، وتلقي الإجابات. ميزاته: إنه يعمل بسرعة ، ويمكن أن يحد من عدد الاتصالات المفتوحة لكل مضيف ، على عكس حزمة net / http. الوثائق موجودة على https://godoc.org/github.com/valyala/fasthttp#Client .

Fasthttp.HostClient هو عميل متخصص للتواصل مع خادم واحد فقط. عادة ما يتم استخدامه للوصول إلى HTTP API: REST API ، JSON API. يمكن استخدامه أيضًا لنقل بيانات الوكيل من الإنترنت إلى مركز بيانات داخلي على خوادم متعددة. الوثائق هنا: https://godoc.org/github.com/valyala/fasthttp#HostClient .
مثل Fasthttp.Client ، يمكن لـ Fasthttp.HostClient تحديد عدد الاتصالات المفتوحة لكل من خوادم Backend. هذه الوظيفة غائبة في net / http ، وكذلك هذه الميزة غائبة في nginx مجانا. هذه الوظيفة هي فقط في nginx مدفوعة ، بقدر ما أعرف.

Fasthttp.PipelineClient هو عميل متخصص يسمح لك بإدارة طلبات خطوط الأنابيب إلى خادم أو إلى عدد محدود من الخوادم. يمكن استخدامه للوصول إلى API ، عبر بروتوكول HTTP ، حيث تحتاج إلى تنفيذ الكثير من الطلبات وبأسرع وقت ممكن. الحد من Fasthttp.PipelineClient هو أنه يمكن أن يعاني من حظر Head of Line. هذا عندما نرسل الكثير من الطلبات إلى الخادم ولا ننتظر إجابة على كل طلب. تم حظر الخادم في أحد هذه الطلبات. لهذا السبب ، سوف تنتظر جميع الطلبات الأخرى التي تبعته حتى يقوم هذا الخادم بمعالجة طلب بطيء. يجب استخدام Fasthttp.PipelineClient فقط إذا كنت متأكدًا من أن الخادم سيرد على الفور على طلباتك. الوثائق

الآن سأبدأ الحديث عن التنفيذ الداخلي لكل من هؤلاء العملاء. سأبدأ مع Fasthttp.HostClient ، نظرًا لأن جميع العملاء الآخرين تقريبا مبنيون على أساسه.

هذا هو أبسط تطبيق لعميل HTTP في كود زائف على الذهاب. نحن متصلون ، نحصل على استجابة http على عنوان URL هذا. نحن نتصل بهذا المضيف. نحصل على اتصال. في هذا الرمز ، بحيث تكون أقل من وحدة التخزين ، تكون كل عمليات التحقق من الخطأ مفقودة. في الواقع ، هذا ليس كذلك. يجب عليك دائما التحقق من الأخطاء. إنشاء اتصال. اتصال وثيق مع تأجيل. نرسل طلب لهذا الاتصال عن طريق URL. نتلقى الجواب ، نعود هذه الإجابة. ما الخطأ في تنفيذ عميل HTTP هذا؟

المشكلة الأولى هي أنه في هذا التطبيق ، يتم تأسيس اتصال لكل طلب. هذا التطبيق لا يدعم HTTP KeepAlive. كيفية حل هذه المشكلة؟ يمكنك استخدام "تجمع الاتصال" لكل خادم. لا يمكنك استخدام "تجمع الاتصالات" لجميع الخوادم ، لأن الطلب التالي ليس واضحًا أي خادم لإرساله إلى. يجب أن يكون لكل خادم تجمع اتصال خاص به. ونحن نستخدم HTTP KeepAlive. هذا يعني أن "رأس الاتصال" لا يحتاج إلى تحديد "إغلاق الاتصال". في HTTP / 1.1 ، بشكل افتراضي ، يوجد دعم HTTP KeepAlive ويجب إزالة اتصال إغلاق من الرأس. هنا هو التنفيذ في رمز العميل الزائف بدعم اتصال تجمع. هناك مجموعة من تجمعات اتصال متعددة لكل مضيف. تقوم الدالة الأولى ، connPoolForHost ، بإرجاع "تجمع الاتصال" لمضيف معين من URL محدد. ثم نحصل على الاتصال من "تجمع الاتصال" هذا ، نخطط لاستخدام "Defer" لإرسال هذا الاتصال مرة أخرى إلى "التجمع" ، وإرسال طلب KeepAlive لهذا الاتصال ، وإرجاع استجابة. بعد الاستجابة ، يتم تنفيذ Defer ويعود الاتصال إلى Pool. وبالتالي ، نقوم بتمكين دعم HTTP KeepAlive ويبدأ كل شيء في العمل بشكل أسرع. لأننا لا نضيع الوقت في إنشاء اتصال لكل طلب.
لكن الحل لديه أيضا مشاكل. إذا نظرت إلى توقيع الوظيفة ، يمكنك أن ترى أنها تُرجع كائن استجابة لكل طلب. هذا يعني أنك تحتاج إلى تخصيص ذاكرة لهذا الكائن في كل مرة ، وتهيئتها وإعادتها. هذا سيء للأداء. قد يكون الأمر سيئًا إذا كان لديك الكثير من هذه المكالمات للحصول على وظائف.

لذلك ، يمكن حل هذه المشكلة حيث يتم حلها في Fasthttp عن طريق وضع كائن المؤشر على كائن الاستجابة في معلمات هذه الوظيفة. بهذه الطريقة ، يمكن لرمز الاتصال إعادة استخدام كائن الاستجابة هذا عدة مرات. على الشريحة هو تنفيذ هذه الفكرة. نقوم بتمرير مرجع إلى كائن الاستجابة إلى الدالة Get - وتقوم الدالة بملء هذه الاستجابة. السطر الأخير يملأ هذا الكائن.

إليك كيفية ظهورها في الكود. دالة تقبل قناة تم تمريرها بقائمة عناوين url المراد استطلاعها. سننظم دورة على هذه القناة. نقوم بإنشاء كائن استجابة مرة واحدة وإعادة استخدامه في حلقة. استدعاء Get ، تمرير مؤشر إلى الكائن ، معالجة هذه الاستجابة. بعد أن نقوم بمعالجته ، نقوم بإعادة تعيينه إلى حالته الأصلية. وبهذه الطريقة نتجنب تخصيص الذاكرة وتسريع التعليمات البرمجية لدينا.

المشكلة الثالثة هي اتصال وثيق. اتصال وثيق - رأس HTTP ، والتي يمكن العثور عليها في كل من الطلب والاستجابة. إذا حصلنا على مثل هذا العنوان ، فيجب إغلاق هذا الاتصال. لذلك ، في تنفيذ العميل ، لا بد من توفير اتصال وثيق. إذا قمت بإرسال طلب مع إغلاق الرأس ، فقمت بإغلاق هذا الاتصال بعد تلقي الرد. إذا قمت بإرسال طلب دون إغلاق الاتصال ، وقمت بإرجاع استجابة مع إغلاق الاتصال ، فأنت بحاجة أيضًا إلى إغلاق هذا الاتصال بعد تلقي استجابة.

هنا هو رمز الزائفة لهذا التطبيق. بعد تلقي استجابة ، نتحقق من تثبيت رؤوس إغلاق الاتصال هناك. إذا كانت مثبتة ، فقم فقط بإغلاق الاتصال. إذا لم يكن مثبتًا ، فارجع الاتصال مرة أخرى إلى التجمع. إذا لم يتم ذلك ، فإذا أغلق الخادم الاتصال بعد أن قام بإرجاع الإجابات ، فسيحتوي تجمع الاتصال الخاص بك على الاتصال المعطّل الذي أغلقه الخادم ، وستحاول كتابة شيء فيه وستصادفك أخطاء.

المشكلة الرابعة التي يتعرض لها عملاء HTTP هي الخوادم البطيئة أو الشبكة البطيئة الخاملة. قد تتوقف الخوادم عن الاستجابة لطلباتك لأسباب متعددة. على سبيل المثال ، الخادم معطل أو الشبكة بين العميل والخادم قد توقفت عن العمل. وبسبب هذا ، سيتم حظر جميع goroutines التي تستدعي وظيفة Get التي تم وصفها مسبقًا ، في انتظار استجابة من الخادم إلى أجل غير مسمى. على سبيل المثال ، إذا قمت بتطبيق بروكسي http يقبل اتصالًا واردًا واستدعت الدالة Get في كل اتصال ، فسيتم إنشاء عدد كبير من goroutines وسيتم تعليقها جميعًا في الخادم الخاص بك حتى تعطل الخادم ، حتى تنفد الذاكرة.

كيفية حل هذه المشكلة؟ يوجد مثل هذا القرار الساذج الذي يتبادر إلى الذهن أولاً - ما عليك سوى لف هذا Get in goroutine منفصل. ثم في goroutine اجتياز قناة فارغة ، والتي سيتم إغلاقها بعد تنفيذ Get. بعد بدء هذا goroutine ، انتظر هذه القناة لفترة (مهلة). في هذه الحالة ، إذا مر بعض الوقت ولم يتم تنفيذ Get هذا ، فسيحدث الخروج من هذه الوظيفة بحلول المهلة. إذا تم تنفيذ Get ، فسيتم إغلاق القناة وسيحدث الخروج. لكن هذا القرار خاطئ ، لأنه ينقل المشكلة من رأس مريض إلى رأس سليم. ومع ذلك ، سيتم إنشاء وتعليق goroutines بغض النظر عن المهلة التي تستخدمها. سيكون عدد goroutines الذي تسبب في Get getout محدودًا ، ولكن سيكون هناك عدد غير محدود من goroutines التي سيتم إنشاؤها داخل Get with a timeout.

كيفية حل هذه المشكلة؟ الحل الأول هو الحد من عدد goroutines المحظورة في وظيفة Get. يمكن القيام بذلك باستخدام نمط معروف مثل استخدام قناة مخزنة ذات طول محدود ، والتي ستحسب عدد goroutines التي تنفذ دالة Get. إذا تجاوزت هذه الكمية من goroutine حدًا معينًا - سعة هذه القناة ، فسنخرج إلى الفرع الافتراضي. هذا يعني أن لدينا جميع الشركات التي ينجزها المشغلون ، وفي الفرع الافتراضي ، نحتاج فقط إلى إرجاع خطأ ، أنه لا توجد موارد مجانية. قبل إنشاء goroutine ، نحاول كتابة بعض البنية الفارغة لهذه القناة. إذا لم ينجح ذلك ، فقمنا بتجاوز كمية goroutines. إذا اتضح ، فإننا ننشئ هذا gorutin وبعد تنفيذ Get ، نقرأ قيمة واحدة من هذه القناة. وبالتالي ، نحن نحد من كمية goroutines التي يمكن حظرها في Get.

الحل الثاني ، الذي يكمل الأول ، هو تعيين مهلات على الاتصال بالخادم. سيؤدي هذا إلى إلغاء تأمين وظيفة get إذا لم يستجب الخادم لفترة طويلة أو إذا كانت الشبكة معطلة.
إذا لم تعمل الشبكة في الحل رقم 1 ، فسيتم تعليق كل شيء. بعد أن كتبنا cuncurrency عدد محدود من goroutines التي علقت هنا ، فإن وظيفة getimeout ستُرجع خطأ دائمًا. من أجل أن تبدأ العمل بشكل طبيعي ، تحتاج إلى حل ثانٍ (الحل رقم 2) ، والذي يحدد مهلة للقراءة والكتابة من الاتصال. يساعد هذا في إلغاء تأمين goroutines المحظورة في حالة توقف الشبكة أو الخادم عن العمل.

الحل رقم 1 له سباق بيانات. سيتم احتلال كائن الاستجابة الذي تم تمرير المؤشر منه إذا تم حظر الحصول على. ولكن هذه وظيفة الحصول على مهلة قد مهلة. في هذه الحالة ، ننتهي من هذه الوظيفة ، وستكون الاستجابة معلقة وبعد إعادة كتابة بعض الوقت. وبالتالي ، يتم الحصول على سباق البيانات. نظرًا لأن لدينا استجابة بعد الخروج من الوظيفة ، لا يزال يستخدم في مكان ما في goroutine.
يتم حل المشكلة عن طريق إنشاء نسخة استجابة وتمرير نسخة الاستجابة إلى goroutine. بعد اكتمال Get ، انسخ الرد من هذا الرد إلى ردنا الأصلي ، والذي يتم تمريره هنا. وبالتالي ، يتم حل سباق البيانات. تعيش هذه النسخة من الاستجابة لفترة قصيرة وتعود إلى المجموعة. نعيد استخدام الرد. قد لا يتم احتواء نسخة الاستجابة في التجمع فقط عن طريق المهلة. من خلال المهلة ، هناك فقدان استجابة من التجمع.

هل أحتاج إلى إغلاق الاتصال بعد أن لا يقوم الخادم بإرجاع استجابة خلال مهلة؟ الجواب هو لا. بدلاً من ذلك ، نعم ، إذا كنت تريد عمل نسخة احتياطية للخادم. لأنه عند إرسال طلب إلى الخادم ، انتظر لبعض الوقت ، لا يستجيب الخادم خلال هذا الوقت - لا يتعامل مع الطلبات. على سبيل المثال ، يمكنك إغلاق هذا الاتصال ، لكن هذا لا يعني أن الخادم سيتوقف على الفور عن تنفيذ هذا الطلب. سوف يستمر الخادم في تنفيذه. سيكتشف الخادم أن هذا الطلب لا يحتاج إلى التنفيذ بعد أن يحاول الرد عليك. لقد قمت بإغلاق الاتصال ، وحاولت مرة أخرى إنشاء طلب جديد ، ومرة أخرى انقضت المهلة ، وأغلقت مرة أخرى ، وأنشأت طلبًا جديدًا. سيكون لديك تحميل على زيادة الخادم. نتيجة لذلك ، تعتمد خدمتك على طلباتك. هذه هي DoS على مستوى طلبات http. إذا كان لديك خوادم تعمل ببطء ، ولا تريد نسخها احتياطيًا ، فلن تحتاج إلى إغلاق الاتصال بعد انتهاء مهلة. تحتاج إلى الانتظار بعض الوقت ، وترك الاتصال للتكفير عن هذا الخادم. دعه يحاول أن يعطيك إجابة. في غضون ذلك ، استخدم اتصالات مجانية أخرى. كل ما قيل قبل ذلك هو كل مراحل تنفيذ Fasthttp.Client والمشاكل التي حدثت أثناء تنفيذ Fasthttp.Client. يتم حل هذه المشكلات في Fasthttp.HostClient.
لدينا الآن عميل سريع؟ ليس حقا تحتاج إلى معرفة كيفية تنفيذ "تجمع الاتصال".

يبدو التنفيذ الساذج لـ Connection Pool هكذا. هناك نوع من عنوان الخادم حيث تحتاج إلى تثبيت الاتصال. توجد قائمة بالاتصالات المجانية وقفل لمزامنة الوصول إلى هذه القائمة.

هنا هي وظيفة للحصول على اتصال من تجمع الاتصال. نحن نبحث في قائمة من مجموعتنا. إذا كان هناك شيء ما ، فسنحصل على اتصال مجاني ونعيده. إذا لم يكن هناك شيء ، فقم بإنشاء اتصال جديد بهذا الخادم وإعادته. ما هو الخطأ هنا؟
إرجاع الدالة connPool.Put اتصال مجاني.
في حساب المهلة. في Fasthttp.Client ، يمكنك تحديد الحد الأقصى لعمر الاتصال المفتوح غير المستخدم. بعد مرور هذا الوقت ، يتم إغلاق الاتصالات غير المستخدمة تلقائيًا ويتم إخراجها من هذا التجمع.
تصبح الاتصالات القديمة غير مستخدمة مع مرور الوقت ويتم إغلاقها تلقائيًا وإزالتها من البلياردو.
عندما يتم أخذ اتصال من التجمع ، وتبين أن خادمه مغلق ، وحاولت كتابة شيء هناك ، يتم إجراء محاولة ثانية - يتم الحصول على اتصال جديد ويحاول إرسال طلبات لهذا الاتصال مرة أخرى. ولكن هذا لا يحدث إلا إذا كان هذا الطلب غير نشط - أي طلب يمكن تنفيذه عدة مرات دون آثار جانبية على الخادم - هل هو طلب GET أو HEAD. على سبيل المثال ، في الشبكة / http القياسية فقط أضفنا التحقق من الاتصالات المغلقة. هناك قاموا بإجراء فحص أكثر صعوبة. يقومون بالتحقق ، عند محاولة إرسال طلب جديد إلى الاتصال من التجمع ، إذا تم إرسال بايت واحد على الأقل إلى هذا الاتصال على الإطلاق. إذا انطلقت ، ثم إرجاع خطأ. إذا لم تغادر ، فنحن نأخذ اتصالًا جديدًا من pool.

ما هو الخطأ في حمام السباحة؟ حجمها غير محدود. نفس التنفيذ كما في صافي / HTTP. إذا قمت بكتابة عميل ينقسم من ملايين goroutines إلى خادم بطيء ، فسيحاول العميل إنشاء مليون اتصال بهذا الخادم. لا يوجد حد أقصى لعدد الاتصالات في حزمة net / http القياسية. بالنسبة للعميل المستخدم للوصول إلى واجهة برمجة التطبيقات (API) عبر HTTP ، يُنصح بتحديد حجم تجمع الاتصال هذا. خلاف ذلك ، قد ينخفض عملائك ، لأنك ستستخدم جميع الموارد: المواضيع ، المواضيع ، الاتصال ، goroutines والذاكرة. أيضًا ، يمكن أن يؤدي ذلك إلى DoS للخوادم الخاصة بك ، حيث سيتم إنشاء الكثير من الاتصال بها ، والتي إما غير مستخدمة أو غير فعالة ، لأن الخادم لا يمكنه إجراء الكثير من الاتصال.

تجمع اتصال الحد. الرمز غير موجود هنا ، لأنه كبير جدًا بحيث لا يمكن احتواؤه على شريحة واحدة. يمكن للمهتمين رؤية تنفيذ هذه الوظيفة على github.com.

المشكلة الثانية. الكثير من الطلبات تأتي إلى العميل في وقت ما. وبعد ذلك هناك تراجع والعودة إلى العدد السابق من الطلبات. على سبيل المثال ، وصل 10000 طلب في وقت واحد ، ثم عاد عدد الطلبات إلى 1000 لكل وحدة زمنية. بعد ذلك ، سينمو تجمع الاتصال إلى 10000 اتصال. هذه الاتصالات سوف يتعطل هناك إلى ما لا نهاية. كانت هذه المشكلة في عميل net / http القياسي قبل الإصدار 1.7. لذلك ، تحتاج إلى حل هذه المشكلة.

يتم حل هذه المشكلة عن طريق الحد من حياة اتصال غير مستخدم. إذا لم يتم إرسال طلب واحد عبر الاتصال لبعض الوقت ، فسيتم إغلاقه ببساطة ويتم طرحه خارج حمام السباحة. لا يوجد تطبيق لأنه كبير جدًا.

لدينا عميل يعمل بسرعة وباردة؟ ليس حقا مثل ذلك. لا يزال لدينا وظيفة إنشاء اتصال - dialHost.

دعونا ننظر في تنفيذه. تطبيق ساذج يبدو مثل هذا. يتم نقل العنوان الذي تريد الاتصال به ببساطة. نحن نسمي وظيفة صافي القياسية. تعيد الاتصال. ما هو الخطأ في هذا التنفيذ؟

بشكل افتراضي ، net.Dial يجعل طلب DNS لكل مكالمة. قد يؤدي ذلك إلى زيادة استخدام موارد نظام DNS الفرعي الخاص بك. إذا اتصل عملاء API بخوادم لا تدعم اتصالات KeepAlive ، فإنهم يغلقون الاتصالات. أنت مدعوم من KeepAlive ، والخوادم ليست كذلك. بعد هذه الاستجابة ، يغلق الخادم الاتصال. اتضح أن net.Dial يسمى على كل طلب. هناك حوالي 10 آلاف مثل هذه الطلبات في الثانية الواحدة. لديك 10 آلاف مرة في الثانية يذهب حل في نظام أسماء النطاقات. هذا يحمّل نظام DNS الفرعي.

كيفية حل هذه المشكلة؟ قم بإنشاء ذاكرة تخزين مؤقت تقوم بتعيين مضيفها في IP لفترة قصيرة مباشرة في رمز Go الخاص بك ، ولا تستدعي تحليل أسماء النطاقات على كل net.Dial. الاتصال بعناوين IP الجاهزة.

المشكلة الثانية هي التحميل غير المتكافئ على الخادم إذا كان لديك عدة خوادم مخفية وراء اسم المجال. على سبيل المثال ، مثل Round Robin DNS. إذا قمت بتخزين عنوان IP واحد مؤقتًا في DNS لفترة من الوقت ، فستذهب جميع طلباتك خلال هذا الوقت إلى خادم واحد. على الرغم من أنه قد يكون لديك العديد منهم هناك. من الضروري حل هذه المشكلة. يتم حلها عن طريق تعداد جميع عناوين IP المتاحة التي كانت مخبأة وراء اسم مجال معين. يتم ذلك أيضًا في Fasthttp.Client.

المشكلة الثالثة هي أن net.Dial يمكن أن يتعطل إلى أجل غير مسمى بسبب مشاكل في الشبكة أو الخادم الذي تحاول الاتصال به. في هذه الحالة ، سيتم تعليق goroutines الخاص بك على وظيفة Get. هذا يمكن أن يؤدي أيضا إلى زيادة استخدام الموارد.
الحل هو إضافة مهلة. Dial package net. , , . , , , .

. Get Dial . - . Dial , , . , , . DialTimeout. , .

HostClient .
HostClient , . LoadBalance.
HostClient . , HostClient . connection . . .
Fauly host .
— . Dial. , Dial. Get, , - . , . , , .
— . Get , . , , , .
Error , Round Robin .
SSL , Golang . .

fasthttp.Client. HostClient, fasthttp.Client HostClient.

Get. HostClient . HostClient . HostClient Get. HostClient.

HostClient - , URL. web-crawling ( ), . HostClient . net/http, . , HostClient, . fasthttp.

Client HostClient, PipelineClient . PipelineClient connection pool. PipelineClient connection, . PipelineClient connection. connection pool. PipelineClient connection .

PipelineClient connection . PipelineConnClient.writer — connection, . PipelineConnClient.reader — connection , PipelineConnClient.writer. PipelineConnClient.reader , Get.

PipelineClient.Get PipelineClient. pipelineWork url, , response, channel done, response.
Get. C . channel, PipelineConnClient.writer connection. channel w.done, PipelineConnClient.reader, response request.

net/http fasthttp.Client 2 .

, , fasthttp. , , . fasthttp. , fasthttp, . allocation . .

net/http. , allocation net/nttp. .

: PipelineClient connection?
: — pending , . . request, pending , Error.
: API , fasthttp, net/http?
: . net/http . . string -, string . , net/http, . - , . fasthttp , . . net/http fasthttp , net/http POST-, response, () . fasthttp , request response . 10 request 10 response . , . fasthttp 10 request 10 response? . — . , net/http. . , net/http — .
PS .
.
— .