Mutex và kỹ thuật giải quyết vấn đề tranh chấp tài nguyên do Race condition gây ra

Mutex và kỹ thuật giải quyết vấn đề tranh chấp tài nguyên do Race condition gây ra

Tin ngắn hàng ngày dành cho bạn
  • Manus đã chính thức mở cửa cho tất cả người dùng rồi đấy mọi người. Cho những ai chưa biết thì đây là một công cụ viết báo cáo (làm mưa làm gió) giống như Deep Research của OpenAI á. Mỗi ngày được miễn phí 300 Credits để nghiên cứu. Mỗi lượt nghiên cứu tiêu tốn tuỳ thuộc vào độ phức tạp của yêu cầu. À với cả họ đang có chương trình tặng miễn phí Credits hay sao á. Như mình thì vào thấy được hẳn 2000.

    Mình dùng thử, so sánh với cùng một lệnh giống như đợt trước dùng bên Deep Research thì nội dung khác biệt nhau hoàn toàn. Manus báo cáo như kiểu viết văn hơn so với OpenAI là các gạch đầu dòng và bảng biểu.

    À lúc đăng ký xong có bắt nhập số điện thoại để xác minh, nếu lỗi thì các bạn đợi qua ngày thử lại xem có được không nhé.

    » Xem thêm
  • Mọi người chắc nghe nhiều về xu hướng tìm kiếm thông tin bằng AI chứ không cần công cụ tìm kiếm như Google nữa rồi đúng không? Không đâu xa ánh xạ vào bản thân thì thấy đúng thật, thi thoảng mới tìm kiếm thôi chứ còn đâu toàn hỏi tụi AI.

    Ngay từ đầu viết blog, thứ mà mình hướng đến là chia sẻ kinh nghiệm chứ không phải là những bài mang nặng tính kỹ thuật, máy móc, hướng dẫn từ đầu... Vì thời điểm đó đã có quá nhiều người làm nội dung này rồi và họ làm rất tốt, tại sao mình phải cố phát minh lại bánh xe? Một điều nữa là tin tưởng độc giả của mình có khả năng tìm hiểu vấn đề. Nếu bạn đọc đủ nhiều các bài viết trên blog thì thấy mình luôn cố gắng chèn thêm các liên kết tham khảo ngoài bài viết, nêu ra vấn đề mở và rất ít khi kết luận chắc chắn một điều gì đó.

    Mình đã cố gắng rèn luyện kỹ năng viết, kỹ năng trình bày và cả cách tương tác với độc giả để mang lại giá trị cho họ. Nhiều lúc ngồi lật lại các con số thống kê thấy lượng đọc bài viết tăng lên lại cảm thấy vui. Nhưng khi nguồn truy cập đến từ Google thì lại thấy buồn, vì điều đó chứng tỏ họ biết đến mình chỉ khi đang cố đi tìm giải pháp, có thể họ chỉ đọc chớp nhoáng, may ra tìm được cách giải quyết và thế là đóng cửa sổ trình duyệt rồi đi như một cơn gió.

    Chừng vài tháng đổ lại đây, một điều khiến mình rất vui đó là lượng người truy cập thẳng vào trang chủ mà không thông qua công cụ tìm kiếm đang tăng dần lên, có nhiều hôm lượng truy cập tự nhiên còn cao hơn cả đến từ Google. Điều đó chứng tỏ độc giả đã có thói quen quay lại trang của mình nhiều hơn và họ tìm thấy được giá trị từ blog mang lại. Vui mừng khôn xiết 🤩

    Bên cạnh đó thì lượng truy cập vào chuyên mục Threads - tức là mục mình đang viết bài này đang cao hơn bao giờ hết. Điều đó chứng tỏ xu hướng đi theo tin nhanh là đúng đắn. Mình có thể ngồi cả ngày để viết tin ngắn cho bạn đọc vì nó rất nhanh mà tiện, không tốn công đi tìm tài liệu để viết, không tốn cả thời gian viết nữa, còn mình thì có rất nhiều thứ để chia sẻ 😅. Nhưng không vì thế mà bỏ bê các bài viết dài, vì dài thì có nhiều thông tin để chia sẻ hơn.

    Vài lời tâm sự thế thôi chứ hơn một tháng nay mình chưa viết bài viết mới nào vì công việc bận quá. Xong lâu dần cứ trì hoãn lại thành lười. À với cả tháng 5 này rất thích hợp để đọc các cuốn sách về cách mạng á. Có hôm đọc đến 2 giờ sáng mới đi ngủ 🥱

    » Xem thêm
  • Mình mới nhìn thấy một trang web khá thú vị nói về các cột mốc đáng nhớ trong lịch sử phát triển Internet toàn cầu: Internet Artifacts

    Chỉ từ 1977 - khi Internet còn nằm trong hộp thí nghiệm thì nhìn xem - giờ đây Internet đã khiến mọi thứ phát triển đến mức nào 🫣

    » Xem thêm

Vấn đề

Trong lập trình đôi khi chúng ta phải đối mặt với trường hợp cần ngăn chặn một yêu cầu đang muốn truy cập vào một biến, tệp, hay một cấu trúc dữ liệu nào đó mà yêu cầu khác đang nắm giữ. Nếu để các yêu cầu có quyền truy cập đồng thời vào một tài nguyên, sửa đổi chúng thì nhiều khả năng gây ra nhiều vấn đề hoặc thậm chí là lỗi không hề mong muốn.

Trong môi trường cân bằng tải - tức là cố gắng tạo ra nhiều phiên bản máy chủ giống nhau để tăng khả năng chịu lỗi cũng như xử lý đồng thời nhiều yêu cầu cùng một lúc. Khi đó càng khó ngăn chặn việc tranh chấp tài nguyên hơn bởi vì mỗi máy chủ hoạt động độc lập, rất khó khăn để liên hệ chúng với nhau. Chưa kể đến vấn đề hiệu suất cũng như độ phức tạp khi muốn thiết lập một kênh liên lạc chung.

Vậy phải có cách nào để quản lý được tài nguyên dùng chung chứ? Đó là lúc cần biết đến một thuật ngữ có tên là Mutex. Vậy Mutex là gì? Áp dụng trong trường hợp nào?

Race condition là gì?

Race condition

Race condition xảy ra khi có hai hay nhiều yêu cầu có thể truy cập dữ liệu được chia sẻ và chúng cố gắng thay đổi nó cùng một lúc. Vì thuật toán lập lịch luồng có thể hoán đổi giữa các luồng bất kỳ lúc nào, nên bạn không biết thứ tự mà các luồng sẽ cố gắng truy cập vào dữ liệu được chia sẻ. Do đó, kết quả của sự thay đổi dữ liệu lại phụ thuộc vào thuật toán lập lịch luồng, tức là cả hai luồng đang "chạy đua" để truy cập/thay đổi dữ liệu.

Vì lẽ đó, Race condition có thể gây ra lỗi không mong muốn trong lập trình, cần phải tìm ra cách để giải quyết việc tranh chấp này. Hay chí ít là phải xác định được yêu cầu nào có quyền thao tác với dữ liệu, loại bỏ yêu cầu còn lại hoặc chờ cho yêu cầu trước đó hoàn thành. Đó là lí do Mutex ra đời.

Mutex là gì?

Mutex

Mutex - Mutual Exclusion hay còn gọi là "loại trừ lẫn nhau" được tạo ra nhằm ngăn chặn Race condition. Với mục tiêu một luồng không bao giờ được truy cập vào tài nguyên mà một luồng thực thi đang nắm giữ.

Tài nguyên được chia sẻ là một đối tượng dữ liệu, mà hai hoặc nhiều luồng đồng thời đang cố gắng sửa đổi. Thuật toán Mutex đảm bảo rằng nếu một quy trình đang chuẩn bị thao tác sửa đổi trên một đối tượng dữ liệu thì không một quy trình/luồng nào khác được phép truy cập hay sửa đổi cho đến khi nó hoàn tất và giải phóng đối tượng để các quy trình khác có thể tiếp tục.

Mutex sử dụng trong trường hợp nào?

Trong lập trình, Mutex được thể hiện tuỳ thuộc vào ngôn ngữ hay công cụ lập trình.

Node.js không có khái niệm rõ ràng về Mutex. Có thể nghe đâu đó Node.js chỉ có một luồng vậy thì trường hợp tranh chấp tài nguyên đâu có xảy ra? Thực tế đúng là Node.js chỉ có một luồng và luồng đó được sử dụng để xử lý mã JS, nhưng còn các tác vụ I/O đa số được thực hiện bởi các luồng song song hay còn gọi là Worker Pool có trong libuv, thế nên vẫn có khả năng tranh chấp tài nguyên xảy ra tại đây.

Một số thư viện hỗ trợ triển khai mutex như async-mutex, về cơ bản nó vận dụng các giải pháp đánh dấu một luồng đang truy cập tài nguyên để loại trừ lẫn nhau, sử dụng Promise để chờ đợi cho đến khi được giải phóng (resolve)... Mọi thứ hoạt động, có lẽ vấn đề đáng lo ngại nhất lúc này chỉ là hiệu suất, bởi vì yêu cầu sau phải đợi yêu cầu trước giải phóng tài nguyên. Nhưng hãy dừng lại một chút, đó là trong trường hợp chỉ có 1 máy chủ. Vậy trong trường hợp có nhiều máy chủ hoặc trong môi trường phân tán (distributed) thì làm sao để ngăn chặn tranh chấp?

Môi trường phân tán là môi trường "nhân bản" nhiều phiên bản máy chủ giống nhau, tài nguyên chia sẻ lúc này cũng có thể nằm trong các máy chủ khác nhau. Khi đó những thư viện hỗ trợ liên lạc nội bộ như async-mutex có lẽ không thể giải quyết mutex theo cách thông thường được nữa. Vì chúng không phải tạo ra để xử lý trong trường hợp phân tán.

Thực tế nếu ứng dụng chỉ cần 1 máy chủ thì không cần bận tâm đến trường hợp phân tán này nữa. Nhưng ai biết đâu một ngày nào đó nó phát triển vượt trội, việc nhân bản chúng lên để cân bằng tải là điều khó tránh khỏi. Dù sớm hay muộn đó vẫn là vấn đề cần phải biết cách giải quyết.

Có nhiều cách xử lý tranh chấp trong trường hợp phân tán. Mỗi cách thể hiện ra những ưu nhược điểm để cho từng trường hợp cụ thể. Cách đơn giản nhất là chỉ chạy một máy chủ tập trung xử lý nghiệp vụ liên quan đến tài nguyên chia sẻ. Mô hình này có thể được thể hiện qua việc dùng message queue hay stream... đầy những yêu cầu cần xử lý vào queue và xử lý chúng lần lượt. Dĩ nhiên rằng như thế sẽ không có việc xung đột ở đây nữa.

Nhưng không phải lúc nào cũng có thể xử lý tách biệt như vậy. Trong trường hợp đó cần tìm đến một giải pháp mới. Tận dụng tốc độ của redis để làm kênh trao đổi chẳng hạn. Về cơ bản cách này hoạt động dựa trên nguyên tắc tạo ra một khoá (key) lưu lại trong redis, luồng xử lý nào nhanh tay nắm được khoá sẽ có quyền truy cập vào tài nguyên trước. Sau khi toàn tất nó giải phóng khoá để nhường cho các luồng xử lý tiếp theo.

Bạn có thể tự triển khai một thuật toán Mutex cho riêng mình hoặc sử dụng thư viện có sẵn. warlock hay live-mutex là những ví dụ. Trong khi warlock sử dụng Redis để tạo mối liên kết giữa các dịch vụ thì live-mutex tự triển khai một hệ thống liên kết riêng, theo mô hình client-server. Nhìn chung những thư viện này có thể đáp ứng nhu cầu ở một mức độ nào đó. Trong một hệ thống thông tin, khả năng "tin cậy", "chịu lỗi" và phục hồi sau sự cố luôn là mối quan tâm hàng đầu.

Redis cũng có một sản phẩm có tên là Distributed Locks, mà họ triển khai thuật toán gọi là Redlock, theo mô hình sử dụng nhiều máy chủ redis tuân thủ 2 nguyên tắc "Safety" và "Liveness" cho mức độ tin cậy cao cùng khả năng chịu lỗi trong môi trường phân tán.

Ngoài ra mutex còn được thể hiện trong việc giải quyết xung đột dữ liệu ở các dịch vụ như là trong cơ sở dữ liệu. Nơi các khoá (locks) phát huy tác dụng. Sử dụng khoá để toàn quyền truy cập vào một bảng hay một hàng dữ liệu và ngăn các truy vấn khác đọc hoặc thay đổi dữ liệu. Có thể tận dụng cơ chế khoá này để giải quyết Race condition, nhưng tài nguyên bị khoá liên tục trong thời gian dài là không mấy hiệu quả, làm giảm hiệu suất hay thậm chí còn gây ra tình trạng deadlock. Khi đó cần phải cân bằng hoặc tìm ra một giải pháp khác sao cho phù hợp hơn.

Tổng kết

Trong lập trình đặc biệt là lập trình trên nhiều luồng xử lý dữ liệu đòi hỏi giải quyết vấn đề tranh chấp tài nguyên. Tranh chấp có thể xảy ra mọi lúc mọi nơi, từ trong một máy chủ hay trong môi trường phân tán. Mutex là một trong những giải pháp ngăn chặn vấn đề này. Tuỳ vào ngôn ngữ lập trình và công cụ sử dụng mà có cách triển khai thuật toán Mutex khác nhau. Có thể tự tạo ra một thuật toán Mutext cho riêng mình hoặc sử dụng thư viện có sẵn để tiết kiệm thời gian mà vẫn mang lại hiệu quả.

Cao cấp
Hello

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...