Phần 1: Nhật ký xây dựng hệ thống thi lập trình trực tuyến
Lí do xây dựng
- Sau khi nhìn đống đề tài web shop của thầy đưa ra em đã quá chán và quyết định làm 1 đề tài gì đó mới mẻ.
- Trong lúc đó CLB em có tổ chức thi contest, hệ thống lúc bấy giờ là 1 open source nhưng ae ra đề lại muốn custom vài chỗ nhưng không thể vì bọn em không đủ trình.
Đó là lý do chính em quyết định tự xây dựng một hệ thống cho riêng mình.
Bước đầu của hệ thống
Tài nguyên ban đầu:
- Backend: Nodejs.
- OS: Ubuntu 20.4
Vấn đề 1: Chạy code các ngôn ngữ lập trình kiểu gì ?
Thường khi muốn chạy các chương trình code ta thường ấn nút run trong các IDE. Nhưng ở đây ta đang muốn chạy code bằng code =))
Nhớ lại khi ta muốn code một ngôn ngữ nào đó ta thường phải có bước cài đặt môi trường (trình biên dịch). Với C/C++ là gcc nó hỗ trợ biên dịch và chạy file code C/C++ thông qua command line và các ngôn ngữ khác cũng tương tự.
Ví dụ biên dịch 1 file C++ bằng gcc
g++ main.cpp -o main
và chạy thì gõ
./main
Vấn đề 2: Chạy command line bằng Nodejs kiểu gì ?
Sau một hồi search google thì em đã tìm ra, ta sẽ dùng Spawned Child Processes .
Triển khai đơn giản như sau:
const { spawn } = require('child_process');
const child = spawn('g++',['main.cpp -o main && ./main'], {shell: true});
child.stdout.on('data', (data) => {
console.log(`output: ${data}`);
});
child.stderr.on("data", (err) => {
console.log(`error, ${err.toString()}`);
});
Viết 1 file định nghĩa các câu lệnh command line của các ngôn ngữ khác là ok.
Vấn đề 3: Làm như thế nào để nhập input vào chương trình ?
Sau một hồi search google sml thì em đã tìm ra 1 cách. Ta sẽ viết input vào 1 file in.txt. Sau này mà 1 bài mà nhiều test case thì sẽ từng ấy file txt
Ví dụ nội dung như sau:
5
Ta sẽ lấy file txt đó làm đầu vào như sau:
./main < in.txt
Vấn đề 4: Giới hạn thời gian kiểu gì ?
Đầu tiên em nghĩ đến hàm setTimeout em quyết định dùng nó để giới hạn thời gian của chương trình.
Ban đầu thì có vẻ ổn nhưng khi em động tới thằng java thì nó lại cứ bị time limit dù chương trình chạy chưa đến 1s (1s là giới hạn em set ở bài đó)
Sau đó em nhận thấy thằng củ cải này compile lâu thế không biết (chắc con vps em cùi). Như hình dưới tổng thời gian là 1.5s vượt quá 1s là đúng rồi.
Vậy khi tính time thì chỉ tính thời gian chạy là được.
Vấn đề 5: Giới hạn bộ nhớ kiểu gì ?
Sau một thời gian tìm hiểu các kiểu con đà điều thì vấn đề này em tạm gác lại 🥲🥲, có lẽ thằng nodejs không xử lý được vấn đề này.
Vấn đề 6: Thế đáp án lưu ở đâu ?
Ban đầu em lưu đáp án vào mysql dưới dạng json. Sau đó em thấy đáp án này thì mình lấy thường xuyên trong 1 khoảng thời gian và em cũng sợ query mysql nó chậm ( làm như database có 1 triệu bản ghi không bằng 🤣🤣)
Sau em sửa lại 1 xíu. Vẫn lưu vào mysql, nhưng sẽ cache bằng memcached.
- Đầu tiên sẽ check dữ liệu có trong memcached không ?
- Nếu có thì lấy dữ liệu trong memcached.
- Nếu không thì query mysql đồng thời lưu vào memcached.
Vấn đề 7: Sanbox
Không loại trừ các trường hợp các sếp viết chương trình chạy command nghịch linh tinh server. Một ngày đẹp trời vào server lỗi vào xem chả còn cái nịt gì thì vui.
Thì em lại ngồi search sml. Em quyết định dùng docker cho nhanh, cho các sếp nghịch tẹt. Mỗi khi có người submit bài em sẽ tạo 1 container môi trường tương ứng với ngôn ngữ người ta gửi lên. Sau đó đọc đầu ra của container, sau đó cho nó bay màu.
Luồng hoạt động sau cùng
- Request đi kèm id, file code, ngôn ngữ
- Khởi tạo container tương ứng với ngôn ngữ của người dùng gửi lên và lấy kết quả của chương trình.
- Tìm đáp án trong memcached và so sánh với đầu ra của chương trình.
- Nếu trong memcached không có đáp án thì query mysql và lưu lại vào memcached.
Đánh giá
- Vấn đề giới hạn thời gian, bộ nhớ chưa ổn cần có giải pháp khác.
- Khởi tạo container và xoá tốn nhiều thời gian. Tổng thời gian chạy 1 file cpp chỉ in "hello world" mất tận 6s.
- 1 bài không chỉ có 1 test case mà sẽ có nhiều test case. Xử lý cái thằng này phần sau em sẽ nói, còn ở hệ thống ban đầu này em xử lý khá ngu =)).
- Có vấn đề nữa là khi có nhiều người submit 1 lúc khả năng hệ thống quá tải 🥲. Em có xem qua các web như leetcode hay codesignal người ta sẽ đá vào queue để xử vấn đề này. (Còn cái con hệ thống dởm của em chắc không cần lo vì chắc gì đã có nhiều người thế 🤣)
Kết: Em vẫn chưa hài lòng lắm về bản V1 này, còn rất nhiều vấn đề cần giải quyết. Sau đó em quyết định đi tìm hiểu xem các opensource người ta xử lý các vấn đề trên như thế nào và viết lại bản V2
Mọi người có thể đọc phần 2 Tại đây
All rights reserved