一、Spider引擎简介
1、spider 引擎是什么
Spider引擎是一个内置的支持数据分片特性的存储引擎,支持分区和XA事务,该引擎可以在服务器上建立和远程数据库表之间的链接,操作起来就像操作本地的表一样。并且对后台数据库的引擎没有任何限制。
目前spider引擎已经集成到了MariaDB中,最新的版本是spider3.2.37.
2、spider架构图
3、spider优劣势分析
优势分析 | |
1 | 对业务完全透明,业务层不需要做任何的修改 对于分库和分表的操作业务层不需要关系,只需要通过spider作为代理入口, 真实数据存储在哪台设备上,spider代理会自动进行路由。 |
2 | 方便横向扩展,能解决单台mysql的性能和存储瓶颈3 |
3 | 对后端的数据库引擎没有限制 |
4 | 实现垂直拆分和水平拆分功能,针对分表支持此哈希,范围,列表等算法 |
5 | 完全兼容mysql协议 |
劣势分析 | |
1 | Spider本身不支持缓存和全文搜索,只能在后端数据库实现全文搜索 |
2 | Spider无法备份数据,只能对后端数据库做物理备份 |
3 | Spider本身是单点的,无法做灾备,只能通过VIP方式自己实现啊 |
4 | 由于业务与数据库之间多了一层spider,在性能上多少会有些损耗 |
二、Spider 的使用场景解析
1、垂直分表的场景和解析
a、垂直分表场景图
从上图可以看出:spider后端有4台数据库,可以将不同功能的表分别放到不同的后端数据库中,例如上图所示:把user_info表放到了HostA中,user_msg表放到HostB中,user_detail表存放在HostC中,user_log表放到了HostD中。在图中的红色部分,当我们执行红色部分的 SQL 的时候,spider 会通过 user_info 表的映射关系以及 HostA 的 IP 映射关系,将查询 user_info 表的请求都转发到 HostA 上,HostA 查询完成后再将结果发给 spider 服务器,spider 再转发给客户端。
2、采用水平分表的场景
Spider支持多种水平分表模式,目前支持hash分表,范围分表,列表分表等算法。上图中是通过范围分表算法来对user_info数据库表进行拆分,把不同记录放到不同的数据库中,从上图中可以看出 spider 对 user_info 表针对 id 进行了分区,将 0~100000 的记录存储在了 HostA,100000~200000 的记录存储在了 HostB,200000~300000 的记录存储在了 HostC,300000~400000 的记录存储在了 HostD。当用户访问 user_info 的某条或者多条记录的时候,spider 会根据分区的情况,对相关的记录落在某台或者多台 DB server 上,再进行转发。比如 select * from user_info where id=1 这个 SQL,spider 在收到这个请求后,会跟进分区情况选择对应的 DB server 进行转发。这里会将该请求转发到 HostA 中。HostA 处理完成后,再将结果返回给 spider server,spider 再将结果转发给发起请求的客户端。
三、实战前准备
a、创建spider server访问后端DB server的权限(后面配置中需要用到)
grant all on *.* tospider_db_all@'10.128.128.91' identified by'tospider_db_all';
b、创建spider后端DB server的配置
可以通过执行如下SQL的形式直接创建
create serverbackend1 foreign data wrapper mysql options (host '10.128.128.60',database 'test', user 'spider_db_all', password 'spider_db_all', port 3306);
create serverbackend2 foreign data wrapper mysql options (host '10.128.128.88',database 'test', user 'spider_db_all', password 'spider_db_all', port 3306);
也可以通过直接给mysql.servers表中直接插入相关的记录,不过后面执行flush hosts才能生效
insert intomysql.servers(Server_name,Host,Db,Username,Password,Port,Socket,Wrapper,Owner)values('backend1','10.128.128.60','test','spider_db_all','spider_db_all',3306,'','mysql','');
insert intomysql.servers(Server_name,Host,Db,Username,Password,Port,Socket,Wrapper,Owner)values('backend2','10.128.128.88','test','spider_db_all','spider_db_all',3306,'','mysql','');
创建完成后可以直接查询mysql.servers表,确认是否添加成功,如下截图所示:
b、创建基础测试表
在后端两台DB server上创建基础测试表(在60和88上执行)
create tabletest_spider (
id int,
username varchar(20),
address varchar(128),
primary key (id),
key (username)
) engine=InnoDBdefault charset=utf8 comment 'spider test base table';
3、spider引擎实战
a、建立垂直表(远程表进行测试)
create tabletest_spider (
id int,
username varchar(20),
address varchar(128),
primary key (id),
key (username)
) ENGINE=SPIDERDEFAULT CHARSET=utf8 COMMENT='server "backend1"';
创建之后,执行对应增删改查,看看是否对应的操作都发生在了backend1对应的DB server上?
测试完成后,删除掉spider 服务器上的test_spider表,你会发现drop掉spider上的表,不会导致后端DB server上的表被删除。
b、建立hash分区表
create tabletest_spider (
id int,
username varchar(20),
address varchar(128),
primary key (id),
key (username)
) ENGINE=SPIDER DEFAULT CHARSET=utf8 COMMENT='wrapper "mysql",table "test_spider"'
PARTITION BY HASH (id)
( PARTITION pt1 COMMENT = 'srv "backend1"',
PARTITION pt2COMMENT = 'srv "backend2"') ;
创建之后,执行对应增删改查,看看是否对应的操作都发生在了backend1和backend2对应的DB server上?
测试完成后,删除掉spider 服务器上的test_spider表,你会发现drop掉spider上的表,不会导致后端DB server上的表被删除。
c、建立range分区表
create tabletest_spider (
id int,
username varchar(20),
address varchar(128),
primary key (id),
key (username)
) ENGINE=SPIDER DEFAULT CHARSET=utf8 COMMENT='wrapper "mysql",table "test_spider"'
PARTITION BY range columns (id)
( PARTITION pt1 values less than (100000) COMMENT = 'srv"backend1"',
PARTITION pt2values less than (200000) COMMENT = 'srv "backend2"') ;
创建之后,执行对应增删改查,看看是否对应的操作都发生在了backend1和backend2对应的DB server上?
测试完成后,删除掉spider 服务器上的test_spider表,你会发现drop掉spider上的表,不会导致后端DB server上的表被删除。
d、建立list分区表测试
create tabletest_spider (
id int,
username varchar(20),
address varchar(128),
primary key (id),
key (username)
) ENGINE=SPIDER DEFAULT CHARSET=utf8 COMMENT='wrapper "mysql",table "test_spider"'
PARTITION BY list columns (id)
( PARTITION pt1 values in (1,3,5,7,9) COMMENT = 'srv"backend1"',
PARTITION pt2values in (2,4,6,8,10) COMMENT = 'srv "backend2"') ;
创建之后,执行对应增删改查,看看是否对应的操作都发生在了backend1和backend2对应的DB server上?
测试完成后,删除掉spider 服务器上的test_spider表,你会发现drop掉spider上的表,不会导致后端DB server上的表被删除。
四、Spider实现原理分析
4.1表连接
当创建一个Spider存储引擎的表时,该表指向远程服务器上对应的一张表或者多个实例上的表,就像UNIX/Linux中的软链接一样。远程服务器上的表可以是任何存储引擎的表。在执行CREATE TABLE命令创建Spider引擎的表时,需要添加COMMENT或CONNECTION语法来指定远程服务器的地址等信息。例如,在远程服务器(该服务器是数据节点,假设IP为192.168.0.1)上创建了如下一张表:
CREATE TABLE s(id INT NOT NULL AUTO_INCREMENT, code VARHCAR(10), PRIMARYKEY(id));
在Spider节点创建一张表指向该表:
CREATE TABLE s(id INT NOT NULL AUTO_INCREMENT, code VARHCAR(10), PRIMARYKEY(id)) ENGINE=SPIDER COMMENT ‘host “192.168.0.1”,user “user1”, password “pwd1”, port “3307”’
在Spider节点,表字段定义可以忽略。Spider第一次访问表的时候,如果发现没有表字段定义,会从后端节点拉取相关元数据,然后缓存在本地。
Spider的系统表spider_tables记录了各个数据分片的位置信息,类似于编程语言中指针作用。该系统表可以便利Spider跨节点的join操作:访问数据所在的机器,然后把数据拉取到本地进行join操作;如果进行join操作字段不是分片字段,那么需要广播SQL语句将数据拉取到Spider节点进行join操作。
4.2 Select操作
上面提到Spider的作用类似一个proxy,本身并不存储数据。因此Spider处理SELECT语句(UPDATE与DELETE类似)首先需要根据查询解析的信息生成一个SELECT语句,发送到查询涉及的后端节点,将数据从远端拉到本地,然后进行处理。函数spider_db_append_select_columns根据查询涉及的读集以及写集获取相应的字段,构造一个SQL语句从后端节点拉取数据到本地。如果涉及多个分片,spider将从不同实例获取过来的结果集存放在不同的结果集spider_db_result中。类spider_db_fetch提供了fetch_next, current_row等方法供上层方法调用。Server层调用get_next方法驱动引擎层获取下一条数据
4.3 insert操作
MySQL的handler类对于INSERT操作提供的接口函数的名字是write_row。存储引擎想要支持INSERT操作就必须实现write_row方法。Spider对于write_row方法的实现是简单地根据查询解析的信息拼接一条INSERT语句,发往后端节点处理。如果是批量插入操作则需要与MySQL Server层配合,将INSERT语句批量发到后端节点
4.4 delet操作
Spider想要支持DELETE操作必须实现MySQLhandler类提供的ha_delete_row方法。与INSERT操作不同,DELETE操作需要生成一条SELECT语句将查询涉及的分区键拉到Spider节点。这是因为MySQLServer层的“once-a-tuple”的查询执行模型(实际上基本所有的关系数据库系统都采用该模型)会驱动Spider逐个拼接DELETE语句,然后发往后端节点。这时候,Spider需要知道对应的DELETE语句该往哪个后端节点发送。为了减少网络开销,Spider提供了批量发送DELETE语句的功能。
4.5 update操作
UPDATE操作的实现类似DELETE,都需要Spider生成SELECT语句从后端节点拉取数据。只不过,UPDATE在更新区分键的时候,可能需要多一次DELETE操作(删除原来分区的数据,将新的数据插入到不同的分区)