ฉันจะเพิ่มความเร็วของฟังก์ชั่น node_save () ของ drupal ได้อย่างไร


9

ฉันกำลังมีปัญหามากกับความไร้ประสิทธิภาพของ node_save () แต่โหนดบันทึกปัญหาของฉันได้อย่างไร นั่นคือสิ่งที่ฉันพยายามค้นหา

ฉันสร้างวงวนซ้ำ 100,000 ครั้ง ฉันสร้างขั้นต่ำเปล่าสำหรับวัตถุโหนดให้ถูกต้องและบันทึกอย่างถูกต้อง นี่คือรหัสการบันทึกโหนด:

$node = new stdClass();
        $node->type = "test_page";

        node_object_prepare($node);

        $node->uid = 1;
        $node->title = $node_title;
        $node->status = 1;
        $node->language = LANGUAGE_NONE;
        if($node = node_submit($node)){
            node_save($node);
}

นี่คือผลลัพธ์:

มีการบันทึก 100,000 โหนดโดยใช้ node_save () ใช้เวลา 5196.22 วินาทีในการทำให้เสร็จสมบูรณ์ นั่นคือเพียง 19 บันทึกวินาที

ที่จะพูดน้อยที่เป็นที่ยอมรับไม่ได้โดยเฉพาะอย่างยิ่งเมื่อสมาชิกผู้นี้จะได้รับรอบ 1200 คำสั่งแทรกบุคคลต่อวินาทีและสมาชิกผู้นี้จะได้รับ 25,000 แทรกต่อวินาที

แล้วเกิดอะไรขึ้นที่นี่? คอขวดอยู่ที่ไหน มันเป็นกับฟังก์ชั่น node_save () และวิธีการออกแบบมันได้หรือไม่

เป็นฮาร์ดแวร์ของฉันได้ไหม ฮาร์ดแวร์ของฉันเป็นเซิร์ฟเวอร์สำหรับการพัฒนาไม่มีใครยกเว้นมันสำหรับฉัน - Intel dual core, 3Ghz, Ubuntu 12.04 พร้อม RAM 16 กิกะไบต์

ในขณะที่ลูปรันการใช้ทรัพยากรของฉันคือ: MySQL 27% CPU, RAM 6M; PHP 22% CPU 2M RAM

การกำหนดค่า MySQL ของฉันถูกทำโดยตัวช่วยสร้าง Percona

mysql บอกว่าถ้าใช้ CPU ของฉันอยู่ภายใต้ 70% ปัญหาของฉันดิสก์ที่ถูกผูกไว้ ได้รับฉันมีเพียงโรงโม่ WD Caviar 7200 รอบต่อนาที แต่ฉันควรจะได้รับมากกว่า 19 แทรกวินาทีกับฉันหวังว่า!

ไม่นานที่ผ่านมาผมเขียนเกี่ยวกับการประหยัด 30,000 โหนดในหนึ่งวัน อย่างไรก็ตามเพื่อความชัดเจนโหนดนี้ไม่มีส่วนเกี่ยวข้องกับแรงภายนอกใด ๆ เป็นมาตรฐานอย่างหมดจดในการเรียนรู้เกี่ยวกับวิธีเพิ่มความเร็วในการโทรถึง node_save ()

ตามจริงแล้วฉันต้องการรับ 30,000 รายการในฐานข้อมูลทุก ๆ นาทีโดยใช้ node_save ถ้าโหนดประหยัดไม่ได้เป็นตัวเลือกที่ฉันสงสัยว่าฉันสามารถเขียนฟังก์ชัน API Drupal ของฉันเอง "node_batch_save ()" หรือบางสิ่งบางอย่างที่ใช้ประโยชน์จากความสามารถของ MySQL ในการที่จะทำใส่กลุ่มกับแบบสอบถาม INSERT ความคิดเกี่ยวกับวิธีการวิธีนี้


2
มีความแตกต่างอย่างมากระหว่างประสิทธิภาพการแทรกแบบดิบและสิ่งที่ node_save จะทำ สำหรับสิ่งหนึ่ง node_save ดำเนินการชุดของการอ่านและการเขียน แต่ไม่มีประเด็นที่จะพูดถึงคอขวดและการเพิ่มประสิทธิภาพที่เป็นไปได้หากไม่มีข้อมูลเพิ่มเติม
Alfred Armstrong

คุณต้องพิจารณาว่าทำไมคุณจึงใช้ Drupal ด้วยวิธีนี้เพื่อจุดประสงค์ของคุณ หากคุณต้องการเก็บข้อมูลจำนวนมากในตารางแบนและแสดงโดยใช้ Drupal คุณอาจต้องการข้าม Drupal ไปพร้อมกันเมื่อเขียนและใช้โมดูลที่กำหนดเองเพื่อรวมข้อมูลโดยใช้ Views ฯลฯ
Alfred Armstrong

ฉันสงสัยว่าคอขวดอยู่ทางด้านฐานข้อมูล Node save ทำสิ่งต่าง ๆ มากมายในพื้นหลัง: มันจะเรียกจำนวน hooks (hook_node_presave, hook_entity_presave, hook_node_insert, hook_entity_insert, ฯลฯ ) ซึ่งแต่ละอันอาจเรียกหมายเลขของโมดูลใด ๆ นอกจากจะสร้าง node_save สิทธิ์สำหรับโหนดนั้นและมันจะล้างแคชสำหรับโหนดที่ ...
อลิซ Heaton

@AlfredArmstrong ฉันสร้างโหนดโดยใช้ข้อมูลที่อยู่ในฐานข้อมูลอื่น ฉันปั้นข้อมูลไปยังประเภทเนื้อหา drupal ที่ถูกต้องและ node_save ลูกค้าของฉันส่วนใหญ่เป็นมหาวิทยาลัยที่ต้องการเปลี่ยนมาใช้ Drupal ไม่ใช่เรื่องแปลกสำหรับพวกเขาที่จะมีโหนดระหว่าง 200,000 ถึง 1,000,000 โหนด (เนื้อหาไซต์ของ depts, บันทึกของนักเรียนและคณาจารย์ ฯลฯ ) พวกเขาต้องการที่จะโยกย้ายหลังจากทศวรรษที่ผ่านมาของพวกเขาเองในการใช้เว็บโซลูชั่น ฉันอ่านสิ่งนี้ซึ่งเป็นกำลังใจ แต่ก็ยังน้อยกว่าวิธีที่พึงประสงค์ evolvingweb.ca/story/…
blue928

.. ดังนั้นฉันอยากพักแบบ drupally มากที่สุด การใช้การบันทึกโหนดด้วยข้อมูลจำนวนมากทำให้มั่นใจในความสมบูรณ์ หากฉันไม่สามารถทำงานได้ฉันก็ยินดีที่จะสร้างสรรค์
blue928

คำตอบ:


10

คุณจะไม่ได้รับ 30,000 เม็ดต่อนาทีโดยใช้ node_save ไม่มีทาง.

INSERT นั้นรวดเร็วเพราะนั่นคือทั้งหมดที่ทำได้ การบันทึกโหนดทำหน้าที่แทรกหลายอย่าง (ตารางหลัก, ตารางการตรวจทาน, ตารางสำหรับแต่ละฟิลด์), ล้างแคชเอนทิตีใด ๆ และยิงตะขอ ตะขอเป็นส่วนที่ยุ่งยาก หากคุณมีโมดูล contrib จำนวนมาก (หรือแม้แต่โมดูลที่ทำงานผิดปกติ) ซึ่งสามารถฆ่าประสิทธิภาพได้จริง ๆ โดยเฉพาะอย่างยิ่งหากผู้เขียนไม่ได้อธิบายถึงการใช้งานกรณี "ฉันกำลังบันทึกโหนดจำนวนมากในคราวเดียว" ตัวอย่างเช่นฉันต้องเพิ่มสิ่งนี้ในชั้นเรียนโยกย้ายของฉัน:

  public function processImport(array $options = array()) {
    parent::processImport($options = array());
    // Do not force menu rebuilding. Otherwise pathauto will try to rebuild
    // in each node_save() invocation.
    variable_set('menu_rebuild_needed', FALSE);
  }

ในทางตรงกันข้ามถ้าคุณเขียนฟังก์ชั่นการบันทึกแบบกำหนดเองที่ไม่ขอฮุกคุณจะตกอยู่ในอันตรายที่ชัดเจนของการรับข้อมูลที่ไม่สอดคล้องกันในสถานะที่ระบบคาดไม่ถึง ฉันจะไม่แนะนำให้ทำเช่นนั้น ดับ xhprof แล้วดูว่าเกิดอะไรขึ้น


โมดูลการย้ายข้อมูลบางส่วนออกมาทำอย่างไรพวกเขาจะจบลงด้วยการบันทึกโหนดจำนวนมาก ฉันหมายความว่าในตอนท้ายของมันทั้งหมดมันทั้งหมดลงไปในคำสั่ง INSERT ใช่มั้ย คลาสการย้ายข้อมูลของคุณแทรกจาก 'ต้นทาง' ถึง 'เป้าหมาย' อย่างไรเมื่อไม่ได้ใช้การบันทึกโหนด แต่ยังต้องการรักษาความสมบูรณ์ของข้อมูลข้ามตาราง
blue928

โมดูลการโอนย้ายทั้งหมดที่ฉันพบจะใช้ node_save
Alfred Armstrong

1
@ blue928 เขาบอกว่าเขาไม่ได้ใช้node_save()แต่เพิ่มโค้ดบางส่วนเพื่อลดปัญหาที่รู้จักกันว่าสามารถเกิดขึ้นเช่นการสร้าง Pathauto แคชเมนูทุกครั้งหลังโหนดประหยัด
ไคลฟ์

อ่าฉันเข้าใจแล้ว Bojan เป็นรหัสของคุณที่มีอยู่ในโมดูลหรือออนไลน์ที่ฉันสามารถดูว่าคุณได้รับการจัดการกับคอขวดเช่นเส้นทางอัตโนมัติ? ความคิดที่ดีกับ xhprof ฉันจะตรวจสอบสิ่งนั้น
blue928

5

ก่อนอื่นให้ติดตั้ง XCache / APC (สำหรับ PHP <5.5) และกำหนดค่า memcached สำหรับ Drupal

จากนั้นคุณสามารถเพิ่มประสิทธิภาพการกำหนดค่า MySQL ของคุณสำหรับการสืบค้นจำนวนมากโดยใช้สคริปต์ mysqltuner ได้ที่: http://mysqltuner.pl

เช่น

# performance tweaks (adjusted based on mysqltuner.pl)
query_cache_size = 32M
query_cache_limit = 256M
join_buffer_size = 32M
key_buffer = 8M
max_allowed_packet = 32M
table_cache = 512
sort_buffer_size = 1M
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 1M
myisam_sort_buffer_size = 8M

# When making adjustments, make tmp_table_size/max_heap_table_size equal
tmp_table_size = 16M
max_heap_table_size = 16M

thread_cache_size = 4

คำแนะนำอื่น ๆ :

  • ปิดการใช้งานโมดูลที่คุณไม่ต้องการ (เช่นDevel , โมดูลการบันทึกฐานข้อมูลหลัก, ฯลฯ ),
  • อัพเกรด PHP ของคุณเป็นสาขาล่าสุดหรือสูงกว่า
  • คอมไพล์ PHP ของคุณใหม่สำหรับสถาปัตยกรรม 64 บิตหรือสูงกว่าขึ้นอยู่กับ CPU ของคุณ
  • ใช้อุปกรณ์เก็บข้อมูลที่เร็วกว่าสำหรับไฟล์ db หรือสภาพแวดล้อม LAMP ทั้งหมด (เช่น SSD หรือระบบไฟล์ที่ใช้หน่วยความจำ )
  • ใช้ดีบักเกอร์ PHP หรือผู้สร้างโปรไฟล์เพื่อหาปัญหาคอขวดของประสิทธิภาพ (เช่นXDebug Profiler , DTraceหรือNuSphere PhpED PHP Profiler )
  • รันคำสั่ง drush ที่ใช้เวลานานภายใต้เครื่องมือการทำโปรไฟล์gprofเพื่อให้คุณสามารถหาคอขวดของประสิทธิภาพได้เช่นกัน

1
การปรับแต่ง MySQL ดูเหมือนจะสร้างความแตกต่างอย่างมาก ฉันไปจาก 80 node_saves ต่อนาทีเป็นประมาณ 700 โดยทำตามคำแนะนำที่ให้ไว้โดย mysqltuner.pl
John McCollum

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.