Redundant Storage Cluster
For When It's Just Too Big
Bob Burgess radian6 Technologies MySQL User Conference 2009
Redundant Storage Cluster For When It's Just Too Big Bob Burgess - - PowerPoint PPT Presentation
Redundant Storage Cluster For When It's Just Too Big Bob Burgess radian 6 Technologies MySQL User Conference 2009 Scope Fundamentals of MySQL Proxy Fundamentals of LuaSQL Description of the Redundant Storage Cluster Architecture
Bob Burgess radian6 Technologies MySQL User Conference 2009
2 4 6 8 10 12
Blog Posts – millions per day
month table month table month table month table
myisam merge table
Other DBs Other DBs
Master DB content
(federated)
Other DBs content
(federated)
Load Balancer 1
content 1
MySQL Proxy
Lua 2
content 2
MySQL Proxy
Lua
content n
MySQL Proxy
Lua
dir dir dir
create table sample ( id int primary key, value varchar(100) ) engine=federated connection= 'mysql://user:password@host:9999/schema/sample'
create table sample ( id int primary key, val int, name varchar(50) ) select id,name from sample; SELECT `id`, `val`, `name` FROM `sample`; select id,name from sample where id=2; SELECT `id`, `val`, `name` FROM sample WHERE `id` = '2'; select val,name from sample where val=2; SELECT `id`, `val`, `name` FROM `sample`; select * from sample limit 10; SELECT `id`, `val`, `name` FROM `sample`;
select max(id)from sample; SELECT `id`, `val`, `name` FROM `sample`; select count(*) from sample; SELECT `id`, `val`, `name` FROM `sample`; insert into sample (id,name) values (5,'bob'); INSERT INTO `sample` (`id`, `val`, `name`) VALUES ('5', NULL, 'bob'); insert into sample values (5,10,'bob'); INSERT INTO `sample` (`id`, `val`, `name`) VALUES ('5', '10', 'bob');
proxy.global.conRemote[tonumber(details.nodeId)] = proxy.global.MySQLenv:connect(...)
proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = {...}
MySQL client MySQL server 3306 MySQL client MySQL server 3306 MySQL Proxy 4040 MySQL client MySQL server MySQL Proxy 4040
Lua LuaSQL
3306
MySQL client MySQL server MySQL Proxy
Lua
read_query( ) read_query_result( )
MySQL client MySQL server MySQL Proxy
Lua
LuaSQL calls
environment connection
:connect
cursor
:execute (select) :execute (ins/upd/del)
return code & error msg
:fetch
return set
call the execute method if cursor object is nil: call connect method for the environment call execute again
function select_db (node,sql) local reconnects = 0 local cur local err repeat cur, err = proxy.global.conRemote[tonumber(node)]:execute(sql) if cur == nil then print ('Reconnecting select_db. Error='..err) reopen_remote_db (node) end reconnects = reconnects+1 until (cur ~= nil or reconnects==proxy.global.connect_retry) if cur==nil then error("Could not reconnect / No result set in select_db",2) else return cur:fetch() end end
function execute_db (node,sql) local reconnects = 0 local LOST_CONNECTION = "MySQL server has gone away" local rc local err repeat rc, err = proxy.global.conRemote[tonumber(node)]:execute(sql) if rc ~= nil then print ("execute_db RC="..rc); end if err~=nil then print ("execute_db error="..err); end if rc == nil and err:find(LOST_CONNECTION) then print ('Reconnecting execute_db. Error='..err) reopen_remote_db (node) end reconnects = reconnects+1 until (rc ~= nil or reconnects==proxy.global.connect_retry or not err:find(LOST_CONNECTION) ) if rc == nil and err:find(LOST_CONNECTION) then error("Could not reconnect in execute_db.",2) else return rc,err end end
proxy.COM_QUERY (Query)
proxy.response={ type= proxy.MYSQLD_PACKET_ERR, errmsg= "Malformed INSERT statement.", errcode= 1064, sqlstate= "42000" } return proxy.PROXY_SEND_RESULT
proxy.response.type=proxy.MYSQLD_PACKET_OK return proxy.PROXY_SEND_RESULT
proxy resultset (etc.) rows fields name type
value value value value value value
rows fields name type
value value value value value value proxy.response.type = proxy.MYSQLD_PACKET_OK proxy.response.resultset = { fields = { {type=proxy.MYSQL_TYPE_LONGLONG, name="blogPostID" }, {type=proxy.MYSQL_TYPE_LONG, name="partitionKey"}, {type=proxy.MYSQL_TYPE_VAR_STRING, name="rawContent" } }, rows = { { tonumber(itemId), tonumber(partKey), contentValue } } } return proxy.PROXY_SEND_RESULT
insert no yes syntax bad good error exists yes no error
store on this node Error: table doesn't exist create table store on this node update ALL directories store Event return OK to client
proxy.response={ type= proxy.MYSQLD_PACKET_ERR, errmsg= "Duplicate entry '"..itemId.."' for key 1", errcode= 1062, sqlstate= "23000"} return proxy.PROXY_SEND_RESULT
select no yes syntax bad good error 1=0 yes no
return result set to client return empty result set to client
info table
yes no
return result set to client
calculate max(ID) and count(*)
read dir
local remote doesn't exist get item from remote db get item from this db return empty result set to client
select max(id)from sample; SELECT `id`, `val`, `name` FROM `sample`;
create table _content_info ( _max_id bigint unsigned, _count bigint unsigned) engine=federated connection=(...schema/_content_info...);
create view _content_info as select max(id) _max_id, count(*) _count from _content;
show table status like `_content`;
Policy enforce for new items get earliest new item next step
no new items
find another node with the most free space copy the item there update all directories
Policy enforce for other items
get one item from the Directory which exists on an insufficient number of nodes and has "me" as the first listed node
next step
no items copy the item to the node with the most free space that doesn't already have it
update all directories
Rebalancer done
move the item from that node to me
update all directories
do I have the most free space of all the nodes no yes find the node with the least free space find an item on that node that's not on this node (that
MySQL Documentation http://forge.mysql.com/wiki/MySQL_Proxy http://forge.mysql.com/tools/search.php?t=tag&k=mysqlproxy http://www.lua.org http://www.keplerproject.org/luasql http://lua-users.org http://jan.kneschke.de/projects/mysql/mysql-proxy http://www.linuxvirtualserver.org