ภาษีการทำ Handshake

การเชื่อมต่อ Magento ของคุณอาจจะช้าลงเนื่องจากต้นทุนเครือข่ายที่ซ่อนอยู่

ผมเคยรันการส่งออกสินค้า (product export) ที่ต้องเรียกใช้งาน pricing API สินค้าชิ้นเดียวทำงานได้เร็วมาก แต่พอส่งออกทั้งแคตตาล็อกกลับใช้เวลานานมาก ฐานข้อมูลของผมว่างงาน (idle) แต่ profiler แสดงให้เห็นว่าปัญหาอยู่ที่เครือข่าย

โค้ดมีการสร้าง HTTP client ใหม่ขึ้นมาภายใน loop

ก่อนที่คุณจะส่งข้อมูลผ่าน HTTPS เครื่องของคุณต้องทำงานหนัก มันต้องทำ TCP handshake เพื่อเปิด socket จากนั้นก็ต้องทำ TLS handshake เพื่อแลกเปลี่ยนใบรับรอง (certificates) และเจรจาตกลงเรื่องคีย์ (negotiate keys) ซึ่งต้องใช้การรับส่งข้อมูลหลายรอบ (round trips)

ถ้าคุณทำแบบนี้เพียงครั้งเดียว ต้นทุนก็ต่ำ แต่ถ้าคุณทำแบบนี้ภายใน loop ของสินค้า 40,000 ชิ้น คุณต้องจ่ายต้นทุนนั้นถึง 40,000 ครั้ง ข้อมูลจริงนั้นมีขนาดเล็ก แต่ขั้นตอนการตั้งค่า (setup) ต่างหากที่เป็นส่วนที่สิ้นเปลือง

ใน PHP มักจะให้ความรู้สึกว่าคุณควรสร้าง client ขึ้นมาแล้วก็ทิ้งไป ซึ่งวิธีนี้ใช้ได้ดีสำหรับการเรียกเว็บเพียงครั้งเดียว (single web request) แต่จะล้มเหลวในกระบวนการที่ทำงานต่อเนื่องยาวนาน (long-running processes)

หลีกเลี่ยงรูปแบบนี้ใน cron jobs, console commands หรือ message queue consumers:

โค้ดนี้จะเปิดการเชื่อมต่อใหม่และทำ handshake เต็มรูปแบบสำหรับสินค้าทุกๆ ชิ้น

Guzzle จะรักษาการเชื่อมต่อให้คงอยู่ (keep connections alive) หากคุณใช้ client instance เดียวกัน ให้ย้าย client ออกมานอก loop:

  • $client = new \GuzzleHttp\Client(['base_uri' => 'https://api.example.com']);
  • foreach ($products as $product) {
  • $client->post('/sync', [...]);
  • }

ตอนนี้ socket และ TLS session จะยังคงเปิดอยู่ คุณทำ handshake เพียงครั้งเดียวแล้วส่งข้อมูลที่เหลือแบบ stream ได้เลย ใน Magento ให้ทำการ inject client ที่ตั้งค่าไว้แล้วผ่าน constructor แทนที่จะสร้างมันขึ้นมาเองด้วยมือ

การไม่ทำเช่นนี้ไม่ได้ส่งผลแค่เรื่องความหน่วง (latency) เท่านั้น แต่คุณอาจจะประสบปัญหา outbound ports หมดได้ด้วย การเชื่อมต่อที่ปิดไปแล้วจะสะสมอยู่ในสถานะ TIME_WAIT เร็วกว่าที่ OS จะเรียกคืนมาได้ ส่งผลให้บริการของคุณไม่สามารถเปิด socket ใหม่ได้อีกเลย

ตรวจสอบโค้ดของคุณเพื่อหาข้อผิดพลาดนี้ ลองรันคำสั่งนี้ใน terminal ของคุณ:

grep -rn "new .*Client(" app/code | grep -i http

มองหาการสร้าง client ใหม่ที่อยู่ภายใน loop ให้ย้าย client ออกมานอก loop นี่คือการเปลี่ยนแปลงเพียงบรรทัดเดียวที่ช่วยเพิ่มความเร็วได้อย่างมหาศาลสำหรับการซิงค์ข้อมูลขนาดใหญ่

Source: https://dev.to/iamrobindhiman/the-handshake-tax-reuse-your-http-client-in-magento-integrations-3kk7