Phân tích chuyên sâu về chức năng Upload Large File: Đến lượt Backend nhờ vả ANH EM FrontEnd

Nội dung bài viết

Video học lập trình mỗi ngày

Bài viết được đưa vào: Phân tích chuyên sâu các tính năng trong hệ thống ứng dụng

Kịch bản upload large file

Khi upload một File chúng tôi nhận thấy với 100Mb thì mất 5 giây, rất nhanh sau đó commit và đưa vào version Prod. Nhưng một sự việc đã xảy ra đó là khách hàng VIP muốn upload File có dung lượng 1Gb.

Như vậy theo logic thì 5 * 10 = 50 seconds mới có thể upload được File. Sự phàn nàn là điều chính xác.

Upload Large File

Trong tình huống này tôi và các bạn sẽ xem xét tình huống như trên, đó chính là xử lý một chức năng rất thực tế Upload Large File In Application.

Đây là phần thứ 9 trong Series: NestJS Backend: Upload Large File, FrontEnd chia nhỏ nhiều File và Backend merge file, hiệu suất cao

Thật ra thuật toán rất đơn giản, tôi có thể mô tả cho bạn thông qua một architect của một vị trí SA - Solution Architecture - Với nhiều thiết kế hệ thống như notifications: Trước hết xem sơ đồ như sau:

Nhờ vào SA mà chúng ta có thể thấy rất dễ hiều cho dù tôi ở level nào đi chăng nữa thì triển khai không phải là khó. Điều đó cho thấy vì sao mức lương của Solution Architecture lạ sao đến thế trong năm nay.

Ngoài ra còn một vị trí nữa rất HOT trong năm nay, bạn biết Có hai vị trí HOT trong năm nay LƯƠNG rất CAO không?

Quan trọng là FrontEnd đã giúp Backend thế nào?

Trước khi đi vào giải thích kiến trúc trên thì bạn có thời gian dành cho mình thì có thể xem thực hành tại đây, ở đó sẽ thực hành với file ~1Gb.

Còn ở đây bạn chú ý có 2 keywords hình thành ở đây. Với vị trí FE thì thì muốn chia nhỏ File LỚN ra thành nhiều File nhỏ thì đầu tiên phải hiểu về cấu trúc của slice(). Tôi trích code ra từ bài thực hành:

const file = inputFile.files[0], chunks = [];
            let startPos = 0;

            while(startPos < file.size){
                chunks.push(file.slice(startPos, startPos + chunkSize))
                startPos += chunkSize;
            }

            if(!chunks.length){
                return
            }

Có nghĩa là bạn phải biết size của file đó là bao nhiêu, và hệ thống nên chia bao nhiêu file từ Size đó. Và bắt đầu size = 0 thì chuẩn bị cắt sử dụng file.slice mà tôi đã nói. Tiếp theo khi cắt xong hãy đưa file vào một Promise để sử dụng Promise.all()để run cùng một lúc

chunks.map((ck, index) => {
                 // multipart/Fromdata
                const data = new FormData();
                const nameFileFinal = fileNameRandom + '-' + file.name + '-' + index
                data.set("name", nameFileFinal);
                // data.set("numFile", 20);
                // [...inputFile.files].forEach(file => {
                //     data.append('files', file)
                // });
                data.append('files', ck)
                // call api 
                // axios.post("http://localhost:3000/user/upload/large-file", data)
                chunkPromise.push(axios.post("http://localhost:3000/user/upload/large-file", data))
                //console.log(">> rs>>", rs)
            })

            // call merge api
            await Promise.all(chunkPromise);

Chính nhờ tài năng của FE, đưa xuống n File với cùng một thời gian, chạy song song cho nên hiệu suất rất tốt. Còn anh em Backend chỉ cần hiểu về một từ khoá đó là fs.createWriteStream(); là có thể merge lại các File. Trích bài thực hành của Backend:


    files.map( file => {
      // get path full
      const filePath = nameDir + '/' + file
      console.log('filePath | ', filePath)
      const streamFile = fs.createReadStream(filePath)
      streamFile.pipe(fs.createWriteStream('uploads/merge/' + fileName, {
        start: startPos
      })).on('finish', () => {
        countFile++
        console.log('countFile | ', countFile)
        if(files.length === countFile){
          fs.rm(nameDir, {
            recursive: true
          }, () => {})  
        }

      })

      startPos += fs.statSync(filePath).size;
    })

    return res.json({
      link: `http://localhost:3000/uploads/merge/${fileName}`,
      fileName
    })

Hãy nhớ rằng, khi đã merge file xong nên xoá những file-index. Bạn có thể tham khảo hơn tại bài thực hành tại đây.

Chúc vui vẻ...

Có thể bạn đã bị missing