ในระบบนิเวศ PHP ปัจจุบันมีตัวเชื่อมต่อสองตัวสำหรับการทำงานกับเซิร์ฟเวอร์ Tarantool - นี่คือส่วนขยาย PECL อย่างเป็นทางการ
ในบทความนี้ ฉันต้องการแบ่งปันผลการทดสอบประสิทธิภาพของไลบรารีทั้งสอง และแสดงให้เห็นว่า ด้วยการเปลี่ยนแปลงโค้ดเพียงเล็กน้อย คุณสามารถเพิ่มประสิทธิภาพได้ 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 สำหรับตัวเชื่อมต่อ PHP และในการทดสอบเพิ่มเติม เราจะใช้อันที่แสดงผลลัพธ์ที่ดีที่สุด:
แม้ว่าเวอร์ชัน PHP (Pure) จะด้อยกว่าส่วนขยาย PECL ในเรื่องความเร็ว แต่ในโครงการจริง ฉันยังคงแนะนำให้ใช้มัน
เรามาวัดประสิทธิภาพของตัวเชื่อมต่อในโหมดซิงโครนัสกันดีกว่า:
ดังที่เห็นได้จากกราฟ ตัวเชื่อมต่อ PECL (Tarantool) แสดงประสิทธิภาพที่ดีกว่าเมื่อเปรียบเทียบกับตัวเชื่อมต่อ PHP (ไคลเอนต์) แต่นี่ก็ไม่น่าแปลกใจ เนื่องจากอย่างหลังนอกเหนือจากการใช้งานในภาษาที่ช้ากว่าแล้ว จริงๆ แล้วยังทำงานได้มากกว่าอีกด้วย: มีการสร้างออบเจ็กต์ใหม่ทุกครั้งที่เรียก ขอร้อง и คำตอบ (ในกรณีเลือก - ด้วย เกณฑ์และในกรณีของ Update/Upsert ― การดำเนินการ) แยกเอนทิตี การเชื่อมต่อ, เครื่องบรรจุหีบห่อ и ผู้ดำเนินการ พวกเขายังเพิ่มค่าใช้จ่ายด้วย แน่นอนว่าความยืดหยุ่นต้องแลกมาด้วยราคา อย่างไรก็ตามโดยทั่วไปล่าม PHP แสดงประสิทธิภาพที่ดีแม้ว่าจะมีความแตกต่าง แต่ก็ไม่มีนัยสำคัญและอาจจะน้อยกว่านี้เมื่อใช้การโหลดล่วงหน้าใน PHP 7.4 ไม่ต้องพูดถึง JIT ใน PHP 8
เดินหน้าต่อไป Tarantool 2.0 เพิ่มการรองรับสำหรับ SQL มาลองดำเนินการเลือก แทรก อัปเดต และลบโดยใช้โปรโตคอล SQL และเปรียบเทียบผลลัพธ์กับ noSQL (ไบนารี) ที่เทียบเท่า:
ผลลัพธ์ของ SQL ไม่ได้น่าประทับใจมากนัก (ฉันขอเตือนคุณว่าเรากำลังทดสอบโหมดซิงโครนัสอยู่) อย่างไรก็ตาม ฉันจะไม่เสียใจกับเรื่องนี้ล่วงหน้า การสนับสนุน SQL ยังอยู่ระหว่างการพัฒนา (เช่น เมื่อเร็วๆ นี้ มีการเพิ่มการสนับสนุน
อะซิงโครนัส
ตอนนี้เรามาดูกันว่าส่วนขยาย Async สามารถช่วยให้เราปรับปรุงผลลัพธ์ข้างต้นได้อย่างไร ในการเขียนโปรแกรมแบบอะซิงโครนัส ส่วนขยายจะมี API ที่ใช้ Coroutines ซึ่งเราจะใช้ เราพบว่าจำนวนโครูทีนที่เหมาะสมที่สุดสำหรับสภาพแวดล้อมของเราคือ 25:
“กระจาย” การดำเนินการ 10,000 ครั้งไปยัง 25 โครูทีน และดูว่าเกิดอะไรขึ้น:
จำนวนการดำเนินการต่อวินาทีเพิ่มขึ้นมากกว่า 3 เท่า
น่าเศร้าที่ตัวเชื่อมต่อ PECL ไม่ได้เริ่มต้นด้วย ext-async
แล้ว SQL ล่ะ?
อย่างที่คุณเห็น ในโหมดอะซิงโครนัส ความแตกต่างระหว่างโปรโตคอลไบนารี่และ SQL อยู่ภายในขอบเขตของข้อผิดพลาด
สวูล
เราค้นหาจำนวนคอร์รูทีนที่เหมาะสมที่สุดอีกครั้ง คราวนี้สำหรับ Swoole:
หยุดที่ 25 ทำซ้ำเคล็ดลับเดียวกันกับส่วนขยาย Async - กระจาย 10,000 การดำเนินการระหว่าง 25 coroutines นอกจากนี้ เราจะเพิ่มการทดสอบอีกครั้งโดยแบ่งงานทั้งหมดออกเป็น 2 กระบวนการ (นั่นคือ แต่ละกระบวนการจะดำเนินการ 5,000 ครั้งใน 25 โครูทีน) กระบวนการจะถูกสร้างขึ้นโดยใช้ SwooleProcess.
ผล:
Swole แสดงผลลัพธ์ที่ต่ำกว่าเล็กน้อยเมื่อเทียบกับ Async เมื่อรันในกระบวนการเดียว แต่ด้วย 2 โพรเซส รูปภาพจึงเปลี่ยนไปอย่างมาก (หมายเลข 2 ไม่ได้ถูกเลือกโดยบังเอิญ บนเครื่องของฉัน มันคือ 2 โพรเซสที่แสดงผลลัพธ์ที่ดีที่สุด)
อย่างไรก็ตามส่วนขยาย Async ยังมี API สำหรับการทำงานกับกระบวนการต่างๆ แต่ฉันไม่ได้สังเกตเห็นความแตกต่างใด ๆ จากการรันการวัดประสิทธิภาพในกระบวนการหนึ่งกระบวนการขึ้นไป (อาจเป็นไปได้ว่าฉันทำผิดพลาดที่ไหนสักแห่ง)
SQL กับโปรโตคอลไบนารี:
เช่นเดียวกับ Async ความแตกต่างระหว่างการดำเนินการไบนารีและ SQL จะถูกตัดออกในโหมดอะซิงโครนัส
Parallel
เนื่องจากส่วนขยายแบบขนานไม่ได้เกี่ยวกับโครูทีน แต่เกี่ยวกับเธรด เราจึงมาวัดจำนวนเธรดแบบขนานที่เหมาะสมที่สุดกัน:
มันคือ 16 ในเครื่องของฉัน มารันการวัดประสิทธิภาพตัวเชื่อมต่อบน 16 เธรดแบบขนานกัน:
อย่างที่คุณเห็น ผลลัพธ์นั้นดีกว่าส่วนขยายแบบอะซิงโครนัสด้วยซ้ำ (ไม่นับ Swoole ที่ทำงานบน 2 กระบวนการ) โปรดทราบว่าสำหรับตัวเชื่อมต่อ PECL การดำเนินการ Update และ Upsert จะว่างเปล่า นี่เป็นเพราะความจริงที่ว่าการดำเนินการเหล่านี้ล้มเหลวโดยมีข้อผิดพลาด - ฉันไม่รู้ว่ามันเป็นความผิดของ ext-parallel, ext-tarantool หรือทั้งสองอย่าง
ตอนนี้เรามาเปรียบเทียบประสิทธิภาพของ SQL:
สังเกตเห็นความคล้ายคลึงกับกราฟของตัวเชื่อมต่อที่ทำงานพร้อมกันหรือไม่
ด้วยกัน
และสุดท้าย เราจะสรุปผลลัพธ์ทั้งหมดในกราฟเดียวเพื่อดูภาพรวมของส่วนขยายที่ทดสอบ มาเพิ่มการทดสอบใหม่หนึ่งรายการลงในแผนภูมิซึ่งเรายังไม่ได้ทำ - มารัน Async coroutines แบบขนานโดยใช้ Parallel* กัน แนวคิดในการรวมส่วนขยายข้างต้นเข้าด้วยกันแล้ว
* ไม่สามารถเปิดใช้ Swoole coroutines ด้วย Parallel ได้ ดูเหมือนว่าส่วนขยายเหล่านี้เข้ากันไม่ได้
ดังนั้นผลลัพธ์สุดท้าย:
แทนการสรุป
ในความคิดของฉัน ผลลัพธ์ที่ได้ออกมาค่อนข้างคุ้มค่า และด้วยเหตุผลบางอย่าง ฉันแน่ใจว่านี่ไม่ใช่ขีดจำกัด! ไม่ว่าคุณจะต้องตัดสินใจสิ่งนี้ในโครงการจริงเพื่อตัวคุณเองเท่านั้น ฉันจะบอกว่าสำหรับฉันมันเป็นการทดลองที่น่าสนใจที่ช่วยให้คุณประเมินได้ว่าคุณสามารถ "บีบ" ออกจากตัวเชื่อมต่อ TCP แบบซิงโครนัสได้มากเพียงใดโดยใช้ความพยายามเพียงเล็กน้อย หากคุณมีแนวคิดในการปรับปรุงเกณฑ์มาตรฐาน เรายินดีที่จะพิจารณาคำขอดึงข้อมูลของคุณ โค้ดทั้งหมดพร้อมคำแนะนำในการเริ่มใช้งานและผลลัพธ์ได้รับการเผยแพร่แยกกัน
ที่มา: will.com