Cấu hình sever khi chạy chương trình nặng trong laravel
Mình mới đưa 1 website lên vps ( CentOs7 - Nginx - larave9 - php8) Mình cco một chương trình đệ quy chạy khá nặng nên khi vào truy cập vào thì luôn báo là 502 bad Gateway trong log của nginx thì báo
2022/05/22 15:02:49 [error] 28086#0: *23 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 210.245.104.244, server: domain.com, request: "GET /testTNT HTTP/2.0", upstream: "fastcgi://unix:/tmp/php-cgi-80.sock:", host: "domain.com"
Vấn đề là cùng code và db đó mình chạy trên localhost thì nó không sao cả. Hiện mình đang không biết cần chỉnh sửa gì trong cấu hình của PHP or Nginx. thanks
2 ANSWERS
cái này bạn chạy đệ quy truy xuất trực tiếp từ cơ sở dữ liệu sẽ khá nặng .Bạn thử cân nhắc xem cách mình xem sao .Truy vấn 1 lần cơ sở dữ liệu sau đó lưu trữ dưới dạng array .Các lần đệ quy bạn sẽ đệ quy trên array điều này sẽ giảm tải cho cơ sở dữ liệu sẽ xử lý được vấn đề
Mình cũng từng có ý tưởng đó nhưng vì số lượng bản ghi khá lớn tầm hơn 40.000 bản ghi và còn tăng nên làm thể cái arr sợ nó to quá dễ bị lỗi k nhỉ?
@LongThanh.it thường thì đệ quy để hiểu được thuật toán thôi, còn code thực thế sẽ chuyển thành vòng lặp while hoặc for , chứ dùng đệ quy nó ngốn tài nguyên máy chủ lắm , vì khi hàm đệ quy chưa thực thi xong nó sẽ không giải phóng bộ nhỡ hay đóng kết nối DB
Hiện tại mình đang có 2 hướng đi.
- Truy vấn đệ quy trực tiếp với database thông qua model.
Model:
public function parent()
{
return $this->hasMany(Post::class, 'id', 'parent_id')->with('parent');
}
Contronller
public function home($id
{
$AllPost = Post::select('id', 'parent_id', )->with('parent')->get()->toArray();
$collapsed = collect($nhanh)->flatten();
// Đã có dữ liệu ....
}
- Lấy hết dữ liệu ra thành array sau đó với dùng đệ quy phân cấp.
Controller:
public function home($id)
{
$post= Post::where('id', $id)->first();
$allpost= Post::select('id', 'parent_id') ->get()->toArray();
$collapsed = $this->dequy_timcha($allpost, $post->id);
//Đã có dữ liệu ....
}
public function dequy_timcha($data, $parent_id)
{
$result = [];
foreach ($data as $key => $item) {
if ($item['id'] == $parent_id) {
$result[] = $item;
$child = $this->dequy_timcha($data, $item['parent_id']);
$result = array_merge($result, $child);
}
}
return $result;
}
Mình đã test cả hai cách này với dữ liệu tầm hơn 40.000 thì nó lag như nhau. ko thấy khác biệt luôn. xử lý rất lâu.
@LongThanh.it Dữ liệu nhiều nên dùng chunkById https://laravel.com/docs/9.x/queries#chunking-results ban sử dụng $posts = Post::chunkById xem sao .Tham khảo thử xem nhé việc tạo sitemap bên mình .Dữ liệu mình query rồi lưu cache ở redis . $data = Cache::remember('sitemaps_index_art',env('CACHE_TIME',10000),function (){ DB::table('articlers')->chunkById(200,function($articlers) { foreach ($articlers as $article) { $this->array_return[] = $article; } }); return $this->array_return; });
public function timcha_ko_dequy($data, $parent_id)
{
$list_parent_id = [];
$list_parent_id[] = $parent_id;
$result = [];
foreach ($data as $key => $item) {
if (in_array($item['id'] ,list_parent_id )) {
$result[] = $item;
$list_parent_id = array_merge($list_parent_id , $item['parent_id'])
}
}
return $result;
}
@haingoc86vibo có nhầm gì không b?
$list_parent_id = array_merge($list_parent_id , $item['parent_id'])
array_merge(): Argument #2 must be of type array, int given
Đối với các hàm đệ quy, bạn không nên sử dụng các câu lệnh truy vấn dữ liệu.
Điều đó sẽ làm tăng số lần truy vấn đến database, dẫn đến tăng thời gian chờ và có thể gây quá tải cho database.
Ngoài ra, bạn cũng có thể cấu hình để tăng thời gian chờ của nginx trong tệp config như sau:
http {
...
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}
Tuy nhiên việc tăng cấu hình nginx sẽ không triệt để, khi lượng data của bạn ngày càng nhiều lên thì việc tăng ở trên sẽ không còn tác dụng
thanks