日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Haproxy+多台MySQL从服务器(Slave) 实现负载均衡

發布時間:2023/12/9 数据库 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Haproxy+多台MySQL从服务器(Slave) 实现负载均衡 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本系統采用MySQL一主多從模式設計,即1臺 MySQL“主”服務器(Master)+多臺“從”服務器(Slave),“從”服務器之間通過Haproxy進行負載均衡,對外只提供一個訪問IP,當程序需要訪問多臺"從"服務器時,只需要訪問Haproxy,再由Haproxy將請求分發到各個數據庫節點。


我們的程序可以有倆個數據源(DataSourceA,DataSourceB),一個(DataSourceA)直接連接主庫,另外一個(DataSourceB)連接Haproxy,當需要寫入操作時可以使用DataSourceA,讀取時使用DataSourceB。


設計圖如下:



看到這里大家可能會有一個疑問,這個問題就是主從數據庫之間數據同步延時的問題!

因為大多數使用MySQL主從同步數據都是異步的,也就是說當主庫的數據發生變化時并不能立即的更新從庫,這么做的目的也是為了更好的性能,那么設想一下,當用戶新增一條記錄后立刻去從庫查詢,可能并不能查到剛剛新增的數據,這豈不是很腦裂的問題~~~。


然而實際情況并不應該是這樣的,我們也不應該這樣去設計程序,我們就拿一個類似于CSND博客管理的系統來說,假設一個“博客系統”只有倆部分, 一部分是博客管理后臺,用戶可以在后臺新增,編輯,刪除博客。另一部分是門戶網站,負責展示所有用戶的博客信息,相對于這樣一個系統來說, 后臺管理模塊對數據庫的操作壓力不是很大,相反門戶網站讀取博客信息對數據庫的壓力很大,這也式一般互聯網產品的特點,而且最重要的一點是系統可以接受主從同步數據帶來的延遲,也就是說當用戶在后臺新增一條博客時,前臺門戶網站并不能立即查詢到這條信息。一般都是再過一段時間后才會出現在首頁,因為大多數系統都有緩存設置,這樣正好給主從同步延遲帶來時間。


接著說上面的問題,有的同學可能會有這樣的疑問,就是后臺用戶在新增一條記錄后,一般都是立即查詢返回博客列表,按照上面說的豈不是查詢不到~~~,我覺得這個問題可以這么解決:

1、后臺用戶在進行 新增,查詢,編輯,刪除等操作時直接連接主庫,這樣無論什么操作都是實時的,因為后臺操作對數據庫的壓力不是很大,所以讀寫全部連接主庫應該沒什么問題!?

2、門戶網站查詢博客列表時從 “從庫集群中查詢“,通過負載均衡技術,解決了擴展性,高可用性等問題,同時門戶網站首頁也不需要實時查詢主庫中的數據,因為網站本身一般都有緩存,也不是實時的。


上面的架構設計只是拋磚引玉,大家有什么好想法也可以相互交流~

本文重點介紹的內容有二點:

1、如何使用Haproxy給MySQL做負載均衡,提供相關的配置說明,健康檢查等等。

2、當程序通過連接Haproxy代理之后,如何解決程序中連接池長連接失效的問題。


下面介紹如何安裝配置Haproxy~

1、首先進行負載均衡配置。

假設兩臺MySQL(slave)從服務器 ?A:192.168.1.191:3306 ? ? ?B:192.168.1.192:3306。


首先在linxu上安裝Haproxy,安裝過程略。。。。。。

安裝完畢后打開配置文件在/etc/haproxy/?haproxy.cfg,配置文件的路徑可能不用,別告訴我找不到~~~!

[html]?view plain?copy?print?

  • global??

  • ????????maxconn?4096??

  • ????????daemon??

  • ????????chroot??????/var/lib/haproxy??

  • ????????pidfile?????/var/run/haproxy.pid??

  • ????????#debug??

  • ????????#quiet??

  • ????????user?haproxy??

  • ????????group?haproxy??

  • ???

  • defaults??

  • ????????log?????global??

  • ????????mode????http??

  • ????????option??httplog??

  • ????????option??dontlognull??

  • ????????log?127.0.0.1?local0??

  • ????????retries?3??

  • ????????option?redispatch??

  • ????????maxconn?2000??

  • ????????#contimeout??????5000??

  • ????????#clitimeout??????50000??

  • ????????#srvtimeout??????50000??

  • ????????timeout?http-request????10s??

  • ????????timeout?queue???????????1m??

  • ????????timeout?connect?????????10s??

  • ????????timeout?client??????????1m??

  • ????????timeout?server??????????1m??

  • ????????timeout?http-keep-alive?10s??

  • ????????timeout?check???????????10s??

  • ???

  • listen??admin_stats?0.0.0.0:8888??

  • ????????mode????????http??

  • ????????stats?uri???/dbs??

  • ????????stats?realm?????Global\?statistics??

  • ????????stats?auth??admin:admin??

  • ???

  • listen??proxy-mysql?0.0.0.0:23306??

  • ????????mode?tcp??

  • ????????balance?roundrobin??

  • ????????option?tcplog??

  • ????????option?mysql-check?user?haproxy?#在mysql中創建無任何權限用戶haproxy,且無密碼??

  • ????????server?MySQL1?192.168.1.191:3306?check?weight?1?maxconn?2000??

  • ????????server?MySQL2?192.168.1.192:3306?check?weight?1?maxconn?2000??

  • ????????option?tcpka??


  • [html]?view plain?copy?print?

  • listen??admin_stats?0.0.0.0:8888?這個配置是監控頁面,綁定到本機8888端口,賬號admin,密碼admin??

  • listen??admin_stats?0.0.0.0:8888?這個配置是監控頁面,綁定到本機8888端口,賬號admin,密碼admin

    可以通過web的方式查看所有MySQL節點的使用情況, http://你的IP:8888/dbs 即可登錄監控后臺。

    如下圖:



    [html]?view plain?copy?print?

  • listen??proxy-mysql?0.0.0.0:23306??

  • ????????mode?tcp??

  • ????????balance?roundrobin??

  • ????????option?tcplog??

  • ????????option?mysql-check?user?haproxy?#在mysql中創建無任何權限用戶haproxy,且無密碼??

  • ????????server?MySQL1?192.168.1.191:3306?check?weight?1?maxconn?2000??

  • ????????server?MySQL2?192.168.1.192:3306?check?weight?1?maxconn?2000??

  • ????????option?tcpka??

  • listen??proxy-mysql?0.0.0.0:23306mode?tcpbalance?roundrobinoption?tcplogoption?mysql-check?user?haproxy?#在mysql中創建無任何權限用戶haproxy,且無密碼server?MySQL1?192.168.1.191:3306?check?weight?1?maxconn?2000server?MySQL2?192.168.1.192:3306?check?weight?1?maxconn?2000option?tcpka

    [html]?view plain?copy?print?

  • </pre><pre?name="code"?class="html">proxy-mysql?0.0.0.0:23306?代理的端口。我們程序連接從庫集群時就訪問這個端口。??

  • </pre><pre?name="code"?class="html">proxy-mysql?0.0.0.0:23306?代理的端口。我們程序連接從庫集群時就訪問這個端口。

    [html]?view plain?copy?print?

  • balance?roundrobin?負載均衡方式,有很多種,可以去Google。??

  • balance?roundrobin?負載均衡方式,有很多種,可以去Google。

    [html]?view plain?copy?print?

  • option?mysql-check?user?haproxy?這里是配置健康檢查的,也是haproxy自帶的功能,<span?style="color:#ff6666;">需要在<span?style="font-family:?Arial,?Helvetica,?sans-serif;">mysql中創建無任何權限用戶haproxy,且無密碼</span></span>??

  • option?mysql-check?user?haproxy?這里是配置健康檢查的,也是haproxy自帶的功能,<span?style="color:#ff6666;">需要在<span?style="font-family:?Arial,?Helvetica,?sans-serif;">mysql中創建無任何權限用戶haproxy,且無密碼</span></span>

    [html]?view plain?copy?print?

  • server?MySQL1?192.168.1.191:3306?check?weight?1?maxconn?2000?配置MySQL從庫節點,有多少配置多少就行了。??

  • server?MySQL1?192.168.1.191:3306?check?weight?1?maxconn?2000?配置MySQL從庫節點,有多少配置多少就行了。



    有的同學可能不知道如何在MySQL中創建用戶,這里也給你寫好了。

    用戶名為haproxy 且無密碼(重要) 否則haproxy無法檢測MySQL狀態。

    CREATE USER 'haproxy'@'%' IDENTIFIED BY '';?


    配置完成后啟動代理 service haproxy start ?如果用過yum方式安裝,應該就能啟動了,如果是其它方式安裝,可能啟動方式不同,需要編寫腳本啟動,應該不難自己研究一下~~~


    然后讓我們寫個demo測試一下代理是否配置成功了沒!


    [java]?view plain?copy?print?

  • public?static?void?main(String[]?args)?throws?Exception?{??

  • ??????

  • ??????

  • ????Class.forName("com.mysql.jdbc.Driver");??

  • ????Connection?conn?=?DriverManager.getConnection("jdbc:mysql://你的IP:23306/template?useUnicode=true",?"root",?"sql2008");??

  • ??????

  • ????for?(int?i?=?0;?i?<?100;?i++)?{??

  • ????????PreparedStatement?pr?=?null;??

  • ????????ResultSet?res?=?null;??

  • ????????try?{??

  • ?????????????pr?=?conn.prepareStatement("select?count(*)?from?sys_user");??

  • ?????????????res?=?pr.executeQuery();??

  • ????????????if(res.next())?{??

  • ????????????????System.out.println(new?Date().toLocaleString()?+?"->"?+?res.getInt(1));??

  • ????????????}??

  • ????????}?catch?(Exception?e)?{??

  • ????????????e.printStackTrace();??

  • ????????????res.close();??

  • ????????????pr.close();??

  • ????????}??

  • ??????????

  • ????????Thread.sleep(25000);??

  • ????}??

  • ??????

  • ????conn.close();??

  • }??

  • public?static?void?main(String[]?args)?throws?Exception?{Class.forName("com.mysql.jdbc.Driver");Connection?conn?=?DriverManager.getConnection("jdbc:mysql://你的IP:23306/template?useUnicode=true",?"root",?"sql2008");for?(int?i?=?0;?i?<?100;?i++)?{PreparedStatement?pr?=?null;ResultSet?res?=?null;try?{pr?=?conn.prepareStatement("select?count(*)?from?sys_user");res?=?pr.executeQuery();if(res.next())?{System.out.println(new?Date().toLocaleString()?+?"->"?+?res.getInt(1));}}?catch?(Exception?e)?{e.printStackTrace();res.close();pr.close();}Thread.sleep(25000);}conn.close();}



    輸出結果如下:可以看到代理MySQL成功了,這時你可以隨機關掉一個MySQL節點的服務,程序依然能夠正常的執行,說明負載均衡也成功了。

    [html]?view plain?copy?print?

  • 2015-8-28?10:09:27->7??

  • 2015-8-28?10:09:52->7??

  • 2015-8-28?10:10:17->7??

  • 2015-8-28?10:10:42->7??

  • 2015-8-28?10:11:07->7??

  • 2015-8-28?10:09:27->7 2015-8-28?10:09:52->7 2015-8-28?10:10:17->7 2015-8-28?10:10:42->7 2015-8-28?10:11:07->7




    小小的激動有沒有~有沒有~。于是乎我們就把程序中數據源的配置改造一下,讓它連接haproxy即可。

    <property name="jdbcUrl" value="jdbc:mysql://你的IP:23306/template?useUnicode=true" /> .

    是不是以為大功告成了,如果你就這樣配置的話,等程序運行起來它就會給你一個大大的surprise

    其實這里面是有坑的~~~~,且聽我細細道來。


    一般的情況下,我相信大家在直接連接MySQL的時候幾乎都用到了連接池。

    以我的配置為例:

    [html]?view plain?copy?print?

  • ??<bean?id="dataSource"?class="com.mchange.v2.c3p0.ComboPooledDataSource"?destroy-method="close">??

  • <property?name="driverClass"?value="com.mysql.jdbc.Driver"?/>??

  • <property?name="jdbcUrl"?value="jdbc:mysql://你的IP:23306/你的數據庫名稱?useUnicode=true"?/>??

  • <property?name="user"?value="xx"?/>??

  • <property?name="password"?value="yy"?/>??

  • <property?name="initialPoolSize"?value="5"?/>??

  • <property?name="minPoolSize"?value="5"?/>??

  • <property?name="maxPoolSize"?value="30"?/>??

  • <property?name="maxIdleTime"?value="0"?/>??

  • <property?name="idleConnectionTestPeriod"?value="30"?/>??

  • <property?name="acquireIncrement"?value="3"?/>??

  • <property?name="automaticTestTable"?value="C3p0TestTable_NotDelete"?/>??

  • <property?name="autoCommitOnClose"?value="false"?/>??

  • lt;/bean>??

  • ????<bean?id="dataSource"?class="com.mchange.v2.c3p0.ComboPooledDataSource"?destroy-method="close"><property?name="driverClass"?value="com.mysql.jdbc.Driver"?/><property?name="jdbcUrl"?value="jdbc:mysql://你的IP:23306/你的數據庫名稱?useUnicode=true"?/><property?name="user"?value="xx"?/><property?name="password"?value="yy"?/><property?name="initialPoolSize"?value="5"?/><property?name="minPoolSize"?value="5"?/><property?name="maxPoolSize"?value="30"?/><property?name="maxIdleTime"?value="0"?/><property?name="idleConnectionTestPeriod"?value="30"?/><property?name="acquireIncrement"?value="3"?/><property?name="automaticTestTable"?value="C3p0TestTable_NotDelete"?/><property?name="autoCommitOnClose"?value="false"?/></bean>


    其它的參數這里不解釋,大家可以查詢C3P0配置信息,網上很多。


    這里只說一個:

    [html]?view plain?copy?print?

  • idleConnectionTestPeriod=30?這個參數是配置連接池?每隔多少時間去檢查池內鏈接的有效性,單位秒。??

  • idleConnectionTestPeriod=30?這個參數是配置連接池?每隔多少時間去檢查池內鏈接的有效性,單位秒。

    [html]?view plain?copy?print?

  • 我這里設置成30秒,那么C3P0會每隔30秒?把連接池內所有的空閑連接拿出來挨個發一個測試SQL語句,已確定這個鏈接的有效性。??

  • 我這里設置成30秒,那么C3P0會每隔30秒?把連接池內所有的空閑連接拿出來挨個發一個測試SQL語句,已確定這個鏈接的有效性。


    以前我們的數據源是直接連接MySQL數據庫的,在正常的情況下MySQL是不會斷開這個鏈接的。

    但是我們現在連接的是haproxy,也就是說我們程序的連接(Connection)是與haproxy建立的,這里的坑在于這個連接是會被haproxy斷掉的,這樣的話你連接池內的鏈接就變成了無效鏈接,在下次需要查詢數據庫時還需要重新創建連接,而且程序由于拿到的連接是無效鏈接,還有可能報錯。


    那么haproxy與我們程序之間的連接超時時間在哪設置呢?

    [html]?view plain?copy?print?

  • timeout?client??????????1m??#這個參數配置程序與haproxy的鏈接超時時間??

  • timeout?server??????????1m??<span?style="font-family:?Arial,?Helvetica,?sans-serif;">#這個參haproxy與mysql鏈接超時時間</span>??

  • ????????timeout?client??????????1m??#這個參數配置程序與haproxy的鏈接超時時間timeout?server??????????1m??<span?style="font-family:?Arial,?Helvetica,?sans-serif;">#這個參haproxy與mysql鏈接超時時間</span>

    這里的超時時間不是指連接過程的超時時間,而是指連接上以后,多少時間內沒有心跳,操作這個時間就認為超時,然后斷開連接。


    寫的可能有些啰嗦,我們看個例子開說明一下:

    [java]?view plain?copy?print?

  • public?static?void?main(String[]?args)?throws?Exception?{??

  • ??????

  • ??????

  • ????Class.forName("com.mysql.jdbc.Driver");??

  • ????Connection?conn?=?DriverManager.getConnection("jdbc:mysql://你的IP:23306/template?useUnicode=true",?"root",?"sql2008");??

  • ??????

  • ????for?(int?i?=?0;?i?<?100;?i++)?{??

  • ????????PreparedStatement?pr?=?null;??

  • ????????ResultSet?res?=?null;??

  • ????????try?{??

  • ?????????????pr?=?conn.prepareStatement("select?count(*)?from?sys_user");??

  • ?????????????res?=?pr.executeQuery();??

  • ????????????if(res.next())?{??

  • ????????????????System.out.println(new?Date().toLocaleString()?+?"->"?+?res.getInt(1));??

  • ????????????}??

  • ????????}?catch?(Exception?e)?{??

  • ????????????e.printStackTrace();??

  • ????????????res.close();??

  • ????????????pr.close();??

  • ????????}??

  • ??????????

  • ????????Thread.sleep(60000);??

  • ????}??

  • ??????

  • ????conn.close();??

  • }??

  • public?static?void?main(String[]?args)?throws?Exception?{Class.forName("com.mysql.jdbc.Driver");Connection?conn?=?DriverManager.getConnection("jdbc:mysql://你的IP:23306/template?useUnicode=true",?"root",?"sql2008");for?(int?i?=?0;?i?<?100;?i++)?{PreparedStatement?pr?=?null;ResultSet?res?=?null;try?{pr?=?conn.prepareStatement("select?count(*)?from?sys_user");res?=?pr.executeQuery();if(res.next())?{System.out.println(new?Date().toLocaleString()?+?"->"?+?res.getInt(1));}}?catch?(Exception?e)?{e.printStackTrace();res.close();pr.close();}Thread.sleep(60000);}conn.close();}




    我上面配置的是?timeout client 1m ,也就是說客戶端連接到haproxy后 1分鐘之內沒有數據請求即為超時,就會斷掉鏈接:

    [html]?view plain?copy?print?

  • <pre?name="code"?class="java"><pre?name="code"?class="java"?style="font-size:18px;">第一次查詢沒有問題:??

  • <pre?name="code"?class="java"><pre?name="code"?class="java"?style="font-size:18px;">第一次查詢沒有問題:

    Thread.sleep(60000); 我把間隔設置為60秒,第二次查詢與第一次查詢間隔60秒就會報錯,因為超時了。



    [java]?view plain?copy?print?

  • 那如果我把間隔改為?<span?style="font-family:?Arial,?Helvetica,?sans-serif;">Thread.sleep(50000);?50秒,就不會報錯。</span>??

  • 那如果我把間隔改為?<span?style="font-family:?Arial,?Helvetica,?sans-serif;">Thread.sleep(50000);?50秒,就不會報錯。</span>



    結論就是

    [html]?view plain?copy?print?

  • idleConnectionTestPeriod?的時間一定要小于?<span?style="font-size:18px;?background-color:?rgb(240,?240,?240);">timeout?client的時間。這樣C3P0會在Haproxy斷掉鏈接之前發送一次“心跳”過去,保持鏈接的有效性。</span>??

  • idleConnectionTestPeriod?的時間一定要小于?<span?style="font-size:18px;?background-color:?rgb(240,?240,?240);">timeout?client的時間。這樣C3P0會在Haproxy斷掉鏈接之前發送一次“心跳”過去,保持鏈接的有效性。</span>

    [html]?view plain?copy?print?

  • <span?style="font-size:18px;?background-color:?rgb(240,?240,?240);">而且?</span><span?style="font-family:?Arial,?Helvetica,?sans-serif;">timeout?client與?</span><span?style="font-family:?Arial,?Helvetica,?sans-serif;">timeout?server?盡量保持一致,已達到最佳效果。</span>??







  • 本文轉自yzy121403725 51CTO博客,原文鏈接:http://blog.51cto.com/lookingdream/1828380,如需轉載請自行聯系原作者


    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的Haproxy+多台MySQL从服务器(Slave) 实现负载均衡的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。