Amoeba是什么?
Amoeba(变形虫)项目,致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当SQL路由功能,专注于分布式数据库代理层(Database Proxy)开发。座落与 Client、DB Server(s)之间,对客户端透明。具有负载均衡、高可用性、SQL过滤、读写分离、可路由相关的到目标数据库、可并发请求多台数据库合并结果。
主要解决:
• 降低 数据切分带来的复杂多数据库结构
• 提供切分规则并降低 数据切分规则 给应用带来的影响
• 降低db 与客户端的连接数
• 多数据源的高可用、读写分离、负载均衡、数据切片功能。
为何要使用Amoeba?
随着传统的数据库技术日趋成熟、计算机网络技术的飞速发展和应用范围的扩充,数据库应用已经普遍建立于计算机网络之上。这时集中式数据库系统表现出它的不足:集中式处理,势必造成性能瓶颈;应用程序集中在一台计算机上运行,一旦该计算机发生故障,则整个系统受到影响,可靠性不高;集中式处理引起系统的规模和配置都不够灵活,系统的可扩充性差。在这种形势下,集中式数据库将向分布式数据库发展。而Amoeba的透明、简易配置及多个优点使其成为分布式数据库代理产品中的优秀选择。
分布式数据库代理的相关概念
Amoeba在分布式数据库领域将致力解决数据切分,应付客户端“集中式”处理分布式数据。这里集中式是一个相对概念,客户端不需要知道某种数据的物理存储地。避免这种逻辑出现在业务端,大大简化了客户端操作分布式数据的复杂程度。
分布式数据库系统的优点:
1.降低费用。分布式数据库在地理上可以式分布的。其系统的结构符合这种分布的要求。允许用户在自己的本地录用、查询、维护等操作,实行局部控制,降低通信代价,避免集中式需要更高要求的硬件设备。而且分布式数据库在单台机器上面数据量较少,其响应速度明显提升。
2.提高系统整体可用性。避免了因为单台数据库的故障而造成全部瘫痪的后果。
3.易于扩展处理能力和系统规模。分布式数据库系统的结构可以很容易地扩展系统,在分布式数据库中增加一个新的节点,不影响现有系统的正常运行。这种方式比扩大集中式系统要灵活经济。在集中式系统中扩大系统和系统升级,由于有硬件不兼容和软件改变困难等缺点,升级的代价常常是昂贵和不可行的。
Amoeba for MySQL
Amoeba for MySQL致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当query 路由功能,专注 分布式数据库 proxy 开发。座落与Client、DB Server(s)之间。对客户端透明。具有负载均衡、高可用性、Query过滤、读写分离、可路由相关的query到目标数据库、可并发请求多台数据库合并结果。在Amoeba上面你能够完成多数据源的高可用、负载均衡、数据切片的功能。
那么Amoeba for mysql 对客户端程序来说是什么呢?我们就当它是mysql吧,它是一个虚拟的mysql,对外提供mysql协议。客户端连接amoeba就象连接mysql一样。在amoeba内部需要配置相关的认证属性。
Amoeba不能做什么?
1.目前还不支持事务
2.暂时不支持存储过程(近期会支持)
3.不适合从amoeba导数据的场景或者对大数据量查询的query并不合适(比如一次请求返回10w以上甚至更多数据的场合)
4.暂时不支持分库分表,amoeba目前只做到分数据库实例,每个被切分的节点需要保持库表结构一致
安装和运行Amoeba
运行环境:CentOS6.3
安装jdk1.5以上版本
卸载centos服务器自带版本jdk
查看服务器自带jdk版本号
[[email protected] ~]# java –version
查看java信息
[[email protected] ~]# rpm -qa | grep java
卸载java文件
[[email protected] ~]# rpm -e --nodeps java-1.6.0-openjdk-1.6.0.0-1.45.1.11.1.el6.x86_64
再次查看java版本,已经删除
[[email protected] ~]# java –version
安装jdk
创建/usr/java文件夹,将jdk安装文件拷贝到此目录
[[email protected] ~]# mkdir /usr/java
[[email protected] ~]# cd /usr/java
赋予权限
[[email protected] java]# chmod 777 jdk-6u30-linux-x64-rpm.bin
安装jdk
[[email protected] java]# ./jdk-6u30-linux-x64-rpm.bin
配置环境变量
[[email protected] java]# vi /etc/profile
在配置文件最后面添加下面3条语句
export JAVA_HOME=/usr/java/jdk1.6.0_30
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
配置完成后,重启服务器
[[email protected] java]# reboot
重启完成后查看新安装jdk版本
[[email protected] ~]# java –version
安装amoeba
下载amoeba,http://sourceforge.net/projects/amoeba/files/,我用的版本是amoeba-mysql-binary-2.2.0.tar
创建amoeba文件夹,将文件解压到此文件夹
[[email protected] ~]# mkdir /usr/local/amoeba
[[email protected] ~]# cd /usr/local/amoeba/
[[email protected] amoeba]# tar -zxvf amoeba-mysql-binary-2.2.0.tar.gz
验证是否安装成功
[[email protected] amoeba]# /usr/local/amoeba/bin/amoeba start
参数配置
[[email protected] amoeba]# cd /usr/local/amoeba/conf/
[[email protected] conf]# ls
Amoeba有哪些主要的配置文件?
1.想象Amoeba作为数据库代理层,它一定会和很多数据库保持通信,因此它必须知道由它代理的数据库如何连接,比如最基础的:主机IP、端口、Amoeba使用的用户名和密码等等。这些信息存储在$AMOEBA_HOME/conf/dbServers.xml中。
2.Amoeba为了完成数据切分提供了完善的切分规则配置,为了了解如何分片数据、如何将数据库返回的数据整合,它必须知道切分规则。与切分规则相关的信息存储在$AMOEBA_HOME/conf/rule.xml中。
3.当我们书写SQL来操作数据库的时候,常常会用到很多不同的数据库函数,比如:UNIX_TIMESTAMP()、SYSDATE()等等。这些函数如何被Amoeba解析呢?$AMOEBA_HOME/conf/functionMap.xml描述了函数名和函数处理的关系。
4.对$AMOEBA_HOME/conf/rule.xml进行配置时,会用到一些我们自己定义的函数,比如我们需要对用户ID求HASH值来切分数据,这些函数在$AMOEBA_HOME/conf/ruleFunctionMap.xml中定义。
5.Amoeba可以制定一些可访问以及拒绝访问的主机IP地址,这部分配置在$AMOEBA_HOME/conf/access_list.conf中
6.Amoeba允许用户配置输出日志级别以及方式,配置方法使用log4j的文件格式,文件是$AMOEBA_HOME/conf/log4j.xml。
配置一个DB节点
以下是配置一个DB节点,使用Amoeba做操作转发的步骤:
1.首先,在$AMOEBA_HOME/conf/dbServers.xml中配置一台数据库,如下:
Example 3.1. 简单的DB节点配置
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd">
<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">
<!--
Each dbServer needs to be configured into a Pool,
If you need to configure multiple dbServer with load balancing that can be simplified by the following configuration:
add attribute with name virtual = "true" in dbServer, but the configuration does not allow the element with name factoryConfig
such as ‘multiPool‘ dbServer
-->
#这份dbServers配置文件中,我们定义了三个dbServer元素,这是第一个dbServer元素的定义。这个名为abstractServer的dbServer,其abstractive属性为true,这意味着这是一个抽象的dbServer定义,可以由其他dbServer定义拓展。
<dbServer name="abstractServer" abstractive="true">
<factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<property name="manager">${defaultManager}</property>
#manager定义了该dbServer选择的连接管理器(ConnectionManager),这里引用了amoeba.xml的配置。
<property name="sendBufferSize">64</property>
<property name="receiveBufferSize">128</property>
#在第一个dbServer元素分别定义MySQL的端口号、数据库名、用户名以及密码。
<!-- mysql port -->
<property name="port">3306</property>
<!-- mysql schema -->
<property name="schema">test</property>
<!-- mysql user -->
<property name="user">root</property>
<!-- mysql password -->
<property name="password">password</property>
</factoryConfig>
#dbServer下有poolConfig的元素,这个元素的属性主要配置了与数据库的连接池。
<poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
<property name="maxActive">500</property>
<property name="maxIdle">500</property>
<property name="minIdle">10</property>
<property name="minEvictableIdleTimeMillis">600000</property>
<property name="timeBetweenEvictionRunsMillis">600000</property>
<property name="testOnBorrow">true</property>
<property name="testWhileIdle">true</property>
</poolConfig>
</dbServer>
#命名为server1的dbServer元素,正如你设想的那样,这个server1是abstractServer的拓展,parent属性配置了拓展的抽象dbServer,它拓展了abstractServer的ipAddress属性来指名数据库的IP地址,而在端口、用户名密码、连接池配置等属性沿用了abstractServer的配置。
<dbServer name="server1" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
#server1拓展了abstractServer的ipAddress属性。
<property name="ipAddress">127.0.0.1</property>
</factoryConfig>
</dbServer>
#这一段其实并不需要配置,并不会影响到基本使用。以下大致介绍下此配置的含义:multiPool是一个虚拟的数据库节点,可以将这个节点配置成好几台数据库组成的数据库池。比如上面这个配置中仅配置了一台server1,负载均衡策略为ROUNDROBIN(轮询)。与虚拟数据库节点相关的详细教程会在后面的章节中介绍。
<dbServer name="multiPool" virtual="true">
<poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
<!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
<property name="loadbalance">1</property>
<!-- Separated by commas,such as: server1,server2,server1 -->
<property name="poolNames">server1</property>
</poolConfig>
</dbServer>
</amoeba:dbServers>
由此,你大概可以理解定义abstractServer的原因:当我们有一个数据库集群需要管理,这个数据库集群中节点的大部分信息可能是相同的,比如:端口号、用户名、密码等等。因此通过归纳这些共性定义出的abstractServer极大地简化了dbServers配置文件:
Example 3.2. 一个利用定义抽象节点配置集群的例子
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd">
<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">
<dbServer name="abstractServerForBilling" abstractive="true">
<factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<property name="manager">${defaultManager}</property>
<property name="sendBufferSize">64</property>
<property name="receiveBufferSize">128</property>
<property name="port">3306</property>
<property name="schema">test</property>
<property name="user">root</property>
<property name="password">password</property>
</factoryConfig>
<poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
<property name="maxActive">500</property>
<property name="maxIdle">500</property>
<property name="minIdle">10</property>
<property name="minEvictableIdleTimeMillis">600000</property>
<property name="timeBetweenEvictionRunsMillis">600000</property>
<property name="testOnBorrow">true</property>
<property name="testWhileIdle">true</property>
</poolConfig>
</dbServer>
<dbServer name="billing1" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.0.1</property>
</factoryConfig>
</dbServer>
<dbServer name="billing2" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.0.2</property>
</factoryConfig>
</dbServer>
......
</amoeba:dbServers>
2.再配置完dbServer.xml后,继续配置amoeba.xml文件:
Example 3.3. 一个基本的amoeba.xml例子
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd">
<amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/">
<proxy>
<!-- server class must implements com.meidusa.amoeba.service.Service -->
#Service节点定义了需要启动的服务,在本配置中其class属性为“com.meidusa.amoeba.net.ServerableConnectionManager”,这意味着这是一个Proxy Service。在这个元素下的connectionFactory元素中定义其class属性为“com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory”,这意味着这是一个MySQL Proxy Service。相应的也会有MongoDB Proxy Service以及Aladdin Proxy Service。
<service name="Amoeba for Mysql" class="com.meidusa.amoeba.net.ServerableConnectionManager">
#这里定义了之前我们所定义的MySQL Proxy Service的服务端口和主机地址。
#Caution:通常Proxy Service服务的主机地址并不需要定义,如果Amoeba所在的服务器在多个网络环境内你可以定义该机器的其中一个IP来指定Amoeba所服务的网络环境。如果设置为127.0.0.1将导致其他机器无法访问Amoeba的服务。
<!-- port --
<property name="port">8066</property>
<!-- bind ipAddress -->
<!--
<property name="ipAddress">127.0.0.1</property>
-->
<property name="manager">${clientConnectioneManager}</property>
<property name="connectionFactory">
<bean class="com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory">
<property name="sendBufferSize">128</property>
<property name="receiveBufferSize">64</property>
</bean>
</property>
#这里配置了MySQL Proxy Service的认证器,user和passwd属性分别定义Amoeba对外服务的用户名和密码。你的程序或者数据库客户端需要使用该用户名和密码来通过Amoeba连接之前定义的dbServer。
<property name="authenticator">
<bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
<property name="user">root</property>
<property name="password">password</property>
<property name="filter">
<bean class="com.meidusa.amoeba.server.IPAccessController">
<property name="ipFile">${amoeba.home}/conf/access_list.conf</property>
</bean>
</property>
</bean>
</property>
</service>
<!-- server class must implements com.meidusa.amoeba.service.Service -->
<service name="Amoeba Monitor Server" class="com.meidusa.amoeba.monitor.MonitorServer">
<!-- port -->
<!-- default value: random number
<property name="port">9066</property>
-->
<!-- bind ipAddress -->
<property name="ipAddress">127.0.0.1</property>
<property name="daemon">true</property>
<property name="manager">${clientConnectioneManager}</property>
<property name="connectionFactory">
<bean class="com.meidusa.amoeba.monitor.net.MonitorClientConnectionFactory"></bean>
</property>
</service>
#runtime元素定义了一些Proxy相关的运行期配置,如客户端及数据库服务器端的线程数以及SQL超时时间设定等等。
<runtime class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">
<!-- proxy server net IO Read thread size -->
<property name="readThreadPoolSize">20</property>
<!-- proxy server client process thread size -->
<property name="clientSideThreadPoolSize">30</property>
<!-- mysql server data packet process thread size -->
<property name="serverSideThreadPoolSize">30</property>
<!-- per connection cache prepared statement size -->
<property name="statementCacheSize">500</property>
<!-- query timeout( default: 60 second , TimeUnit:second) -->
<property name="queryTimeout">60</property>
</runtime>
</proxy>
<!--
Each ConnectionManager will start as thread
manager responsible for the Connection IO read , Death Detection
-->
#connectionManagerList定义了一系列连接管理器,这些连接管理器可以在其他地方被引用,比如clientConnectioneManager在amoeba.xml中被引用作为MySQL Proxy Service的客户端连接管理器;defaultManager在dbServers.xml中被引用作为dbServer的数据库服务器端连接管理器。连接管理器主要配置了用于网络处理的CPU核数,默认其processor属性为Amoeba所在主机的CPU核数。
<connectionManagerList>
<connectionManager name="clientConnectioneManager" class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper">
<property name="subManagerClassName">com.meidusa.amoeba.net.ConnectionManager</property>
<!--
default value is avaliable Processors
<property name="processors">5</property>
-->
</connectionManager>
<connectionManager name="defaultManager" class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper">
<property name="subManagerClassName">com.meidusa.amoeba.net.AuthingableConnectionManager</property>
<!--
default value is avaliable Processors
<property name="processors">5</property>
-->
</connectionManager>
</connectionManagerList>
#最后一部分dbServerLoader定义了dbServers.xml的位置。queryRouter定义了规则配置及函数配置等相关文件的位置。
<!-- default using file loader -->
<dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader">
<property name="configFile">${amoeba.home}/conf/dbServers.xml</property>
</dbServerLoader>
<queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
<property name="ruleLoader">
<bean class="com.meidusa.amoeba.route.TableRuleFileLoader">
<property name="ruleFile">${amoeba.home}/conf/rule.xml</property>
<property name="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property>
</bean>
</property>
<property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property>
<property name="LRUMapSize">1500</property>
<property name="defaultPool">server1</property>
<!--
<property name="writePool">server1</property>
<property name="readPool">server1</property>
-->
<property name="needParse">true</property>
</queryRouter>
</amoeba:configuration>
在Master/Slave结构下的读写分离
首先说明一下amoeba 跟 MySQL proxy在读写分离的使用上面的区别:
在MySQL proxy 6.0版本上面如果想要读写分离并且读集群、写集群机器比较多情况下,用mysql proxy 需要相当大的工作量,目前mysql proxy没有现成的 lua脚本。mysql proxy根本没有配置文件, lua脚本就是它的全部,当然lua是相当方便的。那么同样这种东西需要编写大量的脚本才能完成一个复杂的配置。而Amoeba只需要进行相关的配置就可以满足需求。
假设有这样的使用场景,有三个数据库节点分别命名为Master、Slave1、Slave2如下:
Master: Master (可读写)
Slaves:Slave1、Slave2 (2个平等的数据库。只读/负载均衡)
针对这样的使用方式,首先在dbServers.xml中将Slave1和Slave2配置在一个虚拟的dbServer节点中,使他们组成一个数据库池。
Example 4.3. 数据库池在dbServers.xml的定义与配置
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd">
<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">
...
#定义了Master节点,parent为abstractServer,关于abstractServer的定义方式参照第三章。
<dbServer name="Master" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.0.1</property>
</factoryConfig>
</dbServer>
#定义了Slave1和Slave2节点。
<dbServer name="Slave1" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.0.2</property>
</factoryConfig>
</dbServer>
<dbServer name="Slave2" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.0.3</property>
</factoryConfig>
</dbServer>
#定义了virtualSlave的虚拟节点,这是由Slave1和Slave2组成的一个数据库池。
<dbServer name="virtualSlave" virtual="true">
<poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
#loadbalance元素设置了loadbalance策略的选项,这里选择第一个“ROUNDROBIN”轮询策略,该配置提供负载均衡、failOver、故障恢复功能。
<!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
<property name="loadbalance">1</property>
#poolNames定义了其中的数据库节点配置(当然也可以是虚拟的节点)。此外对于轮询策略,poolNames还定义了其轮询规则,比如设置成“Slave1,Slave1,Slave2”那么Amoeba将会以两次Slave1,一次Slave2的顺序循环对这些数据库节点转发请求。
<!-- Separated by commas,such as: server1,server2,server1 -->
<property name="poolNames">Slave1,Slave2</property>
</poolConfig>
</dbServer>
...
</amoeba:dbServers>
如果不需要配置规则那么可以不使用rule.xml而直接配置amoeba.xml中的queryRouter,配置如下:
Example 4.4. 配置amoeba.xml不使用切分功能直接配置queryRouter以读写分离
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd">
<amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/">
...
<queryRouter class=”com.meidusa.amoeba.mysql.parser.MysqlQueryRouter”>
#LRUMapSize属性定义了Amoeba缓存的SQL语句解析的条数。
<property name="LRUMapSize">1500</property>
#defaultPool配置了默认的数据库节点,一些除了SELECT\UPDATE\INSERT\DELETE的语句都会在defaultPool执行。
<property name="defaultPool">Master</property>
#writePool配置了数据库写库,通常配为Master,如这里就配置为之前定义的Master数据库。
<property name="writePool">Master</property>
#readPool配置了数据库读库,通常配为Slave或者Slave组成的数据库池,如这里就配置之前的virtualSlave数据库池。
<property name="readPool">virtualSlave</property>
<property name="needParse">true</property>
</queryRouter>
...
</amoeba:configuration>
通过Amoeba对数据进行简单的分片
配置dbServers.xml
首先根据前一小节的配置,在dbServers.xml中增加一个dbServer元素(即是我们新增用于水平切分的数据库)如下:
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd">
<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">
...
<dbServer name="server2" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
#这里仅仅在之前的dbServers.xml文件中增加了一段新的节点配置,server2同样继承了abstractServer的配置,唯一不同的是其主机地址不一样,因此它有自己的主机地址属性,你需要按自己的实际需求配置这个主机地址。
<property name="ipAddress">192.168.0.1</property>
</factoryConfig>
</dbServer>
...
</amoeba:dbServers>
配置rule.xml
Example 3.4. 一个基本的rule.xml配置示例
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:rule SYSTEM "rule.dtd">
<amoeba:rule xmlns:amoeba="http://amoeba.meidusa.com/">
#tableRule的name属性定义了表名、schema为数据库名、defaultPools定义了该表的默认库。
<tableRule name="staff" schema="test" defaultPools="server1,server2">
#在tableRule中定义了名为rule1的规则,规则的返回结果为POOLNAME,在这里ruleResult还有其他配置项,将在后面介绍。
<rule name="rule1" ruleResult="POOLNAME">
#parameters元素定义了切分的参数,比如在例子的场景中就是按照员工号来进行切分。通常parameters的配置为该表的某列列名或几列列名。
<parameters>ID</parameters>
#expression元素定义了类似VB Script的切分表达式。在本例中,Amoeba对ID(员工号)取余,如果员工号是单数则存储在server2中,员工号是双数则存储在server1中。
<expression><![CDATA[
var division = ID % 2;
case division when 0 then ‘server1‘;
when 1 then ‘server2‘;
end case;
]]></expression>
</rule>
</tableRule>
</amoeba:rule>
基于Amoeba的数据水平切分
数据水平切分这种方式应该是大家都能想到的,但数据切分以后我们如何访问我们的应用,我们应用如何按照规则做实时的数据切分?在应用层面还是其他层?这个难题可以托付给Amoeba来解决。 Amoeba提供对dba非常友好的数据切分规则表达式。
之前已经有一个通过Amoeba将员工ID通过奇偶不同水平切分到两台机器上的实例。这里会使用一些稍稍复杂一些的函数来完成。
假设我们messagedb 需要根据id hash进行水平切分,我们可以根据hash范围分成2台:
规则1: abs(hash(id)) mod 2 = 0 → blogdb-1
规则2: abs(hash(id)) mod 2 = 1 → blogdb-2
这里abs、hash 都是amoeba 规则中使用到的函数,amoeba允许开发人员增加新的规则函数,这在本章节的Amoeba自定义函数配置详解小节中介绍。
数据的水平切分主要通过对rule.xml文件的配置,如以下这个配置示例:
Example 4.1. 通过配置rule.xml完成水平分区
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:rule SYSTEM "rule.dtd">
<amoeba:rule xmlns:amoeba="http://amoeba.meidusa.com/">
...
#配置该表的表明和数据库名,defaultPools为需要MESSAGE表被分片到的两个数据库节点以逗号分隔符。defaultPools属性中的数据库节点须是dbServers.xml中配置的虚拟数据库节点或真实数据库节点。
<tableRule name="MESSAGE" schema="test" defaultPools="blogdb-1,blogdb-2">
<rule name="rule1">
#parameters元素定义了用作分区规则的字段,这里是MESSAGE.ID。
<parameters>ID</parameters>
#expression元素定义了分区规则,可以从这里了解到rule1中ID哈希取绝对值后模2为0的数据被分片到blogdb-1上。
<expression><![CDATA[ abs(hash(id)) mod 2 = 0 ]]></expression>
<defaultPools>blogdb-1</defaultPools>
</rule>
<rule name="rule2">
<parameters>ID</parameters>
<expression><![CDATA[ abs(hash(id)) mod 2 = 1 ]]></expression>
<defaultPools>blogdb-2</defaultPools>
</rule>
</tableRule>
...
</amoeba:rule>
基于Amoeba的数据垂直切分
垂直切分(纵向)数据是数据按照网站业务、产品进行切分,比如用户数据、博客文章数据、照片数据、标签数据、群组数据等等每个业务一个独立的数据库或者数据库服务器。
如果一个应用只针对单纯的业务功能模块。那么可以直接连接相应的被垂直切分的数据库。但一些复杂的应用需要用到相当多的业务数据,涉及到几乎所有的业务数据。那么垂直切分将会给应用带来一定的复杂度,而且对工程师开发也会有一定影响。整个应用的复杂度将上升。
Amoeba在其中充当了门面功能,相当于水利枢纽。疏通应用与多个数据库数据通讯。
假设有3个数据库:userdb、blogdb、otherdb
userdb:包含有user表
blogdb:包含有message、event
otherdb:其他表所在的数据库
数据的垂直切分主要通过对rule.xml文件的配置,如以下这个配置示例:
Example 4.2. 通过配置rule.xml完成垂直分区
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:rule SYSTEM "rule.dtd">
<amoeba:rule xmlns:amoeba="http://amoeba.meidusa.com/">
...
文章大部分参考于amoeba的首页文档:
http://docs.hexnova.com/amoeba/