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
  • Đây là bài viết thứ 366, có nghĩa là mình đã duy trì được việc mỗi ngày một bài trong chuyên mục Threads 1 năm rồi đấy mọi người. Tuy rằng không phải ngày nào cũng viết vì nhiều hôm mình bận, quên thì hôm sau là lên bài bù, mục đích là để cam kết với độc giả, ấy vậy mà quay đi quay lại đã một năm trôi qua rồi. Nhanh thật 😃

    À mai, kia, ngày kìa nữa mình đi du lịch nên chắc không lên bài cho mọi người được. Về rồi mình lên sau nhé 😅. Cảm ơn!

    » Xem thêm
  • Hơn 1 tuần nay mình không đăng bài, không phải không có gì để viết mà đang tìm cách để phân phối nội dung có giá trị hơn trong thời đại AI đang bùng nổ mạnh mẽ như thế này.

    Như từ hồi đầu năm đã chia sẻ, số lượng người truy cập vào trang blog của mình đang dần ít đi. Khi xem thống kê, lượng người dùng trong 6 tháng đầu năm 2025 đã giảm 30% so với cùng kì năm ngoái, 15% so với 6 tháng cuối năm 2024. Như vậy một sự thật là người dùng đang rời bỏ dần đi. Nguyên nhân do đâu?

    Mình nghĩ lý do lớn nhất là thói quen của người dùng đã thay đổi. Họ tìm thấy blog chủ yếu qua các công cụ tìm kiếm, trong đó lớn nhất là Google. Gần 1/2 số lượng người dùng quay trở lại blog mà không cần thông qua bước tìm kiếm. Đó là một tín hiệu đáng mừng nhưng vẫn không đủ để tăng lượng người dùng mới. Chưa kể giờ đây, Google đã ra mắt tính năng AI Search Labs - tức là AI hiển thị luôn nội dung tổng hợp khi người dùng tìm kiếm, điều đó càng khiến cho khả năng người dùng truy cập vào trang web thấp hơn. Một điều thú vị là khi Search Labs được giới thiệu, thì các bài viết bằng tiếng Anh đã soán ngôi trong bảng xếp hạng truy cập nhiều nhất.

    Một bài viết của mình thường rất dài, có khi lên đến cả 2000 chữ. Mà để viết ra được một bài như thế tốn nhiều thời gian. Nhiều bài viết ra chẳng có ai đọc là điều bình thường. Mình biết và chấp nhận vì không phải ai cũng gặp phải vấn đề đang nói đến. Viết đối với mình như một cách để rèn luyện sự kiên nhẫn và cả tư duy. Viết ra mà giúp được cả ai đó là một điều tuyệt vời.

    Vậy nên mình đang nghĩ sẽ tập trung vào nội dung ngắn và trung bình để viết được nhiều hơn. Nội dung dài chỉ khi muốn viết chi tiết hoặc đi sâu về một chủ đề nào đó. Nên là đang tìm cách thiết kế lại trang blog. Mọi người cùng chờ nha 😄

    » Xem thêm
  • CloudFlare đã giới thiệu tính năng pay per crawl để tính phí cho mỗi lần AI "cào" dữ liệu trên trang web của bạn. Là sao ta 🤔?

    Mục đích của SEO là giúp các công cụ tìm kiếm nhìn thấy trang web. Khi người dùng tìm kiếm nội dung mà có liên quan thì nó hiển thị trang web của bạn ra kết quả tìm kiếm. Điều này gần như là đôi bên cùng có lợi khi Google giúp nhiều người biết đến trang web hơn, còn Google thì được nhiều người dùng hơn.

    Bây giờ cuộc chơi với các AI Agents thì lại khác. AI Agents phải chủ động đi tìm kiếm nguồn thông tin và tiện thể "cào" luôn dữ liệu của bạn về, rồi xào nấu hay làm gì đó mà chúng ta cũng chẳng thể biết được. Vậy đây gần như là cuộc chơi chỉ mang lại lợi ích cho 1 bên 🤔!?

    Nước đi của CloudFlare là bắt AI Agents phải trả tiền cho mỗi lần lấy dữ liệu từ trang web của bạn. Nếu không trả tiền thì tôi không cho ông đọc dữ liệu của tôi. Kiểu vậy. Hãy chờ thêm một thời gian nữa xem sao 🤓.

    » 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

5 bài học sâu sắc

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào 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...