4.2.1.Cài đặt MySQL Proxy
MySQL Proxy có thể cài đặt theo ba cách khác nhau: - Cài đặt MySQL Proxy từ phân phối nhị phân
- Cài đặt MySQL Proxy từ mã nguồn (nếu muốn cài đặt trên các môi trƣờng mà không đƣợc hỗ trợ bởi phân phối nhị phân).
- Cài đặt từ kho Bazaar: phiên bản mới nhất của MySQL Proxy có sẵn trong kho Bazaar này, đây là cách cài đặt tốt nhất để có thể cập nhật phiên bản mới nhất cho MySQL Proxy.
47
Trong khóa luận, tôi cài đặt MySQL Proxy theo cách thứ ba: cài đặt từ kho Bazaar. Để cài đặt MySQL Proxy theo cách này thì cần phải làm theo các bƣớc sau:
Bƣớc 1: Cài đặt các gói phần mềm sau:
bzr 1.10.0 trở lên autoconf 2.56 trở lên automake 1.10 trở lên libevent 1.3 trở lên lua 5.1 trở lên glib2 2.4.0 trở lên pkg-config mysql 5.0 trở lên
Ngoài ra, tùy theo từng hệ điều hành mà có thể cần phải cài các gói sau: lua-devel, glib2-devel, mysql-devel, libffi46, libffi46-devel, libreadline6, readline5-devel
Bƣớc 2: Biên dịch các gói phần mềm:
- Đối với libevent:
# wget https://github.com/downloads/libevent/libevent/libevent-2.0.17-stable.tar.gz # tar zvfx libevent-2.0.17-stable.tar.gz # cd libevent-2.0.17-stable # ./configure # make # make install
- Đối với glib2
# wget http://fossies.org/unix/misc/glib-2.30.2.tar.gz # tar zvfx glib-2.30.2.tar.gz
# cd glib-2.30.2/ # ./configure
48
# make # make install
- Đối với lua
# wget http://www.lua.org/ftp/lua-5.1.5.tar.gz # tar xvfz lua-5.1.5.tar.gz # cd lua-5.1.5/ # make linux # make install # cp /etc/lua.pc /usr/local/lib64/pkgconfig/
- Đối với mysql-proxy
# bzr branch lp:mysql-proxy # tar xvfz mysql-proxy-0.8.2.tar.gz # cd mysql-proxy-0.8.2/ # sh ./autogen.sh #./configure # make # make install # /sbin/ldconfig
Bƣớc 3: Chạy thử MySQL Proxy
# mysql-proxy –V mysql-proxy 0.9.0 chassis: mysql-proxy 0.9.0 glib2: 2.30.2 libevent: 2.0.10-stable LUA: Lua 5.1.4
49 package.path: /usr/local/lib/mysql-proxy/lua/?.lua package.cpath: /usr/local/lib/mysql-proxy/lua/?.so -- modules admin: 0.9.0 proxy: 0.9.0
4.2.2.Cấu hình cho giải pháp replication trong hệ quản trị CSDL MySQL [7] a) Giải pháp replication đơn giản: một master – một slave a) Giải pháp replication đơn giản: một master – một slave
Cấu hình bên master:
Bước 1: Sửa file cấu hình của my.cnf của MySQL:
[mysqld] server-id = 1
log-bin = mysql-bin
log-bin-index = mysql-bin.index
Bước 2: Khởi động lại MySQLD
# /etc/init.d/mysql restart
Bước 3: Tạo ngƣời dùng cho replication:
mysql> CREATE UER „replication_user_name‟@„domain.com/IP address‟ IDENTIFIED BY „replication_password‟;
mysql>GRANT REPLICATION SLAVE ON *.* TO „replication_user_name‟@„domain.com/IP address‟;
mysql>FLUSH PRIVILEGES;
Bước 4: Xem thông tin trạng thái của master
mysql> FLUSH TABLES WITH READ LOCK; mysql> SHOW MASTER STATUS;
50
Cấu hình bên slave:
Bước 1: sửa file cấu hình my.cnf:
[mysqld] server-id = 2
relay-log = slave-relay-bin
relay-log-index = slave-relay-bin.index
Giá trị của server-id có thể là một số nguyên khác, miễn là giá trị này không đƣợc trùng với giá trị của server-id bên master.
Bước 2: Kết nối slave đến master:
Để kết nối slave đến master, có thể sửa trong file cấu hình my.cnf hoặc chạy lệnh nhƣ sau:
mysql > CHANGE MASTER TO
> MASTER_HOST = “master_host_name”, > MASTER_USER = “replication_user_name”, > MASTER_PASSWORD = “replication_password”, > MASTER_LOG_FILE = “mysql-bin.xxxxx”,
> MASTER_LOG_POS = mysql-bin-position;
mysql-bin.xxxxx là tên file mysql-bin và mysql-bin-possition là vị trí của file mysql- bin đƣợc hiển thị trong lệnh SHOW MASTER STATUS bên master.
Bƣớc 3: Chạy slave và kiểm tra trạng thái của slave
mysql > START SLAVE;
mysql > SHOW SLAVE STATUS \G
Slave_IO_State: Connecting to master Master_Host : 10.10.17.40 Master_User : slave2
Master_Port : 3306 Connect_Retry : 60
51 Master_Log_File : mysql-bin.000054 Read_Master_Log_Pos : 480815 Relay_Log_File : slave-relay-bin.000050 Relay_Log_Pos : 4 Relay_Master_Log_File : mysql-bin.000054 Slave_IO_Running : Connecting Slave_SQL_Running : Yes
b) Giải pháp replication master – multi slave
Trong giải pháp này, các bƣớc thực hiện cấu hình ở master và các slave cũng tƣơng tự nhƣ trong mô hình trên. Tuy nhiên, nếu có bao nhiều slave thì trên master phải tạo ra bấy nhiêu ngƣời dùng replication cho các slave, và mỗi slave phải có một server-id riêng biệt.
4.2.3.Kịch bản Lua
MySQL Proxy hoạt động nhờ ngôn ngữ kịch bản Lua, mọi hoạt động của MySQL Proxy nhƣ kết nối đến máy chủ MySQL, nhận các truy vấn từ client, nhận truy vấn trả về từ máy chủ MySQL, lọc ra các truy vấn đọc và ghi,… đƣợc thực hiện do các kịch bản của ngôn ngữ Lua.
Kịch bản quan trọng nhất của MySQL Proxy trong bài toán cân bằng tải là “read- write-splitting.lua” – lọc ra các truy vấn đọc/ghi – đƣợc thực hiện trong hàm read_query(). Các truy vấn đọc – SELECT – gửi đến máy chủ slave, các truy vấn ghi còn lại – CREATE, INSERT, UPDATE, DROP, DELETE – gửi về master. Sau đây là trích đoạn trong kịch bản “read-write-splitting.lua”:
proxy.queries:append(1, packet, { resultset_is_needed = true }) -- read/write splitting
-- send all non-transactional SELECTs to a slave if not is_in_transaction and
52
tokens = tokens or assert(tokenizer.tokenize(cmd.query)) local stmt = tokenizer.first_stmt_token(tokens)
if stmt.token_name == "TK_SQL_SELECT" then is_in_select_calc_found_rows = false local is_insert_id = false
for i = 1, #tokens do
local token = tokens[i]
if not is_in_select_calc_found_rows and (token.token_name ==
"TK_SQL_SQL_CALC_FOUND_ROWS" or (token.token_name == "TK_FUNCTION"
and token.text:upper() == "FOUND_ROWS")) then
is_in_select_calc_found_rows = true elseif not is_insert_id and token.token_name == "TK_FUNCTION"
and token.text:upper() == "LAST_INSERT_ID" then
is_insert_id = true
elseif not is_insert_id and token.token_name == "TK_LITERAL" then
local utext = token.text:upper() if utext == "@@INSERT_ID" then
is_insert_id = true end
53 end
-- we found the two special token, we can't find more if is_insert_id and is_in_select_calc_found_rows then
break end
end
-- if we ask for the last-insert-id we have to ask it on the original -- connection
if is_insert_id then
print(" found a SELECT LAST_INSERT_ID(), going to master") elseif is_in_select_calc_found_rows then
print(" need to calculate the rows, going to master") else -- neither of these two, pick an idle slave
local backend_ndx = lb.idle_ro() if backend_ndx > 0 then proxy.connection.backend_ndx = backend_ndx end end end end 4.2.4.Thử nghiệm
a) Chạy MySQL Proxy
Chạy MySQL Proxy với dòng lệnh sau:
# mysql-proxy --admin-username=root \ > --admin-password=giang \
54 > --admin-address=10.10.17.100:4041 \ > --proxy- address=10.10.17.100:4040\ > --proxy-backend-addresses=10.10.17.40:3306 \ > --proxy-read-only-backend-addresses=10.10.17.5:3306 \ > --admin-lua-script=/home/giangvit/workspace/proxy/admin-script.lua \ > --proxy-lua-script=/home/giangvit/workspace/mysqlProxy/rw4.lua Trong đó:
--admin-username=user_name là tùy chọn xác thực ngƣời dùng cho modul quản trị
--admin-password=password là tùy chọn xác thực mật khẩu cho modul quản trị
--admin-address=host:port là tùy chọn xác định modul quản trị lắng nghe trên tên miền (hoặc địa chỉ IP) nào và cổng nào (mặc định cổng đƣợc lắng nghe là 4041)
--proxy-address=host:port là tùy chọn xác định tên miền (hoặc địa chỉ IP) và cổng (mặc định cổng đƣợc lắng nghe là 4040) của MySQL Proxt
--proxy-backend-addresses=host:port là tùy chọn xác định tên miền (hoặc địa chỉ IP) và cổng của máy chủ MySQL – master – mà MySQL Proxy kết nối tới. Trong trƣờng hợp có nhiều master, có thể chỉ định nhiều tùy chọn này, khi đó các client kết nối đến mỗi master theo giải thuật round-robin. Ví dụ, nếu có hai máy chủ MySQL là master A và B thì xác định hai tùy chọn:
--proxy-backend-addresses=hostA:portA \ --proxy-backend-addresses=hostB:portB
Khi đó, client thứ nhất kết nối đến máy chủ A, client thứ hai kết nối đến máy chủ B, sau đó lại quay về máy chủ A cho kết nối từ client thứ ba…
--proxy-read-only-backend-addresses=host:port là tùy chọn xác định tên miền (hoặc địa chỉ IP) và cổng của máy chủ MySQL chỉ trả lời các truy vấn đọc từ client – máy chủ slave – mà MySQL Proxy kết nối tới. Trong trƣờng hợp có nhiều máy chủ slave thì có thể chỉ định nhiều tùy chọn này, mỗi tùy chọn xác định một máy chủ slave. Khi đó,
55
các client kết nối đến các máy chủ này đƣợc MySQL Proxy chỉ định theo thuật toán cân bằng tải.
--admin-lua-script=file_name là tùy chọn xác định file kịch bản Lua để sử dụng cho modul quản trị proxy.
--proxy-lua-script=file_name là tùy chọn xác định file kịch bản Lua đƣợc nạp vào hành động của MySQL Proxy. Trong trƣờng hợp này, file kịch bản đƣợc sử dụng để cân bằng tải đến các máy chủ MySQL Proxy: read-write-splitting.lua.
b) Client kết nối đến MySQL Proxy
Chạy lệnh mysqlslap với các tham số nhƣ dƣới đây: # mysqlslap --auto-generate-sql \
> --auto-generate-sql-load-type=read \ > --host=10.10.17.100 --port=4040 \ > --concurrency=100 \
> --number-of-queries=100
Trong quá trình kiểm tra, các tùy chọn --concurrency, --number-of-queries có giá trị tăng dần.
Khi kết nối đến máy chủ MySQL, client không biết sự có mặt của MySQL proxy. Client chỉ biết đến một địa chỉ IP duy nhất là địa chỉ IP của MySQL Proxy – 10.10.17.100 – và cổng lắng nghe là 4040. Client nghĩ rằng máy chủ MySQL đang trực tiếp lắng nghe truy vấn của mình.
4.3.PHÂN TÍCH, ĐÁNH GIÁ KẾT QUẢ THỰC NGHIỆM4.3.1.Client gửi truy vấn trực tiếp đến máy chủ MySQL 4.3.1.Client gửi truy vấn trực tiếp đến máy chủ MySQL
Trong mô hình thực nghiệm này, chỉ có duy nhất một MySQL server. Client trực tiếp gửi truy vấn đến server. Lần lƣợt tăng số truy vấn và số client kết nối đến server, thu đƣợc kết quả nhƣ sau:
56
Bảng 2: Kết quả thời gian chạy các truy vấn trong mô hình chỉ có một MySQL server
--number-of-queries --concurrency Average number of seconds to run queries
100 100 5
600 600 35.710
1400 700 45.252
1600 800 Quá tải
b) Hiệu năng của máy
Hình 200: Hiệu năng của server trong mô hình chỉ có duy nhất MySQL server
4.3.2.Mô hình MySQL Proxy – một master – một slave
Mô hình này bao gồm một giải pháp replication với một master và một slave. Máy chủ master có địa chỉ IP và cổng là 10.10.17.40:3306.
Máy chủ slave có địa chỉ IP và công là: 10.10.17.5:3306
MySQL Proxy có địa chỉ IP là 10.10.17.100, lắng nghe trên cổng 4040.
Sử dụng máy có địa chỉ IP là 10.10.17.40 làm client để kết nối đến các máy chủ.
57
Giai đoạn 1 của quá trình công cụ mysqlslap chạy:
Tự động sinh ra lƣợc đồ “mysqlslap”,
Bảng “t1” với ba trƣờng là: id serial, intcol1 INT(32),charcol1 VARCHAR(128) Sinh dữ liệu ngẫu nhiên và chèn vào bảng t1
Toàn bộ các truy vấn từ client gửi đến đƣợc MySQL Proxy gửi về master:
sending to backend : 10.10.17.40:3306 is_slave : false # mysql-proxy --admin-username=root \ > --admin-password=giang \ > --admin-address=10.10.17.100:4041 \ > --proxy- address=10.10.17.100:4040\ > --proxy-backend-addresses=10.10.17.40:3306 \ > --proxy-read-only-backend-addresses=10.10.17.5:3306 \ > --admin-lua-script=/home/giangvit/workspace/proxy/admin-script.lua \ > --proxy-lua-script=/home/giangvit/workspace/mysqlProxy/rw4.lua
2012-05-15 16:47:32: [global] (*) mysql-proxy 0.9.0 started [connect_server] 10.10.17.40:36443 [1].connected_clients = 0 [1].pool.cur_idle = 0 [1].pool.max_idle = 1000000 [1].pool.min_idle = 1 [1].type = 1 [1].state = 0
[1] idle-conns below min-idle [read_query] 10.10.17.40:36443
58 current backend = 0
client default db = client username = root
query = DROP SCHEMA IF EXISTS `mysqlslap` sending to backend : 10.10.17.40:3306
is_slave : false server default db: server username : root in_trans : false in_calc_found : false COM_QUERY : true [read_query] 10.10.17.40:36443 current backend = 0 client default db = client username = root
query = CREATE SCHEMA `mysqlslap` sending to backend : 10.10.17.40:3306 is_slave : false
server default db: server username : root in_trans : false
in_calc_found : false COM_QUERY : true
[read_query] 10.10.17.40:36443 current backend = 0
59 client default db =
client username = root
sending to backend : 10.10.17.40:3306 is_slave : false
server default db: server username : root in_trans : false
in_calc_found : false COM_QUERY : false
[read_query] 10.10.17.40:36443 current backend = 0
client default db = mysqlslap client username = root
query = CREATE TABLE `t1` (id serial,intcol1 INT(32),charcol1 VARCHAR(128)) sending to backend : 10.10.17.40:3306
is_slave : false
server default db: mysqlslap server username : root in_trans : false
in_calc_found : false COM_QUERY : true
[read_query] 10.10.17.40:36443 current backend = 0
client default db = mysqlslap client username = root
60 query = INSERT INTO t1 VALUES
(NULL,1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekb WtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw 1KQ1lT4zg9rdxBL')
sending to backend : 10.10.17.40:3306 is_slave : false
server default db: mysqlslap server username : root in_trans : false
in_calc_found : false COM_QUERY : true
(read_query_result) staying on the same backend in_trans : false
in_calc_found : false have_insert_id : true
61
Giai đoạn 2 của chạy công cụ mysqlslap: tự động sinh ra các truy vấn đọc:
query = SELECT intcol1,charcol1 FROM t1
để kiểm tra tải của hai máy chủ master và slave. Toàn bộ các truy vấn này đƣợc gửi về slave:
sending to backend : 10.10.17.5:3306 is_slave : true
[read_query] 10.10.17.40:36471 current backend = 0
client default db = mysqlslap client username = root
query = SELECT intcol1,charcol1 FROM t1 sending to backend : 10.10.17.5:3306
is_slave : true
server default db: mysqlslap server username : root in_trans : false
in_calc_found : false COM_QUERY : true
[read_query] 10.10.17.40:36471 current backend = 0
client default db = mysqlslap client username = root
(QUIT) current backend = 0
[disconnect_client] 10.10.17.40:36471 [read_query] 10.10.17.40:36472
62 current backend = 0
client default db = mysqlslap client username = root
query = SELECT intcol1,charcol1 FROM t1 sending to backend : 10.10.17.5:3306
is_slave : true
server default db: mysqlslap server username : root in_trans : false
in_calc_found : false COM_QUERY : true
[read_query] 10.10.17.40:36472 current backend = 0
client default db = mysqlslap client username = root
(QUIT) current backend = 0
63
Giai đoạn 3 của quá trình chạy công cụ mysqlslap:
mysqlslap làm sạch quá trình kiểm tra bằng việc xóa dữ liệu và lƣợc đồ đƣợc tạo ra ở giai đoạn 1 để không làm ảnh hƣởng đến cơ sở dữ liệu sẵn có của máy chủ:
query = DROP SCHEMA IF EXISTS `mysqlslap` sending to backend : 10.10.17.40:3306
is_slave : false
Truy vấn này đƣợc gửi về master.
Đồng thời mysqlslap ngắt kết nối đến máy chủ. [read_query] 10.10.17.40:47303
current backend = 0
client default db = mysqlslap client username = root
(QUIT) current backend = 0 [read_query] 10.10.17.40:40536 current backend = 0
client default db = mysqlslap client username = root
query = DROP SCHEMA IF EXISTS `mysqlslap` sending to backend : 10.10.17.40:3306
is_slave : false
server default db: mysqlslap server username : root in_trans : false
in_calc_found : false COM_QUERY : true
64 [disconnect_client] 10.10.17.40:47303
[read_query] 10.10.17.40:40536 current backend = 0
client default db = mysqlslap client username = root
(QUIT) current backend = 0
[disconnect_client] 10.10.17.40:40536
b) Kết quả thời gian trả về từ công cụ mysqlslap
Kết quả thực nghiệm thời gian chạy các truy vấn trong mô hình này nhƣ bảng sau:
Bảng 3: Kết quả thời gian chạy các truy vấn trong mô hình MySQL Proxy-master-slave
--number-of-queries --concurrency Average number of seconds to run queries
100 100 3.691
600 600 9.348
1500 700 9.599
2000 800 10.470
4.3.3.Mô hình MySQL Proxy – một master – hai slave
Mô hình này bao gồm MySQL Proxy và một giải pháp replication với một master và hai slave.
Máy chủ master có địa chỉ IP và cổng là 10.10.17.40:3306. Máy chủ slave thứ nhất có địa chỉ IP và công là: 10.10.17.5:3306 Máy chủ slave thứ hai có địa chỉ IP và cổng là: 10.10.17.100:3306 MySQL Proxy có địa chỉ IP là 10.10.17.100, lắng nghe trên cổng 4040.
65
Sử dụng máy có địa chỉ IP là 10.10.17.40 làm client để kết nối đến các máy chủ.
a) Kết quả chạy của MySQL Proxy:
Kết quả chạy của MySQL Proxy trong mô hình này ở hai giai đoạn 1 và giai đoạn 3 của quá trình chạy công cụ mysqlslap có kết quả tƣơng tự trong giai đoạn 1 và giai đoạn 3 ở mô hình MySQL Proxy – một master – một slave:
Giai đoạn 1 của quá trình chạy công cụ mysqlslap
# mysql-proxy --admin-username=root \ > --admin-password=giang \ > --admin-address=10.10.17.100:4041 \ > --proxy- address=10.10.17.100:4040\ > --proxy-backend-addresses=10.10.17.40:3306 \ > --proxy-read-only-backend-addresses=10.10.17.5:3306 \ > --proxy-read-only-backend-addresses=10.10.17.100:3306 \ > --admin-lua-script=/home/giangvit/workspace/proxy/admin-script.lua \ > --proxy-lua-script=/home/giangvit/workspace/mysqlProxy/rw4.lua
2012-05-15 16:47:32: [global] (*) mysql-proxy 0.9.0 started
[connect_server] 10.10.17.40:38453 [1].connected_clients = 0 [1].pool.cur_idle = 0 [1].pool.max_idle = 1000000 [1].pool.min_idle = 1 [1].type = 1 [1].state = 0
66 [read_query] 10.10.17.40:38453
current backend = 0 client default db = client username = root
query = DROP SCHEMA IF EXISTS `mysqlslap` sending to backend : 10.10.17.40:3306
is_slave : false server default db: server username : root in_trans : false in_calc_found : false COM_QUERY : true [read_query] 10.10.17.40:38453 current backend = 0 client default db = client username = root
query = CREATE SCHEMA `mysqlslap` sending to backend : 10.10.17.40:3306 is_slave : false
server default db: server username : root in_trans : false
in_calc_found : false COM_QUERY : true
67