การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel

ในระบบนิเวศ PHP ปัจจุบันมีตัวเชื่อมต่อสองตัวสำหรับการทำงานกับเซิร์ฟเวอร์ Tarantool - นี่คือส่วนขยาย PECL อย่างเป็นทางการ tarantool/tarantool-php.iniเขียนด้วยภาษา C และ tarantool-php/client.php?เขียนด้วย PHP ฉันเป็นผู้เขียนเรื่องหลัง

ในบทความนี้ ฉันต้องการแบ่งปันผลการทดสอบประสิทธิภาพของไลบรารีทั้งสอง และแสดงให้เห็นว่า ด้วยการเปลี่ยนแปลงโค้ดเพียงเล็กน้อย คุณสามารถเพิ่มประสิทธิภาพได้ 3-5 เท่า (ในการทดสอบสังเคราะห์!).

เราจะทดสอบอะไร

เราจะทดสอบสิ่งที่กล่าวมาข้างต้น ซิงโครนัส ตัวเชื่อมต่อที่ทำงานแบบอะซิงโครนัส แบบขนาน และแบบอะซิงโครนัสแบบขนาน 🙂 เราไม่ต้องการแตะรหัสของตัวเชื่อมต่อด้วย ขณะนี้มีส่วนขยายหลายรายการเพื่อให้บรรลุสิ่งที่คุณต้องการ:

  • สวูล ― เฟรมเวิร์กอะซิงโครนัสประสิทธิภาพสูงสำหรับ PHP ใช้โดยยักษ์ใหญ่อินเทอร์เน็ตเช่นอาลีบาบาและไป่ตู้ ตั้งแต่เวอร์ชัน 4.1.0 วิธีการเวทย์มนตร์ได้ปรากฏขึ้น SwooleRuntime::เปิดใช้งาน Coroutine()ซึ่งช่วยให้คุณ "แปลงไลบรารีเครือข่าย PHP แบบซิงโครนัสไปเป็นไลบรารีอะซิงโครนัสด้วยโค้ดหนึ่งบรรทัด"
  • จนกระทั่งเมื่อไม่นานมานี้ Async ถือเป็นส่วนขยายที่มีแนวโน้มมากสำหรับงานอะซิงโครนัสใน PHP ทำไมจนกระทั่งเมื่อเร็ว ๆ นี้? น่าเสียดาย ด้วยเหตุผลที่ฉันไม่ทราบ ผู้เขียนได้ลบพื้นที่เก็บข้อมูลออกไปและชะตากรรมในอนาคตของโครงการก็ไม่ชัดเจน ฉันจะต้องใช้มัน หนึ่ง จากส้อม เช่นเดียวกับ Swoole ส่วนขยายนี้ช่วยให้คุณสามารถเปิดกางเกงของคุณได้อย่างง่ายดายเพียงสะบัดข้อมือเพื่อเปิดใช้งานอะซิงโครนัสโดยแทนที่การใช้งานมาตรฐานของสตรีม TCP และ TLS ด้วยเวอร์ชันอะซิงโครนัส ทำได้ผ่านตัวเลือก “async.tcp = 1"
  • Parallel - ส่วนขยายที่ค่อนข้างใหม่จาก Joe Watkins ผู้โด่งดัง ผู้เขียนไลบรารีเช่น phpdbg, apcu, pthreads, pcov, uopz ส่วนขยายนี้จัดเตรียม API สำหรับมัลติเธรดใน PHP และอยู่ในตำแหน่งที่จะมาแทนที่ pthreads ข้อจำกัดที่สำคัญของไลบรารีคือใช้งานได้กับ PHP เวอร์ชัน ZTS (Zend Thread Safe) เท่านั้น

เราจะทดสอบอย่างไร?

มาเปิดใช้อินสแตนซ์ Tarantool โดยปิดใช้งานการบันทึกการเขียนล่วงหน้า (wal_mode = ไม่มี) และบัฟเฟอร์เครือข่ายที่เพิ่มขึ้น (อ่านล่วงหน้า = 1 * 1024 * 1024). ตัวเลือกแรกจะยกเลิกการทำงานกับดิสก์ ตัวเลือกที่สองจะทำให้สามารถอ่านคำขอเพิ่มเติมจากบัฟเฟอร์ระบบปฏิบัติการได้ และลดจำนวนการเรียกของระบบ

สำหรับการวัดประสิทธิภาพที่ทำงานกับข้อมูล (การแทรก การลบ การอ่าน ฯลฯ) ก่อนที่จะเริ่มการวัดประสิทธิภาพ พื้นที่ memtx จะถูกสร้างขึ้น (ใหม่) ซึ่งค่าดัชนีหลักจะถูกสร้างขึ้นโดยตัวสร้างค่าจำนวนเต็มเรียงลำดับ ​​(ลำดับ)
พื้นที่ DDL มีลักษณะดังนี้:

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

หากจำเป็น ก่อนที่จะรันการวัดประสิทธิภาพ พื้นที่จะเต็มไปด้วย 10,000 สิ่งอันดับของแบบฟอร์ม

{id, "tuplе_<id>"}

สิ่งอันดับเข้าถึงได้โดยใช้ค่าคีย์แบบสุ่ม

เกณฑ์มาตรฐานนั้นเป็นคำขอเดียวที่ส่งไปยังเซิร์ฟเวอร์ ซึ่งดำเนินการ 10,000 ครั้ง (รอบ) ซึ่งในทางกลับกัน จะดำเนินการในการวนซ้ำ การวนซ้ำจะทำซ้ำจนกระทั่งการเบี่ยงเบนของเวลาทั้งหมดระหว่างการวนซ้ำ 5 ครั้งอยู่ภายในข้อผิดพลาดที่ยอมรับได้ 3%* หลังจากนั้นจะใช้ผลลัพธ์โดยเฉลี่ย มีการหยุดชั่วคราว 1 วินาทีระหว่างการวนซ้ำเพื่อป้องกันไม่ให้โปรเซสเซอร์ควบคุมปริมาณ ตัวรวบรวมขยะของ Lua ถูกปิดใช้งานก่อนการวนซ้ำแต่ละครั้ง และถูกบังคับให้เริ่มต้นหลังจากเสร็จสิ้น กระบวนการ PHP เปิดตัวเฉพาะกับส่วนขยายที่จำเป็นสำหรับการวัดประสิทธิภาพ โดยเปิดใช้งานการบัฟเฟอร์เอาต์พุตและตัวรวบรวมขยะถูกปิดใช้งาน

* จำนวนรอบ การวนซ้ำ และเกณฑ์ข้อผิดพลาดสามารถเปลี่ยนแปลงได้ในการตั้งค่าเกณฑ์มาตรฐาน

สภาพแวดล้อมการทดสอบ

ผลลัพธ์ที่เผยแพร่ด้านล่างจัดทำขึ้นบน MacBookPro (2015) ระบบปฏิบัติการ - Fedora 30 (เคอร์เนลเวอร์ชัน 5.3.8-200.fc30.x86_64) Tarantool เปิดตัวในนักเทียบท่าพร้อมพารามิเตอร์ "--network host".

รุ่นแพ็คเกจ:

Tarantool: 2.3.0-115-g5ba5ed37e
นักเทียบท่า: 19.03.3 สร้าง a872fc2f86
PHP: 7.3.11 (cli) (สร้าง: 22 ต.ค. 2019 08:11:04)
tarantool/ไคลเอนต์: 0.6.0
รีบากิต/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ แพตช์สำหรับ 7.3)*
msgpack ต่อ: 2.0.3
ต่ออะซิงก์: 0.3.0-8c1da46
ext-swoole: 4.4.12
ต่อขนาน: 1.1.3

* ขออภัย ตัวเชื่อมต่ออย่างเป็นทางการใช้ไม่ได้กับ PHP เวอร์ชัน > 7.2 ในการคอมไพล์และรันส่วนขยายบน PHP 7.3 ฉันต้องใช้ ปะ.

ผลการวิจัย

โหมดซิงโครนัส

โปรโตคอล Tarantool ใช้รูปแบบไบนารี MessagePack เพื่อทำให้ข้อความเป็นอนุกรม ในตัวเชื่อมต่อ PECL การทำให้เป็นอนุกรมจะถูกซ่อนลึกในส่วนลึกของไลบรารี และส่งผลต่อกระบวนการเข้ารหัสจากโค้ด userland ดูเหมือนจะเป็นไปไม่ได้. ในทางกลับกัน ตัวเชื่อมต่อ PHP ล้วนๆ ให้ความสามารถในการปรับแต่งกระบวนการเข้ารหัสโดยการขยายตัวเข้ารหัสมาตรฐานหรือโดยการใช้งานของคุณเอง มีตัวเข้ารหัสสองตัวให้เลือกใช้งานในกล่อง โดยตัวหนึ่งเป็นแบบพื้นฐาน msgpack/msgpack-php.php (ส่วนขยาย MessagePack PECL อย่างเป็นทางการ) ส่วนอีกอันเปิดอยู่ รีบากิต/msgpack (ใน PHP ล้วนๆ)

ก่อนที่จะเปรียบเทียบตัวเชื่อมต่อ เราจะวัดประสิทธิภาพของตัวเข้ารหัส MessagePack สำหรับตัวเชื่อมต่อ PHP และในการทดสอบเพิ่มเติม เราจะใช้อันที่แสดงผลลัพธ์ที่ดีที่สุด:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
แม้ว่าเวอร์ชัน PHP (Pure) จะด้อยกว่าส่วนขยาย PECL ในเรื่องความเร็ว แต่ในโครงการจริง ฉันยังคงแนะนำให้ใช้มัน รีบากิต/msgpackเนื่องจากในส่วนขยาย MessagePack อย่างเป็นทางการ ข้อกำหนดรูปแบบมีการใช้งานเพียงบางส่วนเท่านั้น (เช่น ไม่มีการรองรับประเภทข้อมูลที่กำหนดเอง โดยที่คุณไม่สามารถใช้ Decimal ซึ่งเป็นประเภทข้อมูลใหม่ที่นำมาใช้ใน Tarantool 2.3) และมี จำนวนอื่น ๆ ปัญหา (รวมถึงปัญหาความเข้ากันได้กับ PHP 7.4) โดยทั่วไปแล้วโครงการนี้ดูถูกทอดทิ้ง

เรามาวัดประสิทธิภาพของตัวเชื่อมต่อในโหมดซิงโครนัสกันดีกว่า:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
ดังที่เห็นได้จากกราฟ ตัวเชื่อมต่อ PECL (Tarantool) แสดงประสิทธิภาพที่ดีกว่าเมื่อเปรียบเทียบกับตัวเชื่อมต่อ PHP (ไคลเอนต์) แต่นี่ก็ไม่น่าแปลกใจ เนื่องจากอย่างหลังนอกเหนือจากการใช้งานในภาษาที่ช้ากว่าแล้ว จริงๆ แล้วยังทำงานได้มากกว่าอีกด้วย: มีการสร้างออบเจ็กต์ใหม่ทุกครั้งที่เรียก ขอร้อง и คำตอบ (ในกรณีเลือก - ด้วย เกณฑ์และในกรณีของ Update/Upsert ― การดำเนินการ) แยกเอนทิตี การเชื่อมต่อ, เครื่องบรรจุหีบห่อ и ผู้ดำเนินการ พวกเขายังเพิ่มค่าใช้จ่ายด้วย แน่นอนว่าความยืดหยุ่นต้องแลกมาด้วยราคา อย่างไรก็ตามโดยทั่วไปล่าม PHP แสดงประสิทธิภาพที่ดีแม้ว่าจะมีความแตกต่าง แต่ก็ไม่มีนัยสำคัญและอาจจะน้อยกว่านี้เมื่อใช้การโหลดล่วงหน้าใน PHP 7.4 ไม่ต้องพูดถึง JIT ใน PHP 8

เดินหน้าต่อไป Tarantool 2.0 เพิ่มการรองรับสำหรับ SQL มาลองดำเนินการเลือก แทรก อัปเดต และลบโดยใช้โปรโตคอล SQL และเปรียบเทียบผลลัพธ์กับ noSQL (ไบนารี) ที่เทียบเท่า:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
ผลลัพธ์ของ SQL ไม่ได้น่าประทับใจมากนัก (ฉันขอเตือนคุณว่าเรากำลังทดสอบโหมดซิงโครนัสอยู่) อย่างไรก็ตาม ฉันจะไม่เสียใจกับเรื่องนี้ล่วงหน้า การสนับสนุน SQL ยังอยู่ระหว่างการพัฒนา (เช่น เมื่อเร็วๆ นี้ มีการเพิ่มการสนับสนุน แถลงการณ์ที่เตรียมไว้) และตัดสินจากรายการ ปัญหากลไก SQL จะได้รับการเพิ่มประสิทธิภาพหลายประการในอนาคต

อะซิงโครนัส

ตอนนี้เรามาดูกันว่าส่วนขยาย Async สามารถช่วยให้เราปรับปรุงผลลัพธ์ข้างต้นได้อย่างไร ในการเขียนโปรแกรมแบบอะซิงโครนัส ส่วนขยายจะมี API ที่ใช้ Coroutines ซึ่งเราจะใช้ เราพบว่าจำนวนโครูทีนที่เหมาะสมที่สุดสำหรับสภาพแวดล้อมของเราคือ 25:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
“กระจาย” การดำเนินการ 10,000 ครั้งไปยัง 25 โครูทีน และดูว่าเกิดอะไรขึ้น:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
จำนวนการดำเนินการต่อวินาทีเพิ่มขึ้นมากกว่า 3 เท่า tarantool-php/client.php?!

น่าเศร้าที่ตัวเชื่อมต่อ PECL ไม่ได้เริ่มต้นด้วย ext-async

แล้ว SQL ล่ะ?

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
อย่างที่คุณเห็น ในโหมดอะซิงโครนัส ความแตกต่างระหว่างโปรโตคอลไบนารี่และ SQL อยู่ภายในขอบเขตของข้อผิดพลาด

สวูล

เราค้นหาจำนวนคอร์รูทีนที่เหมาะสมที่สุดอีกครั้ง คราวนี้สำหรับ Swoole:
การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
หยุดที่ 25 ทำซ้ำเคล็ดลับเดียวกันกับส่วนขยาย Async - กระจาย 10,000 การดำเนินการระหว่าง 25 coroutines นอกจากนี้ เราจะเพิ่มการทดสอบอีกครั้งโดยแบ่งงานทั้งหมดออกเป็น 2 กระบวนการ (นั่นคือ แต่ละกระบวนการจะดำเนินการ 5,000 ครั้งใน 25 โครูทีน) กระบวนการจะถูกสร้างขึ้นโดยใช้ SwooleProcess.

ผล:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
Swole แสดงผลลัพธ์ที่ต่ำกว่าเล็กน้อยเมื่อเทียบกับ Async เมื่อรันในกระบวนการเดียว แต่ด้วย 2 โพรเซส รูปภาพจึงเปลี่ยนไปอย่างมาก (หมายเลข 2 ไม่ได้ถูกเลือกโดยบังเอิญ บนเครื่องของฉัน มันคือ 2 โพรเซสที่แสดงผลลัพธ์ที่ดีที่สุด)

อย่างไรก็ตามส่วนขยาย Async ยังมี API สำหรับการทำงานกับกระบวนการต่างๆ แต่ฉันไม่ได้สังเกตเห็นความแตกต่างใด ๆ จากการรันการวัดประสิทธิภาพในกระบวนการหนึ่งกระบวนการขึ้นไป (อาจเป็นไปได้ว่าฉันทำผิดพลาดที่ไหนสักแห่ง)

SQL กับโปรโตคอลไบนารี:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
เช่นเดียวกับ Async ความแตกต่างระหว่างการดำเนินการไบนารีและ SQL จะถูกตัดออกในโหมดอะซิงโครนัส

Parallel

เนื่องจากส่วนขยายแบบขนานไม่ได้เกี่ยวกับโครูทีน แต่เกี่ยวกับเธรด เราจึงมาวัดจำนวนเธรดแบบขนานที่เหมาะสมที่สุดกัน:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
มันคือ 16 ในเครื่องของฉัน มารันการวัดประสิทธิภาพตัวเชื่อมต่อบน 16 เธรดแบบขนานกัน:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
อย่างที่คุณเห็น ผลลัพธ์นั้นดีกว่าส่วนขยายแบบอะซิงโครนัสด้วยซ้ำ (ไม่นับ Swoole ที่ทำงานบน 2 กระบวนการ) โปรดทราบว่าสำหรับตัวเชื่อมต่อ PECL การดำเนินการ Update และ Upsert จะว่างเปล่า นี่เป็นเพราะความจริงที่ว่าการดำเนินการเหล่านี้ล้มเหลวโดยมีข้อผิดพลาด - ฉันไม่รู้ว่ามันเป็นความผิดของ ext-parallel, ext-tarantool หรือทั้งสองอย่าง

ตอนนี้เรามาเปรียบเทียบประสิทธิภาพของ SQL:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel
สังเกตเห็นความคล้ายคลึงกับกราฟของตัวเชื่อมต่อที่ทำงานพร้อมกันหรือไม่

ด้วยกัน

และสุดท้าย เราจะสรุปผลลัพธ์ทั้งหมดในกราฟเดียวเพื่อดูภาพรวมของส่วนขยายที่ทดสอบ มาเพิ่มการทดสอบใหม่หนึ่งรายการลงในแผนภูมิซึ่งเรายังไม่ได้ทำ - มารัน Async coroutines แบบขนานโดยใช้ Parallel* กัน แนวคิดในการรวมส่วนขยายข้างต้นเข้าด้วยกันแล้ว ถูกกล่าวถึง ผู้เขียนแต่ยังไม่มีความเห็นพ้องต้องกัน คุณจะต้องดำเนินการด้วยตนเอง

* ไม่สามารถเปิดใช้ Swoole coroutines ด้วย Parallel ได้ ดูเหมือนว่าส่วนขยายเหล่านี้เข้ากันไม่ได้

ดังนั้นผลลัพธ์สุดท้าย:

การเร่งความเร็วตัวเชื่อมต่อ PHP สำหรับ Tarantool โดยใช้ Async, Swoole และ Parallel

แทนการสรุป

ในความคิดของฉัน ผลลัพธ์ที่ได้ออกมาค่อนข้างคุ้มค่า และด้วยเหตุผลบางอย่าง ฉันแน่ใจว่านี่ไม่ใช่ขีดจำกัด! ไม่ว่าคุณจะต้องตัดสินใจสิ่งนี้ในโครงการจริงเพื่อตัวคุณเองเท่านั้น ฉันจะบอกว่าสำหรับฉันมันเป็นการทดลองที่น่าสนใจที่ช่วยให้คุณประเมินได้ว่าคุณสามารถ "บีบ" ออกจากตัวเชื่อมต่อ TCP แบบซิงโครนัสได้มากเพียงใดโดยใช้ความพยายามเพียงเล็กน้อย หากคุณมีแนวคิดในการปรับปรุงเกณฑ์มาตรฐาน เรายินดีที่จะพิจารณาคำขอดึงข้อมูลของคุณ โค้ดทั้งหมดพร้อมคำแนะนำในการเริ่มใช้งานและผลลัพธ์ได้รับการเผยแพร่แยกกัน ที่เก็บ.

ที่มา: will.com

เพิ่มความคิดเห็น