<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>讀寫分離｜林鼎淵 Dean Lin</title>
    <link>https://deanlin.net/tags/%E8%AE%80%E5%AF%AB%E5%88%86%E9%9B%A2/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>讀寫分離｜林鼎淵 Dean Lin</title><link>https://deanlin.net/tags/%E8%AE%80%E5%AF%AB%E5%88%86%E9%9B%A2/</link><width>144</width><height>144</height></image>
    <description>林鼎淵（Dean Lin）的部落格：生成式 AI 企業內訓講師、外商資安公司軟體專家、7 本書作者。400 多篇文章用白話分享生成式 AI 實戰、Claude Code 與 Vibe Coding 教學、團隊合作與職場成長。</description>
    <generator>Hugo</generator>
    <language>zh-tw</language>
    <copyright>© 2020–2026 林鼎淵 Dean Lin</copyright>
    <lastBuildDate>Sun, 03 Oct 2021 07:33:32 +0800</lastBuildDate>
    <atom:link href="https://deanlin.net/tags/%E8%AE%80%E5%AF%AB%E5%88%86%E9%9B%A2/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[面試][資料庫]面對高流量的的系統，會採取哪些措施？</title>
      <link>https://deanlin.net/blog/202110/fullstack-career-notes-day-18/</link>
      <pubDate>Sun, 03 Oct 2021 07:33:32 +0800</pubDate>
      <guid>https://deanlin.net/blog/202110/fullstack-career-notes-day-18/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>除非你的實戰經驗超級豐富，不然在面試時一定會遇到不熟悉的議題；面對無法回答的問題，我個人會老實向面試官表明自己沒有這方面的經驗，會持續學習，瞎掰答案容易讓對方覺得你以後進來公司也會這樣做事。</description>
      <media:content url="https://deanlin.net/blog/202110/fullstack-career-notes-day-18/images/cover_hu_1dbb5eb5480f50de.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<blockquote>
<p>經驗不夠，讀書來湊。</p>
</blockquote>
<p>除非你的實戰經驗超級豐富，不然在面試時一定會遇到不熟悉的議題；面對無法回答的問題，我個人會老實向面試官<mark>表明自己沒有這方面的經驗，會持續學習</mark>，瞎掰答案容易讓對方覺得你以後進來公司也會這樣做事。</p>
<p>不過有些議題雖然實際碰過的人不多，但網路上有很多資源可以學習；如果剛好有研究過相關資料，筆者會回答：「<mark>雖然沒有在工作上使用過，但在下班後我有特別研究這個議題，如果思路上有不對的部分還請各位面試官批評指教。</mark>」</p>
<h2 id="大綱">大綱<a class="h-anchor" href="#%e5%a4%a7%e7%b6%b1" aria-label="這個段落的連結"></a></h2>
<ol>
<li><strong>面對高流量的的系統，會採取哪些措施？</strong>
<ul>
<li>1.1 面試官為什麼會問？</li>
<li>1.2 面試官想從答案確認什麼？</li>
<li>1.3 筆者提供的簡答</li>
</ul>
</li>
<li><strong>回答問題所需具備的知識</strong>
<ul>
<li>2.1 負載平衡（Load Balance）</li>
<li>2.2 主從式架構（Master Slave Repliaction）</li>
<li>2.3 資料庫讀寫分離（read/write splitting）</li>
<li>2.4 垂直切分（vertical-partition）</li>
<li>2.5 水平切分（horizontal-partition）</li>
<li>2.6 分表（Partition Table）</li>
</ul>
</li>
<li><strong>衍伸問題</strong>
<ul>
<li>3.1 有遇過主從複製延遲問題嗎？怎麼解決？</li>
<li>3.2 分散式資料庫（Distributed Database）有哪些優點跟缺點？</li>
</ul>
</li>
</ol>
<hr>
<h2 class="h-nomark" id="1-面對高流量的的系統會採取哪些措施">1. 面對高流量的的系統，會採取哪些措施？<a class="h-anchor" href="#1-%e9%9d%a2%e5%b0%8d%e9%ab%98%e6%b5%81%e9%87%8f%e7%9a%84%e7%9a%84%e7%b3%bb%e7%b5%b1%e6%9c%83%e6%8e%a1%e5%8f%96%e5%93%aa%e4%ba%9b%e6%8e%aa%e6%96%bd" aria-label="這個段落的連結"></a></h2>
<h3 class="h-nomark" id="11-面試官為什麼會問">1.1 面試官為什麼會問？<a class="h-anchor" href="#11-%e9%9d%a2%e8%a9%a6%e5%ae%98%e7%82%ba%e4%bb%80%e9%ba%bc%e6%9c%83%e5%95%8f" aria-label="這個段落的連結"></a></h3>
<p>如果面試的公司在做<mark>金融、電商、社交、媒體</mark>的系統，那這題算是該<mark>職缺所需具備的技術</mark>；儘管也可以透過後天培養，但如果有現成的人才，誰會想要花時間做訓練。</p>
<hr>
<h3 class="h-nomark" id="12-面試官想從答案確認什麼">1.2 面試官想從答案確認什麼？<a class="h-anchor" href="#12-%e9%9d%a2%e8%a9%a6%e5%ae%98%e6%83%b3%e5%be%9e%e7%ad%94%e6%a1%88%e7%a2%ba%e8%aa%8d%e4%bb%80%e9%ba%bc" aria-label="這個段落的連結"></a></h3>
<ul>
<li>要如何設計才能讓前後端伺服器承受大流量情境</li>
<li>資料庫為了處理大流量，可以做哪些調整</li>
<li>這些處理的方式在實務上是否有遇到問題，如何去驗證你的想法是否正確</li>
</ul>
<hr>
<h3 class="h-nomark" id="13-筆者提供的簡答">1.3 筆者提供的簡答<a class="h-anchor" href="#13-%e7%ad%86%e8%80%85%e6%8f%90%e4%be%9b%e7%9a%84%e7%b0%a1%e7%ad%94" aria-label="這個段落的連結"></a></h3>
<p>前後端我會用 <code>Load Balance</code> 緩解 Server 的壓力；在資料庫方面則採取<mark>主從式架構</mark>、<mark>讀寫分離</mark>來降低壓力。</p>
<p>如果經過上面的設計後，資料庫還是無法負荷，可以先用業務種類作為切分條件；以電商系統來說我會先做<mark>垂直切分（vertical-partition）</mark>，像是將商品、訂單、明細拆成 3 個資料庫，以此大幅降低單一資料庫被存取的流量。</p>
<p>如果垂直切分後還是在某個資料庫遇到瓶頸，像是訂單的的資料庫內容遠大於其他資料庫；此時會再做<mark>水平切分（horizontal-partition</mark>），可能會依照訂單的地區再切分成幾個資料庫。</p>
<hr>
<h2 class="h-nomark" id="2-回答問題所需具備的知識">2. 回答問題所需具備的知識<a class="h-anchor" href="#2-%e5%9b%9e%e7%ad%94%e5%95%8f%e9%a1%8c%e6%89%80%e9%9c%80%e5%85%b7%e5%82%99%e7%9a%84%e7%9f%a5%e8%ad%98" aria-label="這個段落的連結"></a></h2>
<h3 class="h-nomark" id="21-負載平衡load-balance">2.1 負載平衡（Load Balance）<a class="h-anchor" href="#21-%e8%b2%a0%e8%bc%89%e5%b9%b3%e8%a1%a1load-balance" aria-label="這個段落的連結"></a></h3>
<p>無論是電商還是媒體的系統，幾乎長時間都要面臨大流量的議題，想當然<mark>一台伺服器是無法承受高流量的</mark>。</p>
<p>而負載平衡（Load Balance）就是為了解決這個問題而誕生的，既然 1 台 Server 無法承受 10 萬流量；那我們就用 100 台 Server 來分散流量吧！</p>
<p>早期做法是先預估流量，然後開啟對應數量的 Server 來作分流；這樣的做法多開頂多浪費錢，但如果估計錯誤少開就可能導致系統當機。</p>
<p>所以像是 <code>GCP、AWS</code> 這類雲端廠商所提供的負載平衡（Load Balance），就有<mark>依照伺服器健康程度來做自動擴展（auto-scaling）</mark>的服務，讓大家不需要去猜要開多少台才合適；如果有使用 <code>Kubernetes</code> 並設定好相關參數，在遇到大流量時也會<mark>自動擴展 Pod</mark> 來應付。</p>
<blockquote>
<p>有時會被問到你的系統過去遇到最高的 QPS 是多少，QPS 指的是每秒查詢率（Queries Per Second）。</p>
</blockquote>
<hr>
<h3 class="h-nomark" id="22-主從式架構master-slave-replication">2.2 主從式架構（Master Slave Replication）<a class="h-anchor" href="#22-%e4%b8%bb%e5%be%9e%e5%bc%8f%e6%9e%b6%e6%a7%8bmaster-slave-replication" aria-label="這個段落的連結"></a></h3>
<p>上面提到的負載平衡只能做到讓網頁成功打開，如果資料庫 Server 沒有做對應的設計，這樣的大流量跟 <code>DDOS</code> 根本沒兩樣，足以讓資料庫 Server 陣亡；所以有時會發現<mark>進入某個網站後可以看到 UI 佈局，卻沒有資料顯示</mark>。</p>
<p>下面我們先探討主從式架構，目標是<mark>先讓資料庫 Server 能承受大流量的檢索</mark>，接著再來考慮寫入問題。</p>
<ul>
<li>
<p><strong>為什麼需要 Master Slave Replication 的架構？</strong></p>
<ul>
<li><strong>網站需要面對大流量</strong><br>有些網站<mark>無論哪個時段都會被大量檢索</mark>，如果資料庫只用一個 Server 來處理會無法負荷高流量。</li>
<li><strong>資料庫內容需要被分析</strong><br>公司如果有<mark>資料分析</mark>部門，他們也會隨時監控資料庫的變化來產生報表，但如果跟一般使用者一樣 query 同一台 Server，會使這台 Server 增加不必要的負荷，甚至導致使用者體驗下降。</li>
</ul>
</li>
<li>
<p><strong>Master Slave Replication 為什麼能夠解決這些問題？</strong></p>
<ul>
<li><strong>主從式架構</strong><br>將資料庫的 Server 區分成 Master(1 台) 與 Slave(N 台) 兩種，<mark>Master 負責資料寫入，Slave 提供資料檢索</mark>；這樣就把壓力分散到幾台 Server 上面。</li>
<li><strong>資料庫同步</strong><br>Slave 會同步 Master 的資料，這樣除了<mark>分散 Server 壓力外，資料也獲得了備份</mark>。</li>
</ul>
</li>
<li>
<p><strong>Master Slave Replication 的架構</strong></p>
<ul>
<li>在 Master 的 Server 執行的 SQL command 會被記錄在 Binary Log 裡面。</li>
<li>Master 將 Binary Log 傳送到 Slave 的 Relay Log。</li>
<li>Slave 依據 Relay Log 做資料的變更。</li>
</ul>
<p><img src="https://deanlin.net/blog/202110/fullstack-career-notes-day-18/images/fullstack-career-notes-day-18-01.webp" width="1024" height="613" alt="2.2 主從式架構（Master Slave Replication）（圖 1）" fetchpriority="high" decoding="async"></p>
<blockquote>
<p>Relay Log 與 Binary Log 檔案格式、內容都一樣，不同在於 Slave 在執行完 Relay Log 的 SQL 之後，會自己刪除當前的 Relay Log。</p>
</blockquote>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="23-資料庫讀寫分離readwrite-splitting">2.3 資料庫讀寫分離（read/write splitting）<a class="h-anchor" href="#23-%e8%b3%87%e6%96%99%e5%ba%ab%e8%ae%80%e5%af%ab%e5%88%86%e9%9b%a2readwrite-splitting" aria-label="這個段落的連結"></a></h3>
<p>我們知道 Master Server 是用來更新資料，Slave Server 是用來檢索資料；但<mark>它們都是獨立的 ip</mark>，使用者在存取資料庫的時候並不知道要使用哪一台 Server ，除非你的 Slave Server 只用來做資料分析。</p>
<p>因此我們要在中間設計一台 <code>Proxy Server</code>，準確地將 SQL 指令分流到正確的 Server。</p>
<p><img src="https://deanlin.net/blog/202110/fullstack-career-notes-day-18/images/fullstack-career-notes-day-18-02.webp" width="1024" height="652" alt="2.3 資料庫讀寫分離（read/write splitting）（圖 2）" loading="lazy" decoding="async"></p>
<blockquote>
<p>媒體類型的平台在讀的需求很高，寫的需求相對低；因此多會採用主從式架構做讀寫分離。</p>
</blockquote>
<hr>
<h3 class="h-nomark" id="24-垂直切分vertical-partition">2.4 垂直切分（vertical-partition）<a class="h-anchor" href="#24-%e5%9e%82%e7%9b%b4%e5%88%87%e5%88%86vertical-partition" aria-label="這個段落的連結"></a></h3>
<p>在讀寫分離後，儘管讀的部分沒有問題；但把寫入的工作交給一個資料庫負責還是會遇到瓶頸。</p>
<p>此時資料庫的垂直切分（vertical-partition）就派上用場了；以商城舉例，商品、訂單、付款明細<mark>各自的業務量都很大</mark>，所以我們可以先依照業務性質把它<mark>拆分成 3 個資料庫</mark>，如此設計可以分散資料庫被存取的流量，來提升系統穩定度。</p>
<hr>
<h3 class="h-nomark" id="25-水平切分horizontal-partition">2.5 水平切分（horizontal-partition）<a class="h-anchor" href="#25-%e6%b0%b4%e5%b9%b3%e5%88%87%e5%88%86horizontal-partition" aria-label="這個段落的連結"></a></h3>
<p>在垂直切分後，有些資料庫還是會遇到瓶頸，像是訂單的資料庫可能遠遠大於其他資料庫。</p>
<p>這時我們就會需要做水平切分（horizontal-partition），將 DB 中<mark>同一類型的資料依據特定邏輯拆分成多個 DB</mark>；像是訂單可能來自於世界各地，所以我們可能就以地區（ex：亞洲、歐洲、美洲&hellip;）做切分的邏輯。</p>
<hr>
<h3 class="h-nomark" id="26-分區表partition-table">2.6 分區表（Partition Table）<a class="h-anchor" href="#26-%e5%88%86%e5%8d%80%e8%a1%a8partition-table" aria-label="這個段落的連結"></a></h3>
<p>資料庫在經歷了垂直切分與水平切分後，寫入遇到的瓶頸就差不多解決了。</p>
<p>但接下來會遇到另外一個問題，Table 中的資料會隨著時間會不斷增長，如果<mark>資料量龐大到就算建立 Index 都無法提升效能</mark>；此時就要考慮將 Table 依照特定邏輯做切割，通常會選擇<mark>自動產生的 id、日期</mark>這類的欄位作為切割依據，在 Table 被切割後因為資料量變少，所以搜尋效能隨之提升。</p>
<p><strong>特別提醒</strong>：如果這個 Table 有 Primary key 或是 Unique key，<mark>分區鍵（Partition Key）必須是 Primary key 或是 Unique key 組成的一個部分</mark>。</p>
<hr>
<h2 class="h-nomark" id="3-衍伸問題">3. 衍伸問題<a class="h-anchor" href="#3-%e8%a1%8d%e4%bc%b8%e5%95%8f%e9%a1%8c" aria-label="這個段落的連結"></a></h2>
<h3 class="h-nomark" id="31-有遇過主從複製延遲問題嗎怎麼解決">3.1 有遇過主從複製延遲問題嗎？怎麼解決？<a class="h-anchor" href="#31-%e6%9c%89%e9%81%87%e9%81%8e%e4%b8%bb%e5%be%9e%e8%a4%87%e8%a3%bd%e5%bb%b6%e9%81%b2%e5%95%8f%e9%a1%8c%e5%97%8e%e6%80%8e%e9%ba%bc%e8%a7%a3%e6%b1%ba" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：瞭解求職者的實務經驗</mark></p>
<p>當時我使用的是 MySQL 資料庫，用 sysbench 這個測試工具模擬<mark>短時間執行大量的 SQL command</mark>（ex：Table 內容大量更新、Index 建立）；但去 Slave 的資料庫確認同步狀況時，卻發現並沒有完全同步 Master 的資料。</p>
<p>經過研究後發現 MySQL 預設的 Process 只有一個，因此累積了很多尚未同步的 SQL Command；將 MySQL 調整成<code>多 Process</code>後，Slave同步的效率就大幅提升了。</p>
<blockquote>
<p>可透過修改「slave_parallel_type、slave_parallel_workers」這兩個變數來調整 Process數量。</p>
</blockquote>
<hr>
<h3 class="h-nomark" id="32-分散式資料庫distributed-database有哪些優點跟缺點">3.2 分散式資料庫（Distributed Database）有哪些優點跟缺點？<a class="h-anchor" href="#32-%e5%88%86%e6%95%a3%e5%bc%8f%e8%b3%87%e6%96%99%e5%ba%abdistributed-database%e6%9c%89%e5%93%aa%e4%ba%9b%e5%84%aa%e9%bb%9e%e8%b7%9f%e7%bc%ba%e9%bb%9e" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：對分散式資料庫的認知程度</mark></p>
<ul>
<li><strong>優點</strong>
<ul>
<li><strong>穩定度與可用性提升</strong><br>過去靠一個資料庫打天下，如果這個資料庫掛了一切都涼了；但建立 Replication 制度後，Slave 資料庫除了可以<mark>分擔流量</mark>，在 Master 資料庫發生問題也可以讓其他 <mark>Slave 資料庫轉成 Master</mark>，不影響整體系統。</li>
<li><strong>擴充性</strong><br>因為資料分散儲存在多個資料庫，如果有更多的需求只要增加伺服器時設定即可。</li>
</ul>
</li>
<li><strong>缺點</strong>
<ul>
<li><strong>開發困難度</strong><br>因為資料分散在各個資料庫，所以對開發人員的經驗以及技術要求更高；如果設計不良反而會影響到資料安全性。</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<p>紙上得來終覺淺，絕知此事要躬行。 ── 陸游</p>
</blockquote>
<p>如果大家想要<mark>親手實作</mark>今天的面試題，在參考資源中有分享一些實作流程喔！</p>
<p>感謝大家的閱讀，如果喜歡我的文章可以<code>訂閱</code>接收通知；如果有幫助到你，按<code>Like</code>可以讓我更有寫文的動力，我們明天見～</p>
<h3 id="參考資源">參考資源<a class="h-anchor" href="#%e5%8f%83%e8%80%83%e8%b3%87%e6%ba%90" aria-label="這個段落的連結"></a></h3>
<ol>
<li><a href="https://medium.com/dean-lin/16d0a0fa1d04">MySQL Master Slave Replication 主從式架構設定教學(筆者部落格)</a></li>
<li><a href="https://medium.com/dean-lin/72759b1b1b33">Ubuntu 用 Atlas 實現 MySQL Proxy 讀寫分離(筆者部落格)</a></li>
<li><a href="https://medium.com/dean-lin/ec59acea6052">用 sysbench 測試 MySQL 性能(筆者部落格)</a></li>
<li><a href="https://medium.com/dean-lin/67c2aec6b021">解決 MySQL 主從複製的延遲問題(筆者部落格)</a></li>
<li><a href="https://ithelp.ithome.com.tw/articles/10227066">30-26 之資料庫層的擴展 - 分庫分表架構</a></li>
<li><a href="https://codingnote.cc/zh-tw/p/215115/">MySQL 分區</a></li>
</ol>
<hr>
<hr>
<blockquote>
<p><img src="https://deanlin.net/blog/202110/fullstack-career-notes-day-18/images/fullstack-career-notes-day-18-03.webp" width="1024" height="233" alt="參考資源（圖 3）" loading="lazy" decoding="async"></p>
<p>在許多人的幫助下，本系列文章已成功出版，除了添加新的篇章，更完善了每個案例的應對進退；如果對現在的職涯感到迷茫，也許這本書能帶給你不一樣的觀點～</p>
<p><strong>天瓏書局：</strong> <a href="https://www.tenlong.com.tw/products/9786263334571">https://www.tenlong.com.tw/products/9786263334571</a></p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Ubuntu 用 Atlas 實現 MySQL Proxy 讀寫分離 read/write splitting</title>
      <link>https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/</link>
      <pubDate>Mon, 29 Mar 2021 08:50:19 +0800</pubDate>
      <guid>https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>技術教學</category>
      <description>如果單純把 DB 分成 Master 及 Slave 並不能真正解決平衡負載問題，因為每台 server 是獨立的 ip，使用者在存取資料庫的時候並不知道要使用哪一台 server 😅；這篇文章會教你如何設定一台 Proxy server，準確地將 SQL 指令正確分流</description>
      <media:content url="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-og_hu_bbca886f617e582f.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<p>在『<a href="https://deanlin.net/blog/202103/mysql-master-slave-replication/">MySQL Master Slave Replication 主從式架構設定教學</a>』這篇文章的結尾有提到如果單純把 DB 分成 Master 及 Slave 並不能真正解決平衡負載問題，因為每台 server 是獨立的 ip，使用者在存取資料庫的時候並不知道要使用哪一台 server 😅 ，除非你的 Slave server 只是用來做資料分析 🤔；這篇文章會教你如何設定一台 Proxy server，準確地將 SQL 指令分流到正確的 server。</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-01.webp" width="1400" height="761" alt="此為設計架構圖" fetchpriority="high" decoding="async">
  <figcaption>此為設計架構圖</figcaption>
</figure>

<pre tabindex="0"><code>一、前置作業
二、MySQL Proxy 的選擇
三、Atlas 功能介紹
四、在 Ubunut 安裝 Atlas
五、連到 Atlas 管理 server
六、實際測試透過 Atlas Proxy 是否達成讀寫分離
</code></pre><h2 id="一前置作業">一、前置作業<a class="h-anchor" href="#%e4%b8%80%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad" aria-label="這個段落的連結"></a></h2>
<blockquote>
<p>OS version、MySQL 是筆者安裝時的環境，ip 是給大家參考對應的</p>
</blockquote>
<h3 id="-準備一台要當-mysql-proxy-的-ubuntu-server">準備一台要當 MySQL Proxy 的 ubuntu server<a class="h-anchor" href="#-%e6%ba%96%e5%82%99%e4%b8%80%e5%8f%b0%e8%a6%81%e7%95%b6-mysql-proxy-%e7%9a%84-ubuntu-server" aria-label="這個段落的連結"></a></h3>
<ul>
<li>OS version：ubuntu 16.04</li>
<li>MySQL：5.7</li>
<li>ip ：172.16.9.39</li>
</ul>
<h3 id="-準備一台-master-server-負責寫入">準備一台 Master server 負責寫入<a class="h-anchor" href="#-%e6%ba%96%e5%82%99%e4%b8%80%e5%8f%b0-master-server-%e8%b2%a0%e8%b2%ac%e5%af%ab%e5%85%a5" aria-label="這個段落的連結"></a></h3>
<ul>
<li>OS version：ubuntu 16.04</li>
<li>MySQL：5.7</li>
<li>ip ：172.16.9.32</li>
</ul>
<h3 id="-準備一台以上的-slave-server-負責讀取">準備一台以上的 Slave server 負責讀取<a class="h-anchor" href="#-%e6%ba%96%e5%82%99%e4%b8%80%e5%8f%b0%e4%bb%a5%e4%b8%8a%e7%9a%84-slave-server-%e8%b2%a0%e8%b2%ac%e8%ae%80%e5%8f%96" aria-label="這個段落的連結"></a></h3>
<blockquote>
<p>準備兩台以上測試 load balance 才會準確，這塊有興趣的讀者可以自己嘗試</p>
</blockquote>
<ul>
<li>OS version：ubuntu 16.04</li>
<li>MySQL：5.7</li>
<li>ip ：172.16.9.32</li>
</ul>
<h3 id="-在-master-server-裡面增加給-proxy-server-使用的使用者並創建測試用-table">在 Master Server 裡面增加給 Proxy server 使用的使用者，並創建測試用 table<a class="h-anchor" href="#-%e5%9c%a8-master-server-%e8%a3%a1%e9%9d%a2%e5%a2%9e%e5%8a%a0%e7%b5%a6-proxy-server-%e4%bd%bf%e7%94%a8%e7%9a%84%e4%bd%bf%e7%94%a8%e8%80%85%e4%b8%a6%e5%89%b5%e5%bb%ba%e6%b8%ac%e8%a9%a6%e7%94%a8-table" aria-label="這個段落的連結"></a></h3>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">/*建立proxy server使用者*/</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span>mysql<span style="color:#ff7b72;font-weight:bold">&gt;</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">CREATE</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">USER</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">&#39;proxy_account&#39;</span><span style="color:#ff7b72;font-weight:bold">@</span><span style="color:#a5d6ff">&#39;%&#39;</span><span style="color:#6e7681"> </span>IDENTIFIED<span style="color:#6e7681"> </span><span style="color:#ff7b72">BY</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">&#39;proxy_password&#39;</span>;<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">/*給使用者權限*/</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span>mysql<span style="color:#ff7b72;font-weight:bold">&gt;</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">GRANT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">ALL</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">ON</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">*</span>.<span style="color:#ff7b72;font-weight:bold">*</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">TO</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">&#39;proxy_account&#39;</span><span style="color:#ff7b72;font-weight:bold">@</span><span style="color:#a5d6ff">&#39;%&#39;</span>;<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">/*使權限生效*/</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span>mysql<span style="color:#ff7b72;font-weight:bold">&gt;</span><span style="color:#6e7681"> </span>FLUSH<span style="color:#6e7681"> </span><span style="color:#ff7b72">PRIVILEGES</span>;<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">/*創建測試用資料庫*/</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">CREATE</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">DATABASE</span><span style="color:#6e7681"> </span>proxy_test;<span style="color:#6e7681">
</span></span></span></code></pre></div><p class="code-source">原始碼：<a href="https://gist.github.com/dean9703111/3c818b9e9a1294cd7e33f108985884e0" rel="noopener">create_proxy_user.sql</a>（GitHub Gist）</p>
<h2 id="二mysql-proxy-的選擇">二、MySQL Proxy 的選擇<a class="h-anchor" href="#%e4%ba%8cmysql-proxy-%e7%9a%84%e9%81%b8%e6%93%87" aria-label="這個段落的連結"></a></h2>
<ul>
<li><strong>MySQL Proxy</strong>：原本想使用官方工具來處理讀寫分離，但一上<strong>官網發現連他自己都不推薦使用</strong>😱，所以就不在多費心力研究。</li>
</ul>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-02.webp" width="1296" height="398" alt="二、MySQL Proxy 的選擇（圖 2）" loading="lazy" decoding="async"></p>
<ul>
<li><strong>MySQL Router</strong>：根據官方的指引認真的研究這個工具後發現雖然設定上簡單，但並不是很符合需求，他的<strong>讀寫分離是同一台伺服器分成兩個 port 來處理</strong>，雖然現在主流框架都支援這樣的操作，但我認為這樣的方式並不優雅</li>
<li><strong>kingshard</strong>：是基於 Go 語言開發的 MySQL Proxy，在 github 上面擁有高人氣；但實際使用心得真的是滿滿的陰影…<strong>官方安裝指引非常的爛</strong>，鬼才知道要自己切換 branch 才能使用啊？設定檔根本要用錯誤嘗試法，沒說清楚必填選填，上面這些問題也就罷了，安裝成功後居然告訴我只有 windows 的電腦可以測試 <a href="https://github.com/flike/kingshard/issues/591#issuecomment-776367532">mac 電腦不行</a>😡，作者是在開玩笑嗎？總之我非常的不推薦。</li>
<li><strong>Atlas</strong>：是基於 MySQL-Proxy 0.8.2 版本開發的工具，由 360 公司推出，在 github 上面找到最新的版本是 2015 年推出的，至於為什麼不再更新的理由，360 公司表示因為這個工具已經夠棒了🥴，沒什麼繼續優化的必要性了；事實上這個工具也是筆者最後選用的，儘管安裝過程滿滿的坑😓</li>
</ul>
<h2 id="三atlas-功能介紹">三、Atlas 功能介紹<a class="h-anchor" href="#%e4%b8%89atlas-%e5%8a%9f%e8%83%bd%e4%bb%8b%e7%b4%b9" aria-label="這個段落的連結"></a></h2>
<ol>
<li>讀寫分離</li>
<li>slave server 的 load balance</li>
<li>IP filter</li>
<li>DBA 可以輕鬆的上下線 DB（有指令支持）</li>
<li>自動移除當機的 DB（但如果當機的是 master server，就只剩讀取功能）</li>
</ol>
<h2 id="四在-ubunut-安裝-atlas">四、在 Ubunut 安裝 Atlas<a class="h-anchor" href="#%e5%9b%9b%e5%9c%a8-ubunut-%e5%ae%89%e8%a3%9d-atlas" aria-label="這個段落的連結"></a></h2>
<blockquote>
<p>筆者在安裝過程中感受到滿滿的惡意</p>
</blockquote>
<p><strong>STEP 1</strong>：下載 &amp; 安裝 Atlas</p>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-03.webp" width="1259" height="340" alt="四、在 Ubunut 安裝 Atlas（圖 3）" loading="lazy" decoding="async"></p>
<p>你可以在官方 <a href="https://github.com/Qihoo360/Atlas/releases">github release </a>中找到 deb 的安裝包下載他</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>wget https://github.com/Qihoo360/Atlas/releases/download/2.2/Atlas-2.2-debian6.0-x86_64.deb
</span></span></code></pre></div><p>執行安裝</p>
<pre tabindex="0"><code>dpkg -i Atlas-2.2-debian6.0-x86_64.deb
</code></pre><p><strong>STEP 2</strong>：調整 Atlas 的設定檔</p>
<p>Atlas 的安裝路徑是/usr/local/mysql-proxy ，執行時的參數會參考 conf 目錄下的 test.cnf 檔案</p>
<pre tabindex="0"><code>vi /usr/local/mysql-proxy/conf/test.cnf
</code></pre><p>下面幾個需要特別調整，其他用默認的就可以了</p>
<ul>
<li><strong>proxy-backend-addresses</strong>：填寫 Master server 的 ip</li>
</ul>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-04.webp" width="1196" height="88" alt="四、在 Ubunut 安裝 Atlas（圖 4）" loading="lazy" decoding="async"></p>
<ul>
<li><strong>proxy-read-only-backend-addresses</strong>：填寫 Slave server 的 ip</li>
</ul>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-05.webp" width="1400" height="122" alt="四、在 Ubunut 安裝 Atlas（圖 5）" loading="lazy" decoding="async"></p>
<ul>
<li><strong>pwds</strong>：請使用於前置作業 Master server 新增專門給 Proxy Server 使用的帳號密碼，密碼要用下面的指令作加密</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 前往加密的目錄</span>
</span></span><span style="display:flex;"><span>cd /usr/local/mysql-proxy/bin
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 對密碼加密</span>
</span></span><span style="display:flex;"><span>./encrypt proxy_password
</span></span></code></pre></div><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-06.webp" width="1332" height="126" alt="四、在 Ubunut 安裝 Atlas（圖 6）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-07.webp" width="1400" height="136" alt="四、在 Ubunut 安裝 Atlas（圖 7）" loading="lazy" decoding="async"></p>
<ul>
<li><strong>sql-log</strong>：預設是 OFF 不會紀錄，但為了方便觀察讀寫是否分離，我們將它設定為 REALTIME</li>
</ul>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-08.webp" width="1400" height="138" alt="四、在 Ubunut 安裝 Atlas（圖 8）" loading="lazy" decoding="async"></p>
<p><strong>STEP 3</strong>：啟動 Atlas</p>
<p>輸入下面指令即可啟動 Atlas</p>
<pre tabindex="0"><code>/usr/local/mysql-proxy/bin/mysql-proxyd test start
</code></pre><p>不過應該有 99% 的人會在這個步驟失敗</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-09.webp" width="1400" height="90" alt="這是另外一種啟動方式，反正只是給大家看會有什麼錯誤而已" loading="lazy" decoding="async">
  <figcaption>這是另外一種啟動方式，反正只是給大家看會有什麼錯誤而已</figcaption>
</figure>

<p>你可以在 log 裡面看錯誤訊息</p>
<pre tabindex="0"><code>vi /usr/local/mysql-proxy/log/test.log
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-10.webp" width="1400" height="192" alt="四、在 Ubunut 安裝 Atlas（圖 10）" loading="lazy" decoding="async"></p>
<p><strong>解決方式：</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 安裝套件相關套件</span>
</span></span><span style="display:flex;"><span>apt-get install libmysqlclient-dev
</span></span><span style="display:flex;"><span>apt-get install mysql-client
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載缺失的 libmysqlclient.so.16 套件，我是在這個網站找到的</span>
</span></span><span style="display:flex;"><span>wget http://files.directadmin.com/services/debian_5.0_64/libmysqlclient.so.16
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 將 libmysqlclient.so.16 搬移到 lib 目錄下</span>
</span></span><span style="display:flex;"><span>mv libmysqlclient.so.16 /usr/lib/x86_64-linux-gnu/
</span></span></code></pre></div><p>再次啟動 Atlas</p>
<pre tabindex="0"><code>/usr/local/mysql-proxy/bin/mysql-proxyd test start
</code></pre><p>看到 <strong>OK: MySQL-Proxy of test is started</strong> 的提示就成功嚕！</p>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-11.webp" width="1400" height="73" alt="四、在 Ubunut 安裝 Atlas（圖 11）" loading="lazy" decoding="async"></p>
<p>檢查 Atlas 服務狀態</p>
<pre tabindex="0"><code>/usr/local/mysql-proxy/bin/mysql-proxyd test status
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-12.webp" width="1400" height="104" alt="四、在 Ubunut 安裝 Atlas（圖 12）" loading="lazy" decoding="async"></p>
<h2 id="五連到-atlas-管理-server">五、連到 Atlas 管理 server<a class="h-anchor" href="#%e4%ba%94%e9%80%a3%e5%88%b0-atlas-%e7%ae%a1%e7%90%86-server" aria-label="這個段落的連結"></a></h2>
<p>Atlas 預設的管理 port 為 2345，ip 填寫 Proxy server ip，如果 admin 的帳號密碼沒換就是跟下面一樣</p>
<pre tabindex="0"><code>mysql -h172.16.9.39 -P2345 -uuser -ppwd
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-13.webp" width="1400" height="553" alt="五、連到 Atlas 管理 server（圖 13）" loading="lazy" decoding="async"></p>
<h3 id="-查看-atlas-的管理命令">查看 Atlas 的管理命令<a class="h-anchor" href="#-%e6%9f%a5%e7%9c%8b-atlas-%e7%9a%84%e7%ae%a1%e7%90%86%e5%91%bd%e4%bb%a4" aria-label="這個段落的連結"></a></h3>
<pre tabindex="0"><code>mysql&gt; select * from help;
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-14.webp" width="1400" height="529" alt="查看 Atlas 的管理命令（圖 14）" loading="lazy" decoding="async"></p>
<h3 id="-查看-mysql-讀寫分離設定是否生效">查看 MySQL 讀寫分離設定是否生效<a class="h-anchor" href="#-%e6%9f%a5%e7%9c%8b-mysql-%e8%ae%80%e5%af%ab%e5%88%86%e9%9b%a2%e8%a8%ad%e5%ae%9a%e6%98%af%e5%90%a6%e7%94%9f%e6%95%88" aria-label="這個段落的連結"></a></h3>
<p>rw 為讀寫權限，ro 代表只有讀的權限</p>
<pre tabindex="0"><code>mysql&gt; select * from backends;
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-15.webp" width="942" height="320" alt="查看 MySQL 讀寫分離設定是否生效（圖 15）" loading="lazy" decoding="async"></p>
<p>到這步其實就可以完結撒花惹 😊😊😊😊😊😊</p>
<h2 id="六實際測試透過-atlas-proxy-是否達成讀寫分離">六、實際測試透過 Atlas Proxy 是否達成讀寫分離<a class="h-anchor" href="#%e5%85%ad%e5%af%a6%e9%9a%9b%e6%b8%ac%e8%a9%a6%e9%80%8f%e9%81%8e-atlas-proxy-%e6%98%af%e5%90%a6%e9%81%94%e6%88%90%e8%ae%80%e5%af%ab%e5%88%86%e9%9b%a2" aria-label="這個段落的連結"></a></h2>
<p>Atlas 預設的proxy port 為 1234，ip 填寫 Proxy server ip，登入的帳號密碼填寫你在 Master 申請給 Atlas Proxy 使用的那組</p>
<pre tabindex="0"><code>mysql -h172.16.9.39 -P1234 -uproxy_account -pproxy_password
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-16.webp" width="1400" height="536" alt="六、實際測試透過 Atlas Proxy 是否達成讀寫分離（圖 16）" loading="lazy" decoding="async"></p>
<h3 id="-測試寫入功能">測試寫入功能<a class="h-anchor" href="#-%e6%b8%ac%e8%a9%a6%e5%af%ab%e5%85%a5%e5%8a%9f%e8%83%bd" aria-label="這個段落的連結"></a></h3>
<pre tabindex="0"><code># 先選擇之前創建的測試資料庫
mysql&gt; use proxy_test;
# 創建表並塞入一寫資料
mysql&gt; CREATE TABLE department (id INT,name varchar(50));
mysql&gt; INSERT INTO department VALUES (1, &#39;Sales&#39;);
mysql&gt; INSERT INTO department VALUES (2, &#39;Operator&#39;);
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-17.webp" width="1062" height="308" alt="測試寫入功能（圖 17）" loading="lazy" decoding="async"></p>
<h3 id="-測試讀取功能">測試讀取功能<a class="h-anchor" href="#-%e6%b8%ac%e8%a9%a6%e8%ae%80%e5%8f%96%e5%8a%9f%e8%83%bd" aria-label="這個段落的連結"></a></h3>
<pre tabindex="0"><code># 先選擇之前創建的測試資料庫
mysql&gt; use proxy_test;
# 讀取剛剛創建的 table
mysql&gt; SELECT * FROM department;
</code></pre><p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-18.webp" width="536" height="308" alt="測試讀取功能（圖 18）" loading="lazy" decoding="async"></p>
<h3 id="-觀察-sql-運行的-log">觀察 sql 運行的 log<a class="h-anchor" href="#-%e8%a7%80%e5%af%9f-sql-%e9%81%8b%e8%a1%8c%e7%9a%84-log" aria-label="這個段落的連結"></a></h3>
<blockquote>
<p>記得把 Atla 設定檔的 ssql-log 參數調整為 REALTIME 才會有喔！</p>
</blockquote>
<p>前往 log file</p>
<pre tabindex="0"><code>tail /usr/local/mysql-proxy/log/sql_test.log
</code></pre><p>從下圖我們可以觀察到，負責變更資料庫的是 Master server(172.16.3.32)，讀取的則是 Slave Server(172.16.3.33)，恭喜自己大功告成</p>
<p><img src="https://deanlin.net/blog/202103/mysql-read-write-splitting-atlas/images/mysql-read-write-splitting-atlas-19.webp" width="1400" height="530" alt="觀察 sql 運行的 log（圖 19）" loading="lazy" decoding="async"></p>
<hr>
<p>希望這篇文章有幫助到使用 Ubuntu 架設 MySQL 並且想做到讀寫分離的開發人員，網路上對這塊的資訊相對來說比較零散，有些甚至都是錯誤，整理起來這些文件也真的很費力，如果對你有幫助的話可以幫我按個拍手👏給我一點繼續分享技術文章的動力。</p>
<pre tabindex="0"><code>如果你想了解資料庫主從式架構的設定歡迎參考我的文章：
👍 MySQL Master Slave Replication 主從式架構設定教學
👍 在 MySQL 5.7 解決主從複製的延遲問題
</code></pre><hr>
<p><strong>參考資訊</strong>：<a href="https://web.archive.org/web/20170127083654/http://files.directadmin.com:80/services/debian_5.0_64/libmysqlclient.so.16" title="原網頁已失效，連到網際網路檔案館的存檔">下載libmysqlclient.so.16檔案</a>、<a href="https://www.jianshu.com/p/67d4b34b2af4">讀寫分離測試</a>、<a href="https://zhuanlan.zhihu.com/p/94279867">Mysql访问中间件 — Atlas初探</a>、<a href="https://www.jianshu.com/p/b68e429d09c7">Atlas</a>、<a href="https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md">Atlas Github</a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
