logo

Lộ trình

Khóa học

Tài liệu

Mock Interview

Liên hệ

Quay lại
  • Trang chủ

    /

  • Tài liệu

    /

  • Áp dụng Connection Multiplexing trong ProxySQL để tối ưu kết nối Database
Tài liệu

Áp dụng Connection Multiplexing trong ProxySQL để tối ưu kết nối Database

Ronin Engineer

22 Tháng 8 2025

<p>By <a href="https://www.linkedin.com/in/cndvn/?ref=roninhub.com" rel="noreferrer">Đức Hiếu</a></p><h1 id="1-t%E1%BB%95ng-quan">1. Tổng quan</h1><p><strong>Connection Multiplexing</strong> là một trong những tính năng nổi bật nhất của ProxySQL, giúp giải quyết vấn đề bottleneck về kết nối với hệ thống Database. Khác với connection pooling truyền thống, multiplexing cho phép nhiều frontend connections <strong>chia sẻ</strong> các backend connections thông qua tỷ lệ N:M thay vì 1:1, từ đó <strong>giảm đáng kể áp lực</strong> lên Database layer.</p><h1 id="2-v%E1%BA%A5n-%C4%91%E1%BB%81-v%E1%BB%9Bi-m%C3%B4-h%C3%ACnh-thread-per-connection-c%E1%BB%A7a-mysql">2. Vấn đề với mô hình Thread-per-Connection của MySQL</h1><p>Trong mô hình truyền thống, MySQL sử dụng <strong>thread-per-connection model</strong> - tức là mỗi connection tạo ra một software thread riêng biệt. Điều này dẫn đến các vấn đề sau khi hệ thống scale lên:</p><h2 id="21-v%E1%BA%A5n-%C4%91%E1%BB%81-v%E1%BB%81-t%C3%A0i-nguy%C3%AAn">2.1. Vấn đề về tài nguyên</h2><ul><li><strong>RAM/CPU tăng cao</strong>: Mỗi thread/connection sẽ tiêu thụ một lượng RAM nhất định. số lượng connection càng lớn dẫn đến tổng RAM chiếm càng lớn - có thể nhanh chóng vượt quá RAM server nếu không kiểm soát.</li><li><strong>Context switching overhead</strong>: Càng nhiều thread, CPU càng phải context switching nhiều giữa các thread</li><li><strong>Connection limit</strong>: MySQL có giới hạn max_connections (mặc định 151)</li></ul><h1 id="3-ki%E1%BA%BFn-tr%C3%BAc-hi%E1%BB%87n-t%E1%BA%A1i-v%E1%BB%9Bi-ki%E1%BA%BFn-tr%C3%BAc-k%E1%BA%BFt-h%E1%BB%A3p-proxysql">3. Kiến trúc hiện tại với Kiến trúc kết hợp ProxySQL</h1><h2 id="31-tr%C6%B0%E1%BB%9Dng-h%E1%BB%A3p-th%C3%B4ng-th%C6%B0%E1%BB%9Dng-kh%C3%B4ng-c%C3%B3-proxysql">3.1. Trường hợp thông thường (không có ProxySQL)</h2><figure class="kg-card kg-image-card"><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfkBBshLVVhwv_rIbidG0249XWmIYbrUTHYm0EPdppDKfnJ5_bPi33wZek7CItxCudXgOE_FQuUaM6ijo6bMhziuopKD4rdIWf0bIvJlu9AUIrFK8p2BGjhS9rwSsLW8vn_ekXTgCN2SkS88mOM3TIlabwfzqc?key=3FIgNeqhNE2XstXCW8YizA" class="kg-image" alt="" loading="lazy" width="948" height="715"></figure><p></p><ul><li><em><u>Chú thích:</u></em><ul><li>Frontend connection: connection trên tầng Application</li><li>Backend connection: connection trên tầng Database</li></ul></li></ul><p>Ở hình trên chúng chúng ta có thể thấy các App instances sẽ tạo kết nối trực tiếp tới Database. Giả sử rằng tổng số lượng kết nối từ các App instances tạo ra là 3000 connection thì sẽ tạo ra 3000 threads trên Database</p><p>=&gt; <strong>Tỷ lệ 1:1 (N frontend : N backend)</strong></p><h2 id="32-v%E1%BB%9Bi-proxysql-multiplexing">3.2 Với ProxySQL Multiplexing</h2><figure class="kg-card kg-image-card"><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXczDZSBkvOydJ0GS0CBxZ0pAmKSwO3rw1WfaKXcF80cAOzLkeYa32LM44ol5uy28ykibr0Q-VDP9C2eBpGONHMhjq1ST061rjP69KMhVFgzU1PbYl5TbHag5tf73vnMEd4Do58w7fv8tRkM-D0dLhdE-yCqSzU?key=3FIgNeqhNE2XstXCW8YizA" class="kg-image" alt="" loading="lazy" width="974" height="590"></figure><p>Với hình trên chúng ta có thể thấy tất cả các kết nối từ các App instances sẽ đi tới Database thông qua ProxySQL. Giả sử rằng tổng số lượng kết nối từ các App instances tạo ra là 3000 connection thì lúc này ProxySQL sẽ gom nhóm chia sẻ 3000 connection này đi vào 100 connection mà ProxySQL tạo để đi tới Database. Lúc này thì Database chỉ tạo ra 100 threads.</p><p>=&gt; <strong>Tỷ lệ N:M (3000 frontend : 100 backend)</strong></p><p></p><p>Từ đây chúng ta có thể thấy. Multiplexing giúp giải quyết:</p><ul><li>Giảm connection trực tiếp ở Database. ProxySQL đứng giữa sẽ gom các frontend connections, tái sử dụng và chia sẻ chúng trên một số lượng backend connections cố định. Giúp cho Database <strong>không bị “ngộp” trong hàng ngàn connection</strong>, đảm bảo ổn định hiệu năng và tận dụng tốt tài nguyên server.</li><li>Giúp giữ một tập backend connections<strong> ổn định và tái sử dụng</strong> chúng, thay vì liên tục đóng/mở connection mới. Đảm bảo Database luôn hoạt động trong <strong>ngưỡng tối ưu </strong>về số connection.</li><li>Cho phép nhận và quản lý <strong>hàng ngàn frontend connections </strong>mà không bắt Database phải chịu tải trực tiếp. khả năng “horizontal scaling” tốt hơn. Vì Application không còn lo giới hạn về connection của Database.</li></ul><h1 id="4-connection-multiplexing-vs-connection-pooling">4. Connection Multiplexing vs Connection Pooling</h1> <!--kg-card-begin: html--> <table style="border:none;border-collapse:collapse;"><colgroup><col width="166"><col width="251"><col width="270"></colgroup><tbody><tr style="height:30.75pt"><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:top;padding:6pt 6pt 6pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Tiêu chí</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:top;padding:6pt 6pt 6pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Connection Pooling</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:top;padding:6pt 6pt 6pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Connection Multiplexing</span></p></td></tr><tr style="height:30.75pt"><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Khái niệm cơ bản</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Các kết nối được tạo sẵn và giữ trong pool</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Các kết nối được tái sử dụng linh hoạt giữa nhiều client</span></p></td></tr><tr style="height:30.75pt"><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Tỷ lệ</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">1:1</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">N:M</span><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"> (N client chia sẻ M backend connection)</span></p></td></tr><tr style="height:30.75pt"><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Tài nguyên sử dụng</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Medium </span><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">(do vẫn giữ số connection tương đương với số client)</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Low </span><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">(giảm đáng kể số connection thực tế)</span></p></td></tr><tr style="height:30.75pt"><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Implementation</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Application-level</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Proxy-level</span></p></td></tr><tr style="height:30.75pt"><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Session Isolation</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Full </span><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">(mỗi client có riêng connection, session variables không bị trộn lẫn)</span></p></td><td style="border-left:solid #000000 0.8333325pt;border-right:solid #000000 0.8333325pt;border-bottom:solid #000000 0.8333325pt;border-top:solid #000000 0.8333325pt;vertical-align:middle;padding:5pt 6pt 5pt 6pt;overflow:hidden;overflow-wrap:break-word;"><p dir="ltr" style="line-height:2.057148;margin-top:11pt;margin-bottom:11pt;"><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Conditional </span><span style="font-size:12pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">(nếu client dùng các tính năng như transaction, temp table,... thì multiplexing sẽ bị tắt)</span></p></td></tr></tbody></table> <!--kg-card-end: html--> <p></p><h1 id="5-c%C6%A1-ch%E1%BA%BF-ho%E1%BA%A1t-%C4%91%E1%BB%99ng-c%E1%BB%A7a-multiplexing">5. Cơ chế hoạt động của Multiplexing</h1><h2 id="51-query-processing-flow">5.1. Query Processing Flow</h2><ol><li>Client connection: Application kết nối tới ProxySQL</li><li>Query analysis: ProxySQL phân tích query và session state</li><li>Connection selection: Chọn idle backend connection phù hợp</li><li>Query execution: Gửi query qua backend connection</li><li>Result routing: Route kết quả về đúng client connection</li><li>Connection release: Trả backend connection về pool (nếu có thể) <strong>ngay lập tức và có thể được sử dụng ngay lập tức bởi một frontend connection khác</strong></li></ol><p>Trường hợp <strong>1 frontend connection gửi nhiều câu query</strong> liên tiếp. ProxySQL vẫn sẽ đảm bảo thứ tự thực thi nhưng <strong>có khả năng nằm ở các backend connection khác nhau</strong>.</p><p>Ví dụ: Mình có 2 backend connection có id là 1 và 2. Giả sử ở application mình tạo một connection và thực thi 2 câu query liên tiếp. Lúc này có khả năng rằng câu query đầu tiên được thực thi ở backend connection có id là 1, và câu query thứ 2 có thể được thực thi ở backend connection có id là 2. Mặc dù 2 cầu query đều được gửi từ 1 frontend connection</p><figure class="kg-card kg-image-card"><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdSQLn0tRmfhOxNcBeEtEb8aa0t7KNMvynef6K4WlBJUobaQydmj8il3zaqhdaCM9FsM5FHdpKBtYNB29sD__fBdlJKr617XmzHMz6S4ldPbPz_MgHs4zZmKXjN2hYUIiVwMdnE0MEB0QyZcDgkkfR2Z0wURuI?key=3FIgNeqhNE2XstXCW8YizA" class="kg-image" alt="" loading="lazy" width="1280" height="357"></figure><h2 id="52-v%C3%B4-hi%E1%BB%87u-h%C3%B3a-multiplexing">5.2. Vô hiệu hóa multiplexing</h2><p>Trước khi đi vào phần dưới đây chúng ta cùng làm rõ mối liên hệ giữa transaction và connection trong Database (MySQL InnoDB). Connection của mình trong ngữ cảnh này là backend connection.</p><ul><li>Một transaction luôn phải gắn liền với một connection đến Database. Tức là khi chúng ta START TRANSACTION T1 trên connection C1, <strong>tất cả query trong transaction T1 cần được gửi trong connection C1</strong>.</li><li>Tại sao vậy? vì nó để <strong>đảm bảo tính tuần tự của các query trong 1 transaction</strong>.</li><li>MySQL server quản lý transaction state của T1 tương ứng với C1.</li></ul><p></p><p>Ở phần 5.1 chúng ta có thể thấy, 1 frontend connection (từ Application) có thể gửi tuần tự nhiều câu query. Các câu query này có thể được ProxySQL phân phối sang nhiều backend connection khác nhau.</p><p></p><p><strong>Vấn đề đưa ra:</strong></p><p><em>"Vậy khi code của mình dùng transaction thì sao? Liệu ProxySQL có thể gửi một phần transaction sang backend connection này, phần còn lại sang backend connection khác không?".</em></p><p><strong>Giả sử</strong> trong code Application có luồng sau:</p><ul><li>Step 1: Start transaction.</li><li>Step 2: Insert thông tin student.</li><li>Step 3: Update thông tin class.</li><li>Step 4: Commit</li></ul><p></p><p>Nếu áp dụng multiplexing thì có khả năng: step 1 nằm ở backend connection #1 nhưng step 2 lại nằm ở backend connection #2 và thậm chí step 4 sẽ nằm ở backend connection nào đó khác nữa.&nbsp;</p><p></p><p>Tóm lại nếu áp dụng multiplexing trong trường hợp trên, các câu query trong 1 transaction có thể chạy trên các backend connection khác nhau. Như vậy, điều này <strong>vi phạm nguyên tắc “tất cả query trong transaction cần được gửi trong một connection”</strong>.</p><p></p><p><strong>Nhưng thực tế ProxySQL không làm như vậy</strong>.</p><p>&nbsp;</p><p><strong>Khi phát hiện một kết nối bắt đầu transaction, ProxySQL sẽ tự động disable multiplexing</strong> và gắn backend connection vừa thực thi query `Start transaction` với frontend connection. Nghĩa là:</p><ul><li>Toàn bộ các câu lệnh trong cùng transaction (từ `Start transaction` cho đến khi `Commit` hoặc `Rollback`) sẽ luôn được gửi đến cùng một backend connection duy nhất.</li><li>Chỉ sau khi transaction kết thúc, ProxySQL mới cho phép multiplexing quay lại sử dụng backend connection đó.</li></ul><p><strong>Cơ chế này đảm bảo tính ACID của transaction</strong> và giúp Application hoạt động đúng logic như khi kết nối trực tiếp với Database.</p><p>Ngoài active transaction, <strong>còn có những tình huống khác cũng khiến ProxySQL tạm thời disable multiplexing</strong> (ví dụ khi sử dụng user-defined variables, temporary tables…), để luôn giữ an toàn cho logic của application.</p><h1 id="6-c%C3%A1c-tr%C6%B0%E1%BB%9Dng-h%E1%BB%A3p-multiplexing-b%E1%BB%8B-v%C3%B4-hi%E1%BB%87u-h%C3%B3a">6. Các trường hợp Multiplexing bị vô hiệu hóa</h1><p>Đây là phần <strong>quan trọng nhất</strong> cần hiểu khi triển khai multiplexing: Ở đây mình tóm tắt lại một số thành phần mình thấy thực tế sẽ gặp. Và nếu các bạn muốn biết chi tiết hơn thì có thể xem trên <a href="https://proxysql.com/documentation/multiplexing/?ref=roninhub.com"><u>document của ProxySQL</u></a></p><ul><li><strong>Active Transaction</strong>: Khi transaction active trên một backend connection thì multiplexing bị disable cho đến khi transaction commit/rollback hoặc frontend connection gắn với backend connection đóng kết nối. Ví dụ ở 5.2 mình giải thích rõ vì sao active transaction lại disable multiplexing các bạn có thể xem lại.</li></ul><pre><code class="language-SQL">START TRANSACTION; -- Hoặc SET @@autocommit = 0;</code></pre><ul><li><strong>Table Locks</strong>: Nếu&nbsp; LOCK TABLE, LOCK TABLES or FLUSH TABLES WITH READ LOCK được thực thi, multiplexing được disable cho đến khi UNLOCK TABLES được thực thi</li></ul><pre><code class="language-SQL">LOCK TABLES users READ; -- disable multiplexing UNLOCK TABLES; – enable multiplexing</code></pre><ul><li><strong>GET_LOCK</strong>: Nếu GET_LOCK() được thực thi, multiplexing bị disable và không bao giờ được enable trên backend connection được sử dụng để thực thi</li></ul><pre><code class="language-SQL">SELECT GET_LOCK('my_lock', 10);</code></pre><ul><li><strong>Temporary Tables</strong>: Nếu tạo table tạm, multiplexing bị disable và không bao giờ được enable trên backend connection được sử dụng để tạo bảng tạm.</li></ul><pre><code class="language-SQL">CREATE TEMPORARY TABLE temp_data (id INT);</code></pre><p><em>Lưu ý rằng:</em> <strong>disable multiplexing nhưng không disable routing</strong>. Trong trường hợp bạn triển khải hostgroups trong ProxySQL rất có khả năng gặp lỗi với message là `'schemaname.temporary_tablename' doesn't exist` khi thực thi CREATE TEMPORARY TABLE và thực thi SELECT bảng tạm vừa tạo. Vì multiplexing bị disable còn routing thì không. Khả năng hai statements được gửi tới hai hostgroups khác nhau và lỗi sẽ xảy ra. Để ngăn điều này chúng ta cần tạo các query rules để chuyển hướng (route) các câu liên quan đến temporary table tới cùng một hostgroup cụ thể.</p><ul><li><strong>Specific session/user variables</strong>: Tất cả các query có dùng ký hiệu @ thì multiplexing bị disable và không bao giờ được enable lại</li></ul><p><em>Lưu ý rằng: </em>Nếu bạn select 1 variable (ví dụ: @test_var) và bạn không nhận được kết quả như mong đợi thì rất có thể là do routing. Vấn đề mình đã đề cập ở Temporary Tables phía trên.</p><ul><li><strong>Disable By Configuration</strong>: Với cấu hình global là mysql-multiplexing có khả năng disable và enable multiplexing trên toàn sessions</li></ul><pre><code class="language-SQL">UPDATE global_variables SET variable_value='true'&nbsp; WHERE variable_name='mysql-multiplexing';</code></pre><h1 id="7-delay-parameters">7. Delay Parameters</h1><h2 id="71-t%C3%ACnh-hu%E1%BB%91ng-g%C3%A2y-l%E1%BB%97i-n%E1%BA%BFu-kh%C3%B4ng-delay-multiplexing">7.1. Tình huống gây lỗi nếu không delay multiplexing</h2><ul><li>Giả sử một query INSERT được gửi đến một backend connection A và tạo giá trị auto-increment X.</li><li>Ngay sau đó, app gửi query SELECT LAST_INSERT_ID() để lấy giá trị mới tạo.</li><li>Nếu multiplexing hoạt động bình thường không delay, ProxySQL có thể gửi query &nbsp;LAST_INSERT_ID() lên <em>backend connection B</em> khác, không phải backend connection A đã INSERT.</li><li>Backend B không có thông tin auto-increment mới, trả về sai hoặc NULL.</li><li>App nhận kết quả sai, dẫn đến lỗi logic.</li></ul><h2 id="72-vai-tr%C3%B2-c%E1%BB%A7a-delay-multiplexing-theo-s%E1%BB%91-c%C3%A2u-query-ho%E1%BA%B7c-th%E1%BB%9Di-gian">7.2. Vai trò của delay multiplexing (theo số câu query &nbsp;hoặc thời gian)</h2><ul><li>Khi ProxySQL nhận được kết quả OK packet từ câu INSERT có auto-increment, nó ghi nhận "backend connection này mới tạo auto-increment".</li><li>ProxySQL sau đó sẽ tạm thời disable multiplexing trên kết nối này theo:<ul><li>Số câu query tiếp theo (vd: 5 câu với biến `mysql-auto_increment_delay_multiplex` = 5)</li><li>Hoặc thời gian (vd: 1000 ms với `mysql-connection_delay_multiplex_ms` = 1000)</li></ul></li><li>Trong khoảng delay này, ProxySQL sẽ không dùng backend connection này để phục vụ query multiplex từ các client khác.</li><li>Đồng thời, các query tiếp theo từ cùng một frontend connection (client) sẽ được "gắn" (pinned) hoặc reuse trên đúng backend connection đã tạo auto-increment.</li><li>Vì vậy, khi frontend connection gửi query SELECT LAST_INSERT_ID(), ProxySQL biết phải gửi query đó trên backend connection vừa thực hiện INSERT, đảm bảo giá trị trả về chính xác.</li></ul><pre><code class="language-SQL">-- Delay multiplexing 5 lần query sau khi có auto-increment UPDATE global_variables SET variable_value='5'&nbsp; WHERE variable_name='mysql-auto_increment_delay_multiplex'; -- Delay multiplexing theo thời gian (milliseconds) UPDATE global_variables SET variable_value='1000'&nbsp; WHERE variable_name='mysql-connection_delay_multiplex_ms';</code></pre><h1 id="8-query-rules-control">8. Query Rules Control</h1><p>Query rules trong ProxySQL dùng để điều khiển hành vi xử lý các câu query. Ở trong bài này mình chỉ giới thiệu sơ qua về query rule trong phạm vi multiplexing chứ không đi sâu vào query rules.</p><h2 id="81-m%E1%BB%A5c-%C4%91%C3%ADch-c%E1%BB%A7a-query-rules-trong-ki%E1%BB%83m-so%C3%A1t-multiplexing">8.1. Mục đích của query rules trong kiểm soát multiplexing</h2><p></p><ul><li><strong>Điều chỉnh multiplexing dựa trên kiểu query</strong>: Không phải tất cả các câu query đều phù hợp để multiplexing, ví dụ: câu query sử dụng các user variables hoặc các query cần liên tục trên cùng một backend connection để đảm bảo tính nhất quán.</li><li><strong>Tăng độ chính xác, giảm lỗi</strong>: Bằng cách tắt multiplexing (multiplexing=0) với những câu query đặc biệt (ví dụ SET @var), đảm bảo câu query đó không bị chuyển sang backend connection khác, tránh mất trạng thái connection (ví dụ: user variables).</li><li><strong>Vẫn cho phép multiplexing cho những câu query an toàn</strong>: Ví dụ đơn giản như SELECT thường được phép multiplexing (multiplexing=1) để tăng hiệu năng.</li><li><strong>Kiểm soát nâng cao</strong>: Giá trị multiplexing=2 nghĩa là không disable multiplexing cho các query chứa dấu @ (giả sử câu query cần lấy system variables), cho phép tối ưu mà không gây lỗi.</li></ul><h2 id="82-v%E1%BA%ADy-query-rules-n%C3%A0y-gi%E1%BA%A3i-quy%E1%BA%BFt-v%E1%BA%A5n-%C4%91%E1%BB%81-g%C3%AC">8.2. Vậy query rules này giải quyết vấn đề gì?</h2><ul><li>Giúp ProxySQL thông minh hơn trong việc chọn khi nào nên multiplexing và khi nào không.</li><li>Tránh các lỗi phát sinh do multiplexing, như sai giá trị user variable, hoặc mất đồng bộ kết nối.</li><li>Giúp cân bằng giữa hiệu năng (bằng multiplexing với các query an toàn) và sự chính xác, nhất quán của kết quả (disable multiplexing với các query cần trạng thái connection).</li></ul><pre><code class="language-SQL">-- Rule-based multiplexing control INSERT INTO mysql_query_rules (rule_id, active, match_pattern, multiplexing, apply) VALUES (1, 1, '^SELECT.*', 1, 1),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- Enable cho SELECT (2, 1, '^SET @.*', 0, 1), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- Disable cho user variables (3, 1, '^SELECT @@max_allowed_packet', 2, 1); -- Không disable cho system vars LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;</code></pre><p>Multiplexing values:</p><ul><li>0: Disable multiplexing</li><li>1: Enable multiplexing</li><li>2: Không disable multiplexing cho queries chứa @</li></ul><h1 id="9-k%E1%BA%BFt-lu%E1%BA%ADn">9. Kết luận</h1><p><strong>Connection Multiplexing</strong> trong ProxySQL là công cụ mạnh mẽ để tối ưu hóa hiệu suất Database, đặc biệt quan trọng trong các hệ thống high-concurrency. Tuy nhiên, để triển khai thành công, chúng ta cần:</p><ol><li>Hiểu rõ limitations: Biết khi nào multiplexing bị disable</li><li>Tuning đúng parameters: Đặc biệt là auto-increment delay</li><li>Monitoring thường xuyên: Theo dõi metrics để đảm bảo hiệu quả</li><li>Application design: Thiết kế ứng dụng multiplexing-friendly:<ol><li>Hạn chế sử dụng các session variable và user variable</li><li>Sử dụng START TRANSACTION rõ ràng</li><li>Hạn chế sử dụng các câu query bị phụ thuộc trạng thái connection như LAST_INSERT_ID()</li></ol></li></ol><p>Khi được cấu hình đúng cách, multiplexing có thể giảm 80-90% số lượng backend connections, từ đó cải thiện đáng kể performance và scalability của hệ thống Database.</p><p></p><p>Các nguồn tham khảo thêm:</p><p><a href="https://www.youtube.com/watch?v=nHBmMjGx-J8&ref=roninhub.com"><u>https://www.youtube.com/watch?v=nHBmMjGx-J8</u></a></p><p><a href="https://proxysql.com/documentation/multiplexing/?ref=roninhub.com"><u>https://proxysql.com/documentation/multiplexing/</u></a></p>

By Đức Hiếu

1. Tổng quan

Connection Multiplexing là một trong những tính năng nổi bật nhất của ProxySQL, giúp giải quyết vấn đề bottleneck về kết nối với hệ thống Database. Khác với connection pooling truyền thống, multiplexing cho phép nhiều frontend connections chia sẻ các backend connections thông qua tỷ lệ N:M thay vì 1:1, từ đó giảm đáng kể áp lực lên Database layer.

2. Vấn đề với mô hình Thread-per-Connection của MySQL

Trong mô hình truyền thống, MySQL sử dụng thread-per-connection model - tức là mỗi connection tạo ra một software thread riêng biệt. Điều này dẫn đến các vấn đề sau khi hệ thống scale lên:

2.1. Vấn đề về tài nguyên

  • RAM/CPU tăng cao: Mỗi thread/connection sẽ tiêu thụ một lượng RAM nhất định. số lượng connection càng lớn dẫn đến tổng RAM chiếm càng lớn - có thể nhanh chóng vượt quá RAM server nếu không kiểm soát.
  • Context switching overhead: Càng nhiều thread, CPU càng phải context switching nhiều giữa các thread
  • Connection limit: MySQL có giới hạn max_connections (mặc định 151)

3. Kiến trúc hiện tại với Kiến trúc kết hợp ProxySQL

3.1. Trường hợp thông thường (không có ProxySQL)

  • Chú thích:
    • Frontend connection: connection trên tầng Application
    • Backend connection: connection trên tầng Database

Ở hình trên chúng chúng ta có thể thấy các App instances sẽ tạo kết nối trực tiếp tới Database. Giả sử rằng tổng số lượng kết nối từ các App instances tạo ra là 3000 connection thì sẽ tạo ra 3000 threads trên Database

=> Tỷ lệ 1:1 (N frontend : N backend)

3.2 Với ProxySQL Multiplexing

Với hình trên chúng ta có thể thấy tất cả các kết nối từ các App instances sẽ đi tới Database thông qua ProxySQL. Giả sử rằng tổng số lượng kết nối từ các App instances tạo ra là 3000 connection thì lúc này ProxySQL sẽ gom nhóm chia sẻ 3000 connection này đi vào 100 connection mà ProxySQL tạo để đi tới Database. Lúc này thì Database chỉ tạo ra 100 threads.

=> Tỷ lệ N:M (3000 frontend : 100 backend)

Từ đây chúng ta có thể thấy. Multiplexing giúp giải quyết:

  • Giảm connection trực tiếp ở Database. ProxySQL đứng giữa sẽ gom các frontend connections, tái sử dụng và chia sẻ chúng trên một số lượng backend connections cố định. Giúp cho Database không bị “ngộp” trong hàng ngàn connection, đảm bảo ổn định hiệu năng và tận dụng tốt tài nguyên server.
  • Giúp giữ một tập backend connections ổn định và tái sử dụng chúng, thay vì liên tục đóng/mở connection mới. Đảm bảo Database luôn hoạt động trong ngưỡng tối ưu về số connection.
  • Cho phép nhận và quản lý hàng ngàn frontend connections mà không bắt Database phải chịu tải trực tiếp. khả năng “horizontal scaling” tốt hơn. Vì Application không còn lo giới hạn về connection của Database.

4. Connection Multiplexing vs Connection Pooling

Tiêu chí

Connection Pooling

Connection Multiplexing

Khái niệm cơ bản

Các kết nối được tạo sẵn và giữ trong pool

Các kết nối được tái sử dụng linh hoạt giữa nhiều client

Tỷ lệ

1:1

N:M (N client chia sẻ M backend connection)

Tài nguyên sử dụng

Medium (do vẫn giữ số connection tương đương với số client)

Low (giảm đáng kể số connection thực tế)

Implementation

Application-level

Proxy-level

Session Isolation

Full (mỗi client có riêng connection, session variables không bị trộn lẫn)

Conditional (nếu client dùng các tính năng như transaction, temp table,... thì multiplexing sẽ bị tắt)

5. Cơ chế hoạt động của Multiplexing

5.1. Query Processing Flow

  1. Client connection: Application kết nối tới ProxySQL
  2. Query analysis: ProxySQL phân tích query và session state
  3. Connection selection: Chọn idle backend connection phù hợp
  4. Query execution: Gửi query qua backend connection
  5. Result routing: Route kết quả về đúng client connection
  6. Connection release: Trả backend connection về pool (nếu có thể) ngay lập tức và có thể được sử dụng ngay lập tức bởi một frontend connection khác

Trường hợp 1 frontend connection gửi nhiều câu query liên tiếp. ProxySQL vẫn sẽ đảm bảo thứ tự thực thi nhưng có khả năng nằm ở các backend connection khác nhau.

Ví dụ: Mình có 2 backend connection có id là 1 và 2. Giả sử ở application mình tạo một connection và thực thi 2 câu query liên tiếp. Lúc này có khả năng rằng câu query đầu tiên được thực thi ở backend connection có id là 1, và câu query thứ 2 có thể được thực thi ở backend connection có id là 2. Mặc dù 2 cầu query đều được gửi từ 1 frontend connection

5.2. Vô hiệu hóa multiplexing

Trước khi đi vào phần dưới đây chúng ta cùng làm rõ mối liên hệ giữa transaction và connection trong Database (MySQL InnoDB). Connection của mình trong ngữ cảnh này là backend connection.

  • Một transaction luôn phải gắn liền với một connection đến Database. Tức là khi chúng ta START TRANSACTION T1 trên connection C1, tất cả query trong transaction T1 cần được gửi trong connection C1.
  • Tại sao vậy? vì nó để đảm bảo tính tuần tự của các query trong 1 transaction.
  • MySQL server quản lý transaction state của T1 tương ứng với C1.

Ở phần 5.1 chúng ta có thể thấy, 1 frontend connection (từ Application) có thể gửi tuần tự nhiều câu query. Các câu query này có thể được ProxySQL phân phối sang nhiều backend connection khác nhau.

Vấn đề đưa ra:

"Vậy khi code của mình dùng transaction thì sao? Liệu ProxySQL có thể gửi một phần transaction sang backend connection này, phần còn lại sang backend connection khác không?".

Giả sử trong code Application có luồng sau:

  • Step 1: Start transaction.
  • Step 2: Insert thông tin student.
  • Step 3: Update thông tin class.
  • Step 4: Commit

Nếu áp dụng multiplexing thì có khả năng: step 1 nằm ở backend connection #1 nhưng step 2 lại nằm ở backend connection #2 và thậm chí step 4 sẽ nằm ở backend connection nào đó khác nữa. 

Tóm lại nếu áp dụng multiplexing trong trường hợp trên, các câu query trong 1 transaction có thể chạy trên các backend connection khác nhau. Như vậy, điều này vi phạm nguyên tắc “tất cả query trong transaction cần được gửi trong một connection”.

Nhưng thực tế ProxySQL không làm như vậy.

 

Khi phát hiện một kết nối bắt đầu transaction, ProxySQL sẽ tự động disable multiplexing và gắn backend connection vừa thực thi query `Start transaction` với frontend connection. Nghĩa là:

  • Toàn bộ các câu lệnh trong cùng transaction (từ `Start transaction` cho đến khi `Commit` hoặc `Rollback`) sẽ luôn được gửi đến cùng một backend connection duy nhất.
  • Chỉ sau khi transaction kết thúc, ProxySQL mới cho phép multiplexing quay lại sử dụng backend connection đó.

Cơ chế này đảm bảo tính ACID của transaction và giúp Application hoạt động đúng logic như khi kết nối trực tiếp với Database.

Ngoài active transaction, còn có những tình huống khác cũng khiến ProxySQL tạm thời disable multiplexing (ví dụ khi sử dụng user-defined variables, temporary tables…), để luôn giữ an toàn cho logic của application.

6. Các trường hợp Multiplexing bị vô hiệu hóa

Đây là phần quan trọng nhất cần hiểu khi triển khai multiplexing: Ở đây mình tóm tắt lại một số thành phần mình thấy thực tế sẽ gặp. Và nếu các bạn muốn biết chi tiết hơn thì có thể xem trên document của ProxySQL

  • Active Transaction: Khi transaction active trên một backend connection thì multiplexing bị disable cho đến khi transaction commit/rollback hoặc frontend connection gắn với backend connection đóng kết nối. Ví dụ ở 5.2 mình giải thích rõ vì sao active transaction lại disable multiplexing các bạn có thể xem lại.
START TRANSACTION;
-- Hoặc
SET @@autocommit = 0;
  • Table Locks: Nếu  LOCK TABLE, LOCK TABLES or FLUSH TABLES WITH READ LOCK được thực thi, multiplexing được disable cho đến khi UNLOCK TABLES được thực thi
LOCK TABLES users READ; -- disable multiplexing
UNLOCK TABLES; – enable multiplexing
  • GET_LOCK: Nếu GET_LOCK() được thực thi, multiplexing bị disable và không bao giờ được enable trên backend connection được sử dụng để thực thi
SELECT GET_LOCK('my_lock', 10);
  • Temporary Tables: Nếu tạo table tạm, multiplexing bị disable và không bao giờ được enable trên backend connection được sử dụng để tạo bảng tạm.
CREATE TEMPORARY TABLE temp_data (id INT);

Lưu ý rằng: disable multiplexing nhưng không disable routing. Trong trường hợp bạn triển khải hostgroups trong ProxySQL rất có khả năng gặp lỗi với message là `'schemaname.temporary_tablename' doesn't exist` khi thực thi CREATE TEMPORARY TABLE và thực thi SELECT bảng tạm vừa tạo. Vì multiplexing bị disable còn routing thì không. Khả năng hai statements được gửi tới hai hostgroups khác nhau và lỗi sẽ xảy ra. Để ngăn điều này chúng ta cần tạo các query rules để chuyển hướng (route) các câu liên quan đến temporary table tới cùng một hostgroup cụ thể.

  • Specific session/user variables: Tất cả các query có dùng ký hiệu @ thì multiplexing bị disable và không bao giờ được enable lại

Lưu ý rằng: Nếu bạn select 1 variable (ví dụ: @test_var) và bạn không nhận được kết quả như mong đợi thì rất có thể là do routing. Vấn đề mình đã đề cập ở Temporary Tables phía trên.

  • Disable By Configuration: Với cấu hình global là mysql-multiplexing có khả năng disable và enable multiplexing trên toàn sessions
UPDATE global_variables SET variable_value='true' 
WHERE variable_name='mysql-multiplexing';

7. Delay Parameters

7.1. Tình huống gây lỗi nếu không delay multiplexing

  • Giả sử một query INSERT được gửi đến một backend connection A và tạo giá trị auto-increment X.
  • Ngay sau đó, app gửi query SELECT LAST_INSERT_ID() để lấy giá trị mới tạo.
  • Nếu multiplexing hoạt động bình thường không delay, ProxySQL có thể gửi query  LAST_INSERT_ID() lên backend connection B khác, không phải backend connection A đã INSERT.
  • Backend B không có thông tin auto-increment mới, trả về sai hoặc NULL.
  • App nhận kết quả sai, dẫn đến lỗi logic.

7.2. Vai trò của delay multiplexing (theo số câu query  hoặc thời gian)

  • Khi ProxySQL nhận được kết quả OK packet từ câu INSERT có auto-increment, nó ghi nhận "backend connection này mới tạo auto-increment".
  • ProxySQL sau đó sẽ tạm thời disable multiplexing trên kết nối này theo:
    • Số câu query tiếp theo (vd: 5 câu với biến `mysql-auto_increment_delay_multiplex` = 5)
    • Hoặc thời gian (vd: 1000 ms với `mysql-connection_delay_multiplex_ms` = 1000)
  • Trong khoảng delay này, ProxySQL sẽ không dùng backend connection này để phục vụ query multiplex từ các client khác.
  • Đồng thời, các query tiếp theo từ cùng một frontend connection (client) sẽ được "gắn" (pinned) hoặc reuse trên đúng backend connection đã tạo auto-increment.
  • Vì vậy, khi frontend connection gửi query SELECT LAST_INSERT_ID(), ProxySQL biết phải gửi query đó trên backend connection vừa thực hiện INSERT, đảm bảo giá trị trả về chính xác.
-- Delay multiplexing 5 lần query sau khi có auto-increment
UPDATE global_variables SET variable_value='5' 
WHERE variable_name='mysql-auto_increment_delay_multiplex';

-- Delay multiplexing theo thời gian (milliseconds)
UPDATE global_variables SET variable_value='1000' 
WHERE variable_name='mysql-connection_delay_multiplex_ms';

8. Query Rules Control

Query rules trong ProxySQL dùng để điều khiển hành vi xử lý các câu query. Ở trong bài này mình chỉ giới thiệu sơ qua về query rule trong phạm vi multiplexing chứ không đi sâu vào query rules.

8.1. Mục đích của query rules trong kiểm soát multiplexing

  • Điều chỉnh multiplexing dựa trên kiểu query: Không phải tất cả các câu query đều phù hợp để multiplexing, ví dụ: câu query sử dụng các user variables hoặc các query cần liên tục trên cùng một backend connection để đảm bảo tính nhất quán.
  • Tăng độ chính xác, giảm lỗi: Bằng cách tắt multiplexing (multiplexing=0) với những câu query đặc biệt (ví dụ SET @var), đảm bảo câu query đó không bị chuyển sang backend connection khác, tránh mất trạng thái connection (ví dụ: user variables).
  • Vẫn cho phép multiplexing cho những câu query an toàn: Ví dụ đơn giản như SELECT thường được phép multiplexing (multiplexing=1) để tăng hiệu năng.
  • Kiểm soát nâng cao: Giá trị multiplexing=2 nghĩa là không disable multiplexing cho các query chứa dấu @ (giả sử câu query cần lấy system variables), cho phép tối ưu mà không gây lỗi.

8.2. Vậy query rules này giải quyết vấn đề gì?

  • Giúp ProxySQL thông minh hơn trong việc chọn khi nào nên multiplexing và khi nào không.
  • Tránh các lỗi phát sinh do multiplexing, như sai giá trị user variable, hoặc mất đồng bộ kết nối.
  • Giúp cân bằng giữa hiệu năng (bằng multiplexing với các query an toàn) và sự chính xác, nhất quán của kết quả (disable multiplexing với các query cần trạng thái connection).
-- Rule-based multiplexing control
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, multiplexing, apply) VALUES
(1, 1, '^SELECT.*', 1, 1),                    -- Enable cho SELECT
(2, 1, '^SET @.*', 0, 1),                     -- Disable cho user variables
(3, 1, '^SELECT @@max_allowed_packet', 2, 1); -- Không disable cho system vars
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

Multiplexing values:

  • 0: Disable multiplexing
  • 1: Enable multiplexing
  • 2: Không disable multiplexing cho queries chứa @

9. Kết luận

Connection Multiplexing trong ProxySQL là công cụ mạnh mẽ để tối ưu hóa hiệu suất Database, đặc biệt quan trọng trong các hệ thống high-concurrency. Tuy nhiên, để triển khai thành công, chúng ta cần:

  1. Hiểu rõ limitations: Biết khi nào multiplexing bị disable
  2. Tuning đúng parameters: Đặc biệt là auto-increment delay
  3. Monitoring thường xuyên: Theo dõi metrics để đảm bảo hiệu quả
  4. Application design: Thiết kế ứng dụng multiplexing-friendly:
    1. Hạn chế sử dụng các session variable và user variable
    2. Sử dụng START TRANSACTION rõ ràng
    3. Hạn chế sử dụng các câu query bị phụ thuộc trạng thái connection như LAST_INSERT_ID()

Khi được cấu hình đúng cách, multiplexing có thể giảm 80-90% số lượng backend connections, từ đó cải thiện đáng kể performance và scalability của hệ thống Database.

Các nguồn tham khảo thêm:

https://www.youtube.com/watch?v=nHBmMjGx-J8

https://proxysql.com/documentation/multiplexing/

database
duchieu
connection multiplexing
middle

Bài viết liên quan

ACID - A Deep Dive into Transactions

By @wuan580 Trong thế giới khắc nghiệt của các hệ thống dữ liệu, mọi thứ đều có thể xảy ra: * Phần mềm hoặc phần cứng cơ sở dữ liệu có thể bị lỗi bất cứ lúc nào (kể cả giữa thao tác ghi) * Ứng dụng có thể sập giữa chừng, khi một loạt thao tác vẫn chưa hoàn tất. * Sự cố mạng có thể bất ngờ cắt đứt ứng dụng khỏi cơ sở dữ liệu hoặc một nút cơ sở dữ liệu này khỏi nút khác. * Nhiều client có thể ghi đồng thời, vô tình ghi đè lên thay đổi của nhau. * Client có thể đọc dữ liệu vô nghĩa vì nó chỉ

Transaction trong Store Procedure: Vấn đề gì xảy ra khi quên ROLLBACK?

By Đức Hiếu Store Procedure: Vũ khí hai lưỡi trong tối ưu hóa performance Trong quá trình phát triển phần mềm, chúng ta thường tin rằng Store Procedure là công cụ mạnh mẽ để tối ưu hiệu suất hệ thống. Tuy nhiên, qua trải nghiệm thực tế, mình nhận ra rằng nếu không sử dụng đúng cách, chúng có thể gây ra những vấn đề nghiêm trọng về hiệu năng. Bài viết này chia sẻ một bài học quý giá về trường hợp Store Procedure có thể trở thành nguyên nhân làm chậm hệ thống nếu không được xử lý lỗi đúng cách.

MySQL Thực Thi Lệnh SELECT Như Thế Nào?

select * from Member where CardNo = 1; Nhưng đã bao giờ bạn tự hỏi, điều gì đã diễn ra trong quá trình MySQL thực thi một câu lệnh truy vấn select chưa?

Sự khác biệt giữa Count(*) và Count(1)? Cái nào hiệu quả hơn?

Khi chúng ta đếm các bản ghi trong bảng dữ liệu, chúng ta đã quen với việc sử dụng hàm count để đếm, nhưng có nhiều loại tham số có thể được truyền trong hàm count, chẳng hạn như count(1), count(), count(column), … Vậy sử dụng cái nào là hiệu quả nhất? ngoài ra, có những cách count nào khác?

Java Virtual Thread: Cuộc cách mạng cho lập trình đồng thời

By @wuan.580 Bạn đã bao giờ viết một ứng dụng xử lý hàng ngàn request cùng lúc, và cảm thấy như mình đang chiến đấu với chính Java? Bạn từng dùng ThreadPoolExecutor và vắt óc cân chỉnh số lượng thread cho "vừa đủ dùng", tránh thiếu nhưng cũng không dám dư vì sợ OutOfMemoryError? Bạn từng nhăn mặt khi phải viết những dòng code callback chằng chịt, chỉ để tránh block một luồng? Và rồi đau đầu gỡ bug vì stacktrace rối như tơ vò? Nếu câu trả lời là "có", thì bạn không đơn độc. Và bạn cũng sắp có

Tất cả bài viết
logo

HỘ KINH DOANH LẬP VƯƠNG

Giấy chứng nhận đăng ký doanh nghiệp số: 8656162915-001. Cấp ngày 21/02/2024. Nơi cấp: Sở Kế hoạch và Đầu tư TP. Hà Nội

PHƯƠNG THỨC THANH TOÁN

vnpay

LIÊN HỆ

roninengineer88@gmail.com

0362228388

26 ngõ 156 Hồng Mai, Hai Bà Trưng, Hà Nội

THEO DÕI CHÚNG TÔI

Facebook

Youtube

Tiktok

CHÍNH SÁCH

Chính sách bảo mật

Chính sách thanh toán

Đổi trả/Hoàn tiền

Hướng dẫn thanh toán VNPAY

PHƯƠNG THỨC THANH TOÁN

vnpay

Ronin Engineer 2024