Giải Pháp Cứ 16 Giây Thì Phải Tạo Hoặc Update 80.000 rows.
Chào các bạn, mình gặp một vấn đề khi phát triển project trên nền laravel
Nói sơ qua về project này.
- Đầu Tiên Người dùng tạo Jobs :
- Cứ mỗi 16s giây lại phải làm 1 lần, làm xong sẽ lưu lại log bao gồm trạng thái và kết quả ,tổng cộng làm 5000 lần sẽ xong Jobs.
- Jobs khi sử lý cần phải curl 3-5 lần rất tốn tài nguyên.
- Jobs phải có chức năng stop nên mình cũng ko thể add hết 5000 lần vào hàng đợi mà phải tạo bảng chứa time_start cho từng jobs rồi sau đó.Mình sẽ phải dùng scheduling chạy mỗi phút 1 lần query đám jobs đã đến lúc chạy để thêm chúng vào hàng đợi.
Hiện có tầm 5000 jobs và đang tăng lên.
=> cứ 16 giây thì phải tạo hoặc update 80.000 rows.
=> Web đơ
Mình research vài ngày nhưng vẫn chưa ra giải pháp nào tốt. Hy vọng bạn nào đã từng làm project tương tự share mình ít kinh nghiệm
1 CÂU TRẢ LỜI
@MinhDuc Với thông tin hiện tại mình có một ý kiến thế này
Bạn có thể thử dùng Redis để lưu 5000 kết quả trung gian. Redis đọc ghi rất nhanh, ưu việt hơn hẳn so với SQL nên có thể sẽ giải quyết tốt bài toán đọc ghi liên tục của bạn.
Sau khi hoàn thành job to bạn có thể ghi 1 lần các kết quả trung gian vào DB chính, hoặc nếu không cần thiết thì delete dữ liệu ở Redis đi là xong.
Chào bạn. Các trên gặp một vấn đề là Khi Người dùng dừng tiến trình. Thì các Jobs buộc phải bị hủy. Nếu vậy. Trong jobs ta vẫn phải request tới database để kiểm tra trạng thái của tiếng trình
@MinhDuc redis về cơ bản nó cũng là một dạng db, đọc ghi bình thường mà
Giả sử user huỷ job lớn thì set một cái key “<job_id>_cancelled” value true.
Trước khi chạy job con nào thì check cái key đó, true thì return luôn không cho chạy nữa chẳng hạn.
Ngoài ra thay vì tạo một lúc 5000 rows, nếu có thể bạn có thể chỉ set các job con cho phút đầu tiên, sau mỗi mỗi job con sẽ có callback để init job con kế tiếp gối nhau như thế. Tuy nhiên làm thế này sẽ phải handle error tốt nếu không muốn đang chạy thì đứt gánh
1.Qua gợi ý của bạn. Mình nghĩ ko nên dùng queues vì sợ mất data , time out các kiểu . 2. Cách trên bị hạng chế do độ trễ của mỗi jobs => jobs A chạy tốn 5s thì jobs B sẽ bị call trễ 5 giây Mình nghĩ ra giải pháp sau bạn góp ý vs nha
- cron job chạy 1 phút 1 lần query lấy process nào active = true;
- Nếu nó đang được kích hoạt thì mình cho nó vào vòng lặp while với điều kiện bên dưới
public function shedule(){
$total = $process->total;
$result = array(
'completed ' => 0
'success' => 0,
'error' => 0,
);
while ( ){
if( Redis::get('active'.$process_id) == flase || $result['completed '] > $total ){
break;
$this->jobCompletedCallback($result);
}
try{
$this->doMyJobs();
$result['success']++;
}catch(Exception $e){
$result['error']++;
}
$result['completed ']++;
$this->saveResult($result);
sleep(16);
}
}
public function doMyJobs(){
// nhiệm vụ con
}
public function saveResult($result){
// lưu tạm kết quả lên redis
}
public function jobCompletedCallback($result){
// nhiệm vụ xong lưu kết quả vào database và xóa mọi thứ trên redis
}
@MinhDuc Có giải pháp thì ta cứ thử thôi Đáp ứng được yêu cầu là OK. Mình cũng không nắm được gì về yêu cầu của cái bạn đang làm.
Còn về vụ
jobs A chạy tốn 5s thì jobs B sẽ bị call trễ 5 giây
thì đơn giản mình assign job B vào đầu tiến trình chạy job A là xong mà
P.S. Mình chỉ đóng góp ý tưởng thôi, còn không biết gì về PHP và Laravel nhé
Theo mình hiểu thì jobs được chạy phía backend sao lại làm web (phần frontend phía trên) đơ được bạn nhỉ?
Trên frontend phải hiển thị được trạng thái đang chạy của jobs à?
Thực sự đọc giải thích của bạn khó hiểu quá Mình ngồi đọc đi đọc lại không dưới chục lần nhưng vẫn ... chưa hiểu gì cả
Bạn giải thích thêm một chút được không
"làm 1 lần" ở đây là làm cái gì? Bạn đang làm thế nào để căn 16 giây để thực hiện việc đó.
lưu trạng thái và kết quả của cái gì? bởi theo bạn nói là chạy 5000 lần mới xong 1 job, nên mình không rõ là lưu lại log thì là log của cái gì
Tức là 1 job của bạn chạy 5000 lần một cái gì đó, và trong đó có 3-5 lần là curl, không biết mình hiểu thế có đúng không Bạn đang
curl
cái gì mà lại tốn tài nguyên? Hiện quá trình đó đang xử lý mất bao lâu? Từ đó tính ra để chạy hết 1 job hiện đang cần bao nhiêu thời gian?Schedulling hay crontab thì chỉ chạy được theo từng phút, hiện bạn đang xử lý thế nào để cứ 16 giây lại xử lý 1/5000 của job nhỉ? Và sao lại cần phải tạo hoặc update 80,000 rows vậy? Bạn tạo mới, hay update 80,000 rows này như thế nào, cần dùng đến khoảng bao nhiêu câu query?
Web đơ là do web cũng request đến bảng chứa 80,000 rows được tạo mới/update, mình hiểu thế đúng không nhỉ?
Bạn nên đưa thêm thông tin chi tiết thì mọi người sẽ có thể hiểu và support bạn được tốt hơn
@thangtd90 Theo em hiểu thì vấn đề của bạn ấy là thế này
@bs90 : Bác Nói đúng ý em rồi Đơ là do em sử lý bacnkend cả triệu reuqest một lúc Vì Khi người dùng tạo ra một tiến trình . Ngay lập tức trong backend của em sẽ tạo 5000 rows chứa Thông tin về Jobs của Tiến trình Vừa tạo. => em nói thêm là cứ mỗi lần request thành công em sẽ tính phí người dùng.
Giải pháp ném lên Redis : Gặp một ván đề là khi người dùng hủy tiến trình thì các Jobs của tiến trình đó phải hủy theo.