Keep Alive สำหรับ https ใน golang
ทางหนึ่งในการพัฒนา security คือการ call API ด้วย https protocol แต่ก็จะแลกมาด้วย cost ที่ต้องจ่ายในการทำ SSL handshake
พอลองทำ performance test ดูก็พบว่า perfomance มันไม่ได้ ผลที่ออกมา Transaction Per Second (TPS) มันตกจาก 200 เหลือแค่ 12 พอไล่หาดูก็เจอว่า เพราะ server มันมีคอขวดในการทำ SSL handshake เราเลยตัดสินใจจะ optimize โดยการ keep-alive เพื่อ reuse http connection ที่ทำ SSL handshake มาแล้ว
ข้างล่างเป็นตัวอย่างในการยิง request 2 ครั้งด้วย https ธรรมดา โดยยังไม่ใส่ keep-alives
หลังจากนั้นเราก็ใส่ keep-alive เข้าไป ผลคือ performance แย่เหมือนเดิม…!?
เราก็ reuse transport instance แล้วนะ แล้วก็ enable keep-alives แล้วด้วย แต่ทำไมถึงยังไม่ได้นะ พี่เอ (พี่ในทีม) ก็เดาว่า keep-alives ที่เรา set ไปมันยังไม่ effective เพราะผลได้ 12 TPS เหมือนไม่ได้เปิดเลย พอหาต่อก็เจอว่า ถ้า read ของออกจาก body ไม่หมด หรือว่าลืมปิดมัน มันจะไม่สามารถ reuse ได้ แม้ว่าจะ set keep-alives แล้วก็ตาม เราก็เลยเติม code ที่ ensure ว่า body จะถูก read ทิ้งและปิดแน่นอนเข้าไป
แต่ก็ยังไม่หายเหมือนเดิม…
จนสุดท้าย เจอว่าถ้าเป็น HTTP 1.0 keep-alives จะไม่ปิดโดย default ถ้าอยากเปิด ต้องส่ง header ไปบอก server ด้วย
แล้วพอยิงอีกทีก็สำเร็จ! ได้ 120 TPS (พอๆกับ http ธรรมดาเลย) ถ้าเป็น HTTP 1.1 ขึ้นไปอาจจะไม่ต้องใส่ header เข้าไปก็ได้ เพราะ keep-alives จะเปิดโดย default ถ้าจะปิดค่อยใส่ Connection: close เข้าไปแทน
สรุปคือ 4 สิ่งที่เราทำไปเพื่อให้ keep-alives มัน work ใน context ของเรามีดังนี้:
- reuse transport instance (เอา instance ที่ config ไว้ว่าจะใช้ keep-alives อ่ะนะ)
- อ่านจาก body ให้เกลี้ยง
- อ่านเสร็จก็ปิด body ซะ
- ใส่ header ไปบอก server ด้วยสำหรับ HTTP1.0
โค้ดสุดท้าย (พร้อม history ของมัน) หน้าตาแบบนี้ครับ
จบละครับ หวังว่าจะมีประโยชน์ฮะ
ขอบคุณพี่เอ พี่ยอดที่ทำให้ blog นี้เกิดฮะ วิธีทั้งหลาย ผมไม่ได้หาเลยนะฮะ เป็นค.สามารถพี่เอล้วนๆฮะ ผมเอามาเล่าเป็นสตอรี่อย่างเดียวฮะ