天天看點

Maxscale-正确對待讀寫分離(2)

前言

在現在讀寫分離已經是不奇怪了, 基本上有接觸一點MySQL的都會談到要讀寫分離。下面我們以3個方面來探讨一些并且介紹如何使用Maxscale來做适合業務的讀寫分離:

  1. 讀寫分離要怎麼做呢?
  2. 在一個項目當中應該什麼時候接入讀寫分離呢?
  3. 如何正确的使用讀寫分離呢?

讀寫分離要怎麼做

其實讀寫分離最穩定的做法就是直接嵌入到程式中,通過業務程式來直接做判斷哪些SQL需要通路哪個庫。但是往往對于一個開放團隊來說,在一個已有的項目中應入讀寫分離,其實工作量還是有的。特别是在一個公司如果沒有一個很好的程式設計的人員,做讀寫分離将會是無趣找代碼、cpoy代碼并且讓代碼變的維護性變的更差。

插曲:如果有一個比較強的程式設計人員可以将重構讀寫分離的程式達到一兩行代碼搞定(這邊使用程式程式設計的裝飾器和工廠模式配合将會比較合适,當然肯定有更合适的方法)。

當然現在能做的讀寫分離的中間件很多,Maxscale就能夠勝任這樣的工作,Maxscale的Hint解析分發SQL能見讀寫分離做的更加靈活。最主要的是使用Maxscale的Hint最代碼的改造将會減少很多。

注意:這邊有的人會有疑問Maxscale天生不就是做讀寫分離麼,為啥還要用到Hint,别急下面會說道'正确的使用讀寫分離'(可能你的業務預設使用Maxscale讀寫分離就能滿足了)。

做讀寫分離其實在前期和開發溝通是主要一方面,要不斷引導他們如何去做讀寫分離。畢竟一個公司裡面不都是經驗豐富的開發0-2年工作經驗的偏多。

什麼時候接入讀寫分離

在一個新項目開始的時候基本上是以功能為核心,以功能多并且還比較好來搶占市場,來積累一定的使用者,是不穩定的。因為他們在一點點的快速摸索疊代中,過早的引入讀寫分離,會在一定程度上拉長項目的進度(當然這個階段如果有DBA最基本的規範優化還是要有的)。

如果有項目需要重構 或 一般當項目上線一段時間了發現了發現了一般業務的SQL不能滿足業務的發展需要一些花哨的功能來響應市場,但是這些功能編寫出來的SQL會一定程度上會影響到資料庫的運作。這時候就應該規劃讀寫分離的使用。

當然如果對項目的的未來有個比較好的預測,那從項目的開始就使用讀寫分離降低之後接入讀寫分離的成本這是一個正确的做法。比如現在阿裡、移動、電信又要搞一個産品那我覺得可以把讀寫分離提前就搞上,畢竟他們有使用者基礎,隻要産品出來稍微推廣一下壓力就上來了。

正确的使用讀寫分離

要正确的使用讀寫分離,那就必須和實際情況和業務相結合了。

這邊先說使用普通讀寫分離的一個現象:直接通過中間件使用讀寫分離,讓讀都走 slave。在沒啥壓力的時候主從不延時的時候這樣能很好的服務。但是當壓力以上來主從有延時了那麼就有問題了。比如:建立一個商品建立的時候寫的是Master,可是建立成功了一般還要從新查詢一下資料庫資料,并轉跳到編輯頁面。但是這時候主從有延時的時候就讀取不到資料了。

是以一般在查詢清單的時候可以讀slave,但是在精确查找的時候應該是讀master的。當然比較普遍的複雜查詢也放在slave是比較明智的。

Maxscale使用Hint讀寫分離實驗

二話不說在之前環境的基礎上來做接下來的實驗。直接上配置檔案:

主要配置

[Read-Write Service]...

filters=Hint

[Hint]

type=filter

module=hintfilter

1

2

3

4

5

6

7

[Read-Write Service]

...

完整配置

[root@normal_11 ~]# cat /etc/maxscale.cnf ###################################################

# CREATE USER maxscale@'%' IDENTIFIED BY "123456";

# GRANT replication slave, replication client ON *.* TO maxscale@'%';

# GRANT SELECT ON mysql.* TO maxscale@'%';

# GRANT ALL ON maxscale_schema.* TO maxscale@'%';

# GRANT SHOW DATABASES ON *.* TO maxscale@'%';

# groupadd maxscale

# useradd -g maxscale maxscale

# cd /opt

# tar -zxf maxscale-2.0.1.rhel.7.tar.gz

# ln -s /opt/maxscale-2.0.1.rhel.7 /usr/local/maxscale

# chown -R maxscale:maxscale /usr/local/maxscale

# mkdir -p /u01/maxscale/{data,cache,logs,tmp}

# mkdir -p /u01/maxscale/logs/{binlog,trace}

# chown -R maxscale:maxscale /u01/maxscale

# /usr/local/maxscale/bin/maxkeys /u01/maxscale/data/

# /usr/local/maxscale/bin/maxpasswd /u01/maxscale/data/.secrets 123456

###################################################

[maxscale]

# 開啟線程個數,預設為1.設定為auto會同cpu核數相同

threads=auto

# timestamp精度

ms_timestamp=1

# 将日志寫入到syslog中

syslog=1

# 将日志寫入到maxscale的日志檔案中

maxlog=1

# 不将日志寫入到共享緩存中,開啟debug模式時可打開加快速度

log_to_shm=0

# 記錄告警資訊

log_warning=1

# 記錄notice

log_notice=1

# 記錄info

log_info=1

# 不打開debug模式

log_debug=0

# 日志遞增

log_augmentation=1

# 相關目錄設定

basedir=/usr/local/maxscale/

logdir=/u01/maxscale/logs/trace/

datadir=/u01/maxscale/data/

cachedir=/u01/maxscale/cache/

piddir=/u01/maxscale/tmp/

[server1]

type=server

address=192.168.137.21

port=3306

protocol=MySQLBackend

serv_weight=1

[server2]

address=192.168.137.22

serv_weight=3

[server3]

address=192.168.137.23

[MySQL Monitor]

type=monitor

module=mysqlmon

servers=server1,server2,server3

user=maxscale

passwd=1D30C1E689410756D7B82C233FCBF8D9

# 監控心态為 10s

monitor_interval=10000

# 當複制slave全部斷掉時,maxscale仍然可用,将所有的通路指向master節點

detect_stale_master=true

# 監控主從複制延遲,可用後續指定router service的(配置此參數請求會永遠落在 master)

# detect_replication_lag=true

[Read-Only Service]

type=service

router=readconnroute

router_options=slave

# 允許root使用者登入執行

enable_root_user=1

# 查詢權重

weightby=serv_weight

router=readwritesplit

max_slave_connections=100%

# sql語句中的存在變量隻指向master中執行

use_sql_variables_in=master

# 允許主從最大間隔(s)

max_slave_replication_lag=3600

[MaxAdmin Service]

router=cli

[Read-Only Listener]

type=listener

service=Read-Only Service

protocol=MySQLClient

port=4008

[Read-Write Listener]

service=Read-Write Service

port=4006

[MaxAdmin Listener]

service=MaxAdmin Service

protocol=maxscaled

socket=/u01/maxscale/tmp/maxadmin.sock

port=6603

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

[root@normal_11 ~]# cat /etc/maxscale.cnf

編寫​​Python​程式實作Hint讀寫分離

這邊由于在MySQL Client 控制台效果示範不出來,這邊就用程式來示範:

  1. 代碼

在代碼中我們手動指定SELECT讀取Master 在SQL後面加上 -- maxscale route to master

[root@normal_11 tmp]# cat test.py#!/usr/bin/env python

# -*- coding:utf-8 -*-

from sqlalchemy import create_engine

conf = {

'host': '192.168.137.11',

'port': 4006,

'user': 'HH',

'passwd': '<a href="http://www.ttlsa.com/oracle/" title="Oracle"target="_blank">oracle</a>',

'db': 'test',

'charset': 'utf8'

}

# 生成連結資料庫engine

str = ('mysql+mysqldb://{username}:{password}@{host}:{port}/{database}'

'?charset=utf8'.format(username = conf.get('user', ''),

password = conf.get('passwd', ''),

host = conf.get('host', ''),

port = conf.get('port', 3306),

database = conf.get('db', '')))

engine = create_engine(str)

conn = engine.connect()

sql = """

SELECT * from t1; -- maxscale route to master

"""

conn.execute("SET AUTOCOMMIT=1")

conn.execute(sql)

[root@normal_11 tmp]# cat test.py

#!/usr/bin/env python

    'host': '192.168.137.11',

    'port': 4006,

    'user': 'HH',

    'passwd': 'oracle',

    'db': 'test',

    'charset': 'utf8'

            '?charset=utf8'.format(username = conf.get('user', ''),

                                   password = conf.get('passwd', ''),

                                   host = conf.get('host', ''),

                                   port = conf.get('port', 3306),

                                   database = conf.get('db', '')))

  1. 執行

[root@normal_11 tmp]# python test.py

  1. 檢視日志

# 這邊Maxscale路由到手動指定master上2016-11-05 11:34:43.681 [7] info : (route_single_stmt): > Autocommit: [enabled], trx is [not open], cmd: COM_QUERY, type: QUERY_TYPE_READ, stmt:

, Hint: HINT_ROUTE_TO_MASTER

# 這邊Maxscale路由到手動指定master上

2016-11-05 11:34:43.681   [7]  info   : (route_single_stmt): > Autocommit: [enabled], trx is [not open], cmd: COM_QUERY, type: QUERY_TYPE_READ, stmt:

  1. 手動指定 Slave

-- 修改代碼中的查詢語句,讓語句路由到SlaveSELECT * from t1; -- maxscale route to master

-- 修改給

SELECT * from t1; -- maxscale route to slave

-- 修改代碼中的查詢語句,讓語句路由到Slave
  1. 運作代碼 并 産看日志情況

# 這邊Maxscale路由到手動指定slave上2016-11-05 11:48:56.974 [6] info : (route_single_stmt): > Autocommit: [enabled], trx is [not open], cmd: COM_QUERY, type: QUERY_TYPE_READ, stmt:

, Hint: HINT_ROUTE_TO_SLAVE

# 這邊Maxscale路由到手動指定slave上

2016-11-05 11:48:56.974   [6]  info   : (route_single_stmt): > Autocommit: [enabled], trx is [not open], cmd: COM_QUERY, type: QUERY_TYPE_READ, stmt:

總結

Maxscale的Hint功能就能滿足通過業務情況在實作正确的讀寫分離了,并且這對于程式原來說隻需要有使用到SQL語句的地方就好了。