Làm cách nào để tăng tốc hàm node_save () của drupal?


9

Tôi đang gặp nhiều rắc rối với sự không hiệu quả của node_save (). Nhưng nút có cứu được vấn đề của tôi không? Cuối cùng đó là những gì tôi đang cố gắng tìm hiểu.

Tôi đã tạo ra một vòng lặp với 100.000 lần lặp. Tôi đã tạo mức tối thiểu để đối tượng nút có hiệu lực và lưu chính xác. Đây là mã lưu nút:

$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);
}

Đây là kết quả:

100.000 nút đã được lưu, mỗi nút sử dụng node_save (). Phải mất 5196,22 giây để hoàn thành. Đó là CHỈ 19 tiết kiệm một giây.

Để nói rằng, điều đó không được chấp nhận, đặc biệt là khi người này nhận được khoảng 1200 truy vấn chèn riêng lẻ mỗi giâyngười này đang nhận được 25.000 lần chèn mỗi giây .

Vì vậy, những gì đang xảy ra ở đây? Nút thắt ở đâu? Đây có phải là hàm với hàm_s_save () không và nó được thiết kế như thế nào?

Nó có thể là phần cứng của tôi? Phần cứng của tôi là một máy chủ phát triển, không có ai trên đó ngoại trừ tôi - Intel dual core, 3Ghz, Ubuntu 12.04 với 16 hợp đồng ram.

Trong khi vòng lặp chạy sử dụng tài nguyên của tôi là: CPU 27% MySQL, RAM 6M; PHP RAM 22% RAM 2M.

Cấu hình mysql của tôi được thực hiện bởi trình hướng dẫn percona .

Mysql nói rằng nếu việc sử dụng CPU của tôi dưới 70% thì vấn đề của tôi là bị ràng buộc bởi đĩa . Cấp, tôi chỉ có một hoạt động của nhà máy WD Caviar 7200 RPM, nhưng tôi sẽ nhận được hơn 19 lần chèn một giây với nó Tôi hy vọng!

Cách đây không lâu tôi đã viết về việc lưu 30.000 nút trong một ngày . Tuy nhiên, để rõ ràng, nút này không liên quan gì đến bất kỳ lực lượng bên ngoài nào. Đây hoàn toàn là một điểm chuẩn để tìm hiểu về cách tăng tốc độ của các cuộc gọi đến node_save ().

Thực tế, tôi cần nhận được 30.000 mục vào cơ sở dữ liệu mỗi phút bằng cách sử dụng node_save. Nếu lưu nút không phải là một tùy chọn, tôi tự hỏi liệu tôi có thể viết hàm api drupal của riêng mình "node_batch_save ()" hay thứ gì đó lợi dụng khả năng của mysql để thực hiện chèn hàng loạt với truy vấn INSERT không . Suy nghĩ về cách tiếp cận này?


2
Có một sự khác biệt lớn giữa hiệu năng chèn thô và những gì node_save sẽ làm. Đối với một điều, node_save thực hiện một loạt các lần đọc và ghi. Nhưng không có điểm nào để thảo luận về các tắc nghẽn và tối ưu hóa có thể có mà không cần thêm dữ liệu.
Alfred Armstrong

Bạn cần xem xét lý do tại sao bạn sử dụng Drupal theo cách này cho mục đích của bạn. Nếu bạn chỉ đơn giản muốn thu thập nhiều dữ liệu trong một bàn phẳng và hiển thị nó bằng Drupal, bạn có thể muốn bỏ qua Drupal hoàn toàn khi viết nó và sử dụng một mô-đun tùy chỉnh để tích hợp dữ liệu bằng cách sử dụng Chế độ xem, v.v.
Alfred Armstrong

Tôi nghi ngờ cổ chai là về phía cơ sở dữ liệu. Node save thực hiện rất nhiều thứ trong nền: nó sẽ gọi một số hook (hook_node_presave, hook_entity_presave, hook_node_insert, hook_entity_insert, v.v.), mỗi cái có thể gọi bất kỳ số lượng mô-đun nào. Ngoài ra, node_save sẽ xây dựng lại các quyền cho nút đó và nó sẽ xóa bộ đệm cho nút đó ...
Alice Heaton

@AlfredArmstrong Tôi đang tạo các nút dựa trên dữ liệu trong cơ sở dữ liệu khác. Tôi nhào nặn dữ liệu theo đúng kiểu nội dung drupal và node_save nó. Khách hàng của tôi chủ yếu là các trường đại học muốn chuyển sang drupal. Không có gì lạ khi họ có từ 200.000 đến 1.000.000 nút (nội dung trang web, hồ sơ sinh viên và giảng viên, v.v.) họ muốn di chuyển sau một thập kỷ sử dụng giải pháp web của riêng họ. Tôi đọc nó, điều này đáng khích lệ, nhưng vẫn ít hơn cách tiếp cận mong muốn. evolvingweb.ca/story/...
blue928

.. vì vậy, tôi muốn ở lại càng say càng tốt. Sử dụng nút lưu với nhiều dữ liệu này đảm bảo tính toàn vẹn. Nếu tôi không thể làm việc đó, tôi sẵn sàng sáng tạo.
blue928

Câu trả lời:


10

Bạn sẽ không bao giờ nhận được 30 000 chèn một phút bằng cách sử dụng node_save. Không đời nào.

Một INSERT là nhanh bởi vì đó là tất cả những gì nó làm. Node save thực hiện nhiều lần chèn (bảng chính, bảng sửa đổi, bảng cho từng trường), xóa bất kỳ bộ đệm thực thể nào và bắn móc. Các móc là phần khó khăn. Nếu bạn có nhiều mô-đun đóng góp (hoặc thậm chí một mô-đun hoạt động sai) có thể thực sự giết chết hiệu suất, đặc biệt là nếu tác giả không tính đến trường hợp sử dụng "Tôi đang tiết kiệm một tấn nút cùng một lúc". Chẳng hạn, tôi đã phải thêm cái này vào lớp Migrate của mình:

  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);
  }

Mặt khác, nếu bạn viết một chức năng lưu tùy chỉnh mà không gọi được móc, bạn có nguy cơ rõ ràng nhận được dữ liệu không nhất quán, trong trạng thái bất ngờ của hệ thống. Tôi sẽ không bao giờ khuyên bạn nên làm điều đó. Bật xhprof và xem những gì đang xảy ra.


Một số mô-đun di chuyển ngoài kia, làm thế nào để chúng kết thúc các nút lưu số lượng lớn? Ý tôi là, ở phần cuối của tất cả, tất cả đều sôi sục với một tuyên bố INSERT, phải không? Làm thế nào để lớp di chuyển của bạn cuối cùng chèn từ 'nguồn' vào 'đích' khi không sử dụng lưu nút nhưng vẫn cần duy trì tính toàn vẹn dữ liệu trên các bảng?
blue928

Tất cả các mô-đun di chuyển mà tôi đã đi qua đều sử dụng node_save.
Alfred Armstrong

1
@ blue928 Anh ta nói rằng anh ta sử dụng node_save(), nhưng thêm một số mã để giảm thiểu các sự cố đã biết có thể gây ra, như Pathauto xây dựng lại bộ đệm của menu sau mỗi lần lưu nút
Clive

ah, tôi hiểu rồi Bojan là mã của bạn có sẵn trong một mô-đun hoặc trực tuyến nơi tôi có thể thấy cách bạn đã xử lý các tắc nghẽn như đường dẫn tự động? Ý tưởng tốt với xhprof. Tôi sẽ kiểm tra nó.
blue928

5

Trước hết, cài đặt XCache / APC (cho PHP <5.5) và định cấu hình memcached cho Drupal.

Sau đó, bạn có thể tối ưu hóa cấu hình MySQL của mình cho các truy vấn nặng bằng cách sử dụng tập lệnh mysqltuner có sẵn tại: http://mysqltuner.pl

Ví dụ

# 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

Đề xuất khác:

  • vô hiệu hóa các mô-đun mà bạn không cần (ví dụ: Devel , mô-đun ghi nhật ký cơ sở dữ liệu cốt lõi, v.v.),
  • nâng cấp PHP của bạn lên nhánh mới nhất hoặc cao hơn,
  • biên dịch lại PHP của bạn cho kiến ​​trúc 64 bit hoặc cao hơn tùy thuộc vào CPU của bạn,
  • sử dụng thiết bị lưu trữ nhanh hơn cho các tệp db của bạn hoặc toàn bộ môi trường LAMP (ví dụ: SSD hoặc hệ thống tệp dựa trên bộ nhớ ),
  • sử dụng trình gỡ lỗi PHP hoặc trình lược tả để tìm ra bất kỳ nút cổ chai hiệu năng nào (ví dụ: XDebug Profiler , DTrace hoặc NuSphere PhpED PHP Profiler ),
  • chạy một số lệnh drush tốn thời gian dưới công cụ định hình gprof , vì vậy bạn cũng có thể tìm thấy một số nút cổ chai hiệu năng

1
Điều chỉnh MySQL dường như tạo ra một sự khác biệt lớn. Tôi đã đi từ khoảng 80 node_saves một phút đến khoảng 700 chỉ bằng cách làm theo các mẹo được đưa ra bởi mysqltuner.pl.
John McCollum

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.