amoeba_mysql_MyCAT
http://www.oschina.net/p/amoeba/similar_projects?lang=0&sort=view&p=9
amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy。它集中地响应应用的请求,依据用户事先设置的规则,将SQL请求发送到特定的数据库上执行。基于此可以实现负载均衡、读写分离、高可用性等需求。与MySQL官方的MySQL Proxy相比,作者强调的是amoeba配置的方便(基于XML的配置文件,用SQLJEP语法书写规则,比基于lua脚本的MySQL Proxy简单)。
amoeba相当于一个SQL请求的路由器,目的是为负载均衡、读写分离、高可用性提供机制,而不是完全实现它们。用户需要结合使用MySQL的 Replication等机制来实现副本同步等功能。amoeba对底层数据库连接管理和路由实现也采用了可插拨的机制,第三方可以开发更高级的策略类来替代作者的实现。这个程序总体上比较符合KISS的思想。
amoeba主要解决以下问题:
a). 数据切分后复杂数据源整合
b). 提供数据切分规则并降低数据切分规则给数据库带来的影响
c). 降低数据库与客户端连接
d). 读写分离路由
- 授权协议: GPL
- 开发语言: Java
- 操作系统: 跨平台
- 收录时间: 2008年11月13日 (国产软件 or 国人参与)
http://docs.hexnova.com/amoeba/
Amoeba使用指南 | ||
---|---|---|
Next |
Table of Contents
List of Tables
- 4.1.tableRule的属性
- 4.2.tableRule的元素
- 4.3.rule的属性
- 4.4.rule的元素
- 5.1.JVM(Java Virtual Machine)内存参数设置
List of Examples
- 3.1.简单的DB节点配置
- 3.2.一个利用定义抽象节点配置集群的例子
- 3.3.一个基本的amoeba.xml例子
- 3.4.一个基本的rule.xml配置示例
- 4.1.通过配置rule.xml完成水平分区
- 4.2.通过配置rule.xml完成垂直分区
- 4.3.数据库池在dbServers.xml的定义与配置
- 4.4.配置amoeba.xml不使用切分功能直接配置queryRouter以读写分离
- 4.5.通过使用isReadStatement在rule.xml配置中指定读库和写库
- 5.1.设置Amoeba启动脚本来调整内存参数
- 5.2.配置amoeba.xml的多线程相关选项
- 5.3.配置amoeba.xml的网络相关选项
- 6.1.一个基本的Benchmark的query文件
- 6.2.一个更高级的Benchmark的query文件以及其对应的context文件
同事 Struct Chen 的 Amoeba For MySQL 项目已经 出来不短时间了,可一直没有时间好好体验,最近一直在做一些软件和硬件的功能以及性能相关的测试工作,Amoeba For MySQL自然也将被列入计划之内。
对 Amoeba For MySQL 的测试到目前位置主要还是功能方面的测试,配置了一套四台机器的环境:
Server A: Amoeba Server
Server B: MySQL Master
Server C: MySQL Slave1
Server D: MySQL Slave2
软件环境:RHEL5.2 (X86_64),JAVA 1.5.0_16, Amoeba For MySQL 0.31
测试功能:
1、读写分离
2、数据垂直切分
3、数据水平切分
amoeba.xml配置如下:
< !DOCTYPEamoeba:configurationSYSTEM”amoeba.dtd”>
<amoeba:configurationxmlns:amoeba=”http://amoeba.meidusa.com/”>
<server>
<propertyname=”port”>8066</property>
<propertyname=”ipAddress”>10.0.38.21</property>
<!– proxy server net IO Read thread size –>
<propertyname=”readThreadPoolSize”>500</property>
<!– proxy server client process thread size –>
<propertyname=”clientSideThreadPoolSize”>500</property>
<!– mysql server data packet process thread size –>
<propertyname=”serverSideThreadPoolSize”>500</property>
<!– socket Send and receive BufferSize(unit:K) –>
<propertyname=”netBufferSize”>200</property>
<!– Enable/disable TCP_NODELAY (disable/enable Nagle\’s algorithm). –>
<propertyname=”tcpNoDelay”>true</property>
<propertyname=”user”>user</property>
<propertyname=”password”>password</property>
</server>
<connectionmanagerlist>
<connectionmanagername=”defaultManager”>
<classname>com.meidusa.amoeba.net.AuthingableConnectionManager</classname>
</connectionmanager>
</connectionmanagerlist>
<dbserverlist>
<dbservername=”master”>
<factoryconfig>
<classname>com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory</classname>
<propertyname=”manager”>defaultManager</property>
<propertyname=”port”>3306</property>
<propertyname=”ipAddress”>10.0.38.37</property>
<propertyname=”schema”>test</property>
<propertyname=”user”>root</property>
<propertyname=”password”>password</property>
</factoryconfig>
<poolconfig>
<classname>com.meidusa.amoeba.net.poolable.PoolableObjectPool</classname>
<propertyname=”maxActive”>500</property>
<propertyname=”maxIdle”>200</property>
<propertyname=”minIdle”>10</property>
<propertyname=”minEvictableIdleTimeMillis”>600000</property>
<propertyname=”timeBetweenEvictionRunsMillis”>600000</property>
<propertyname=”testOnBorrow”>true</property>
<propertyname=”testWhileIdle”>true</property>
</poolconfig>
</dbserver>
<dbservername=”slave1″>
<factoryconfig>
<classname>com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory</classname>
<propertyname=”manager”>defaultManager</property>
<propertyname=”port”>3306</property>
<propertyname=”ipAddress”>10.0.38.22</property>
<propertyname=”schema”>test</property>
<propertyname=”user”>root</property>
<propertyname=”password”>password</property>
</factoryconfig>
<poolconfig>
<classname>com.meidusa.amoeba.net.poolable.PoolableObjectPool</classname>
<propertyname=”maxActive”>500</property>
<propertyname=”maxIdle”>200</property>
<propertyname=”minIdle”>10</property>
<propertyname=”minEvictableIdleTimeMillis”>600000</property>
<propertyname=”timeBetweenEvictionRunsMillis”>600000</property>
<propertyname=”testOnBorrow”>true</property>
<propertyname=”testWhileIdle”>true</property>
</poolconfig>
</dbserver>
<dbservername=”slave2″>
<factoryconfig>
… …
</factoryconfig>
<poolconfig>
… …
</poolconfig>
</dbserver>
<dbservername=”virtualSlave”virtual=”true”>
<poolconfig>
<classname>com.meidusa.amoeba.server.MultipleServerPool</classname>
<!– 1=ROUNDROBIN , 2=WEIGHTBASED –>
<propertyname=”loadbalance”>1</property>
<propertyname=”poolNames”>slave1,slave2</property>
</poolconfig>
</dbserver>
</dbserverlist>
<queryrouter>
<classname>com.meidusa.amoeba.mysql.parser.MysqlQueryRouter</classname>
<propertyname=”ruleConfig”>${amoeba.home}/conf/rule.xml</property>
<propertyname=”functionConfig”>${amoeba.home}/conf/functionMap.xml</property>
<propertyname=”ruleFunctionConfig”>${amoeba.home}/conf/ruleFunctionMap.xml</property>
<propertyname=”LRUMapSize”>1500</property>
<propertyname=”defaultPool”>master</property>
<propertyname=”writePool”>master</property>
<propertyname=”readPool”>virtualSlave</property>
<propertyname=”needParse”>true</property>
</queryrouter>
</amoeba>
rule.xml配置:
< !DOCTYPEamoeba:ruleSYSTEM”rule.dtd”>
<amoeba:rulexmlns:amoeba=”http://amoeba.meidusa.com/”>
<tablerulename=”test_horiz”schema=”test”defaultPools=”master”>
<rulename=”rule1″>
<parameters>ID</parameters>
<expression>< ![CDATA[ ID <= 100000000]]></expression>
<defaultpools>master</defaultpools>
<readpools>slave1</readpools>
<writepools>master</writepools>
</rule>
<rulename=”rule2″>
<parameters>ID</parameters>
<expression>< ![CDATA[ IDbetween100000001and200000000 ]]></expression>
<defaultpools>master</defaultpools>
<writepools>master2</writepools>
<readpools>slave2</readpools>
</rule>
<rulename=”rule3″>
<parameters>ID</parameters>
<expression>< ![CDATA[ ID> 200000000 ]]></expression>
<defaultpools>master</defaultpools>
</rule>
</tablerule>
<tablerulename=”master”schema=”test”defaultPools=”master”/>
<tablerulename=”slave1″schema=”test”defaultPools=”slave1″/>
<tablerulename=”slave2″schema=”test”defaultPools=”slave2″/>
<tablerulename=”master”schema=”t”defaultPools=”master”/>
</amoeba>
由于第一步主要还只是测试读写分离与数据的垂直切分,所以水平切分的规则设置的很简单,仅仅是按照ID的范围设置简单的规则。而设置一些更为复杂的规则。
总体测试效果还是比较满意的,预期的功能都全部正常,当然所用于测试的SQL语句也大都比较简单,主要还是根据当前工作中遇到的一些SQL。
这次测试没有进行性能测试,等后面再找时间测试一下,不知道有没有哪位朋友已经做过了相应的性能测试没?性能测试之后就要开始规划应用到某些应用上面去了
http://amoeba.sourceforge.net/doc/amoeba_for_mysql.htm
Amoeba For Mysql
Amoeba For Mysql 是 Amoeba项目的子项目。要使用Amoeba For Mysql您必须确保您已符合所有先决条件:
先决条件:
- Java SE 1.5或者以上 Amoeba 框架是基于JDK1.5开发的,采用了JDK1.5的特性。
- 支持Mysql协议版本10(mysql 4.1以后的版本)。
- 您的网络环境至少运行有一个mysql 4.1以上的服务
如何快速配置:
-
配置Server(以下是双核CPU配置,调整线程数可优化性能),配置说明:
配置项 是否必选 默认值 说明 port 否 8066 Amoeba Server绑定的对外端口 ipAddress 否 空 Amoeba绑定的IP user 是 空 客户端连接到Amoeba的用户名 password 否 空 客户端连接到Amoeba所用的密码 readThreadPoolSize 否 16 负责读客户端、databa seserver 端网络数据包线程数 clientSideThreadPoolSize 否 16 负责读执行客户端请求的线程数 serverSideThreadPoolSize 否 16 负责处理服务端返回数据包的线程数
- <server>
- <!– proxy server绑定的端口 –>
- <property name=“port”>2066</property>
- <!– proxy server绑定的IP –>
- <property name=“ipAddress”>127.0.0.1</property>
- <!– proxy server net IO Read thread size –>
- <property name=“readThreadPoolSize”>100</property>
- <!– proxy server client process thread size –>
- <property name=“clientSideThreadPoolSize”>80</property>
- <!– mysql server data packet process thread size –>
- <property name=“serverSideThreadPoolSize”>100</property>
- <!– 对外验证的用户名 –>
- <property name=“user”>root</property>
- <!– 对外验证的密码 –>
- <property name=“password”>password</property>
- </server>
-
配置 ConnectionManager
需要至少配置一个ConnectionManager,每个ConnectionManager将作为一个线程启动,ConnectionManager负责管理所注册在自身的Conneciton、负责他们的空闲检测,死亡检测、IO Event
- <!–
- 每个ConnectionManager都将作为一个线程启动。
- manager负责Connection IO读写/死亡检测
- —>
- <connectionManagerList>
- <connectionManager name=“defaultManager”>
- <className>com.meidusa.amoeba.net.AuthingableConnectionManager</className>
- </connectionManager>
- </connectionManagerList>
-
配置 dbServer ,需要至少配置一个dbServer,每个dbServer将是物理数据库Server的衍射
factoryConfig –目标物理数据库衍射配置情况:
配置项 是否必选 默认值 说明 manager 是 空 表示该dbServer 将注册到指定的ConnectionManager port 否 3306 目标数据库端口 ipAddress 否 127.0.0.1 目标数据库IP schema 否 空 连接初始化的Schema user 是 空 用于登陆目标数据库的用户名 password 否 空 用于登陆目标数据库的密码 className 是 空 连接工厂实现类(com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory) poolConfig — 连接池配置情况:
配置项 是否必选 默认值 说明 className 否 连接池实现类。默认:com.meidusa.amoeba.net.poolable.PoolableObjectPool maxActive 否 8 最大活动连接数,如果达到最大活动连接数,则会等待 maxIdle 否 8 最大的空闲连接数,如果超过则将会关闭多余的空闲连接 minIdle 否 0 最小的空闲连接,连接池将保持最小空闲连接,即使这些连接长久不用 testOnBorrow 否 false 当连接在使用前是否检查连接可用 testWhileIdle 否 fale 是否检测空闲连接,这个参数启动的时候下列2个参数才有效 minEvictableIdleTimeMillis 否 30分钟 连接空闲多少时间将被驱逐(关闭)(time Unit:ms) timeBetweenEvictionRunsMillis 否 -1 用于驱逐空闲连接没间隔多少时间检查一次空闲连接(time Unit:ms)
- <dbServerList>
- <!–
- 一台mysqlServer 需要配置一个pool,
- 如果多台 平等的mysql需要进行loadBalance,
- 平台已经提供一个具有负载均衡能力的objectPool:com.meidusa.amoeba.mysql.server.MultipleServerPool
- 简单的配置是属性加上 virtual=“true”,该Pool 不允许配置factoryConfig 、poolConfig
- —>
- <dbServer name=“server1”>
- <!– PoolableObjectFactory实现类 –>
- <factoryConfig>
- <className>com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory</className>
- <property name=“manager”>defaultManager</property>
- <!– 真实mysql数据库端口 –>
- <property name=“port”>3301</property>
- <!– 真实mysql数据库IP –>
- <property name=“ipAddress”>127.0.0.1</property>
- <!– 用于登陆mysql的用户名 –>
- <property name=“user”>test</property>
- <!– 用于登陆mysql的密码 –>
- <property name=“password”>test</property>
- <property name=“schema”>testSchema</property>
- </factoryConfig>
- <!– ObjectPool实现类 –>
- <poolConfig>
- <className>com.meidusa.amoeba.net.poolable.PoolableObjectPool</className>
- <property name=“maxActive”>200</property>
- <property name=“maxIdle”>200</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>
- </dbServerList>
- QueryRouter 查询路由配置
配置项 | 是否必选 | 默认值 | 说明 |
---|---|---|---|
className | 是 | 空 | QueryRouter实现类,Amoeba For Mysql(com.meidusa.amoeba.mysql.parser.MysqlQueryRouter)。 |
functionConfig | 否 | 空 | 用于解析sql 函数的配置文件,如果不配置则将不解析包含函数sql或者解析的不完整。 |
ruleConfig | 否 | 空 | 数据切分规则配置文件,如果不配置则sql数据切分功能将不能用 |
needParse | 否 | true | 是否对 sql进行parse,如果false 则将不能使用数据切分、读写分离等功能 |
defaultPool | 是 | 空 | needParse=false、无法解析query、不满足切分规则的、writePool|readPool == null情况。 所有sql 将在默认得dbServer上面执行。(必选) |
writePool | 否 | 空 | 启用needParse 功能,并且没有匹配到数据切分规则,则 update、insert、delete 语句将在这个pool中执行 |
readPool | 否 | 空 | 启用needParse 功能,并且没有匹配到数据切分规则,则 select 语句将在这个pool中执行 |
LRUMapSize | 否 | 1000 | statment cache ,存放 sql 解析后得到的statment |
- <queryRouter>
- <className>com.meidusa.amoeba.mysql.parser.MysqlQueryRouter</className>
- <!–
- <property name=“ruleConfig”>./src/conf/rule.xml</property>
- <property name=“functionConfig”>./src/conf/functionMap.xml</property>
- —>
- <property name=“needParse”>false</property>
- <property name=“LRUMapSize”>1500</property>
- <property name=“defaultPool”>server1</property>
- <!–
- <property name=“writePool”>server1</property>
- <property name=“readPool”>server1</property>
- —>
- </queryRouter>
Mysql的主从复制的读写分离之Amoeba实现
以前写过了一篇Mysql的主从复制,但没有实现Mysql的主从复制的读写分离。
关于读写分离:
读写分离(Read/Write Splitting),基本的原理是让主数据库处理事务性增、改、删、操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
关于Mysql的读写分离实现大致有三种:
1、 程序修改Mysql操作类
就以程序来完成Mysql的读写操作,如以PHP程序、java程序等解决此需求。
优点:直接和数据库通信,简单快捷的读写分离和随机的方式实现的负载均衡,权限独立分配
缺点:自己维护更新,增减服务器上的代码处理。
2、 mysql-proxy
MySQL-Proxy是处在你的MySQL数据库客户和服务端之间的程序,它还支持嵌入性脚本语言Lua。这个代理可以用来分析、监控和变换(transform)通信数据,它支持非常广泛的使用场景:
- 负载平衡和故障转移处理
- 查询分析和日志
- SQL宏(SQL macros)
- 查询重写(quer rewriting)
- 执行shell命令
优点:直接实现读写分离和负载均衡,不用修改代码,master和slave用同一个账号
缺点:字符集问题,lua语言编程,还只是alpha版本,时间消耗有点高
3、 Amoeba
参考官网:http://amoeba,meidusa.com/
优点:直接实现读写分离和负载均衡,不用修改代码,有很灵活的数据解决方案
缺点:自己分配账户,和后端数据库权限管理独立,权限处理不够灵活
以上是三种常见的Mysql的读写分离方法。在这建议用第三种也就是amoeba来实现
关于Amoeba
Amoeba(变形虫)项目,该开源框架于2008年开始发布一款Amoeba for Mysql软件。这个软件致力于Mysql的分布式数据库前端代理层,它主要在应用层访问Mysql的时候充当SQL路由功能,专注于分布式数据库代理层(Database Proxy)开发。位于Client、DB Server(s)之间,对客户透明。具有负载均衡、高可用性、SQL过滤、读写分离、可路由相关的到目标数据库、可并发请求多台数据库合并结果。通过Amoeba你能够完成多数据源的高可用、负载均衡、数据切片的功能,目前Amoeba已在很多企业的生产线上使用。
下面就来把 Mysql的主从复制和读写分离完整的实现一下。
先来做Mysql的主从复制。
我实现的环境如下:
System:Centos 5.4 32bit
主:192.168.1.107
从:192.168.1.139
读写分离:192.168.1.183
拓扑图如下:
MySql的主从复制:
对主MysqL服务器,主要是开启二进制日志,这个默认是开启的,在配置文件中:
# vim /etc/my.cnf
server-id = 1 (默认为1)
log-bin = mysql-bin (这个也是默认开启的)
下面连接到mysql数据库中创建一个用户并赋予复制权限。
mysql> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO \’repl\’@\’192.168.1.139\’ IDENTIFIED BY “123456”;
这样在主服务器上操作暂时完成了。
下面来在从服务器上操作:
修改主配置文件:my.cnf
- # vim /etc/my.cnf
- 定位到 server-id = 1
- 修改为:server-id = 2
- 添加如下内容:
- relayrelay-log = relay-bin
- relayrelay-log-index = relay-bin.index
- 修改完成后,保存退出;
- # service mysqld restart
因为在主mysql中已经有数据了,所以要把主服务器的数据导入到从服务器中,所以在主服务器上的操作:
- # mysqldump –all-databases –lock-all-tables –master-data=2 > /tmp/slave.sql
- 导出后复制到从服务器上:
- # scp /tmp/slave.sql 192.168.1.139:/tmp/
- 进入到从服务器上,导入数据。
- # mysql < /tmp/slave.sql
以上操作完成后就可以做把主从连接在一起了。
在从服务器上进入数据库中
- mysql> CHANGE MASTER TO MASTER_HOST=\’192.168.1.107\’,MASTER_USER=\’repl\’,MASTER_PASSWORD=\’123456\’;
下面就可以在从服务器上开启复制了
mysql> start slave;
查看是否连接成功:
- mysql> show slave status\G
- 如下两行出现则表明主从复制成功:
- Slave_IO_Running: Yes
- Slave_SQL_Running: Yes
可在主服务器上创建一个数据库或表来在从服务器上来验证一下。
下面来进行最为核心的内容——读写分离
下面的操作要在读写分离的服务器上操作也就是:192.168.1.183
Amoeba的安装:
安装Amoeba前要先安装JDK,因为Amoeba是用java开发的所要有JDK支持。
- # java -version
- java version “1.6.0_33”
- Java(TM) SE Runtime Environment (build 1.6.0_33-b04)
- Java HotSpot(TM) Server VM (build 20.8-b03, mixed mode)
如果没有安装JDK,要先安装,方法如下 :
- 去oracle官网下载jdk安装包后,安装jdk
- # chmod 755 jdk-6u33-linux-i586.bin
- # ./jdk-6u33-linux-i586.bin
- 默认安装到/usr/java/jdk1.6.0_33
- 下面来修改环境变量:
- # vim /etc/profile
- 添加如下行:
- export JAVA_HOME=/usr/java/jdk1.6.0_33
- export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
- export PATH=$PATH:$JAVA_HOME/bin
- 保存退出!
- # source /etc/profile \\使之生效
- 查看:
- # java -version
- java version “1.6.0_33”
- Java(TM) SE Runtime Environment (build 1.6.0_33-b04)
- Java HotSpot(TM) Server VM (build 20.8-b03, mixed mode)
安装完成后就可以安装Amoeba了
下载:
- wget http://nchc.dl.sourceforge.net/project/amoeba/Amoeba%20for%20mysql/2.x/amoeba-mysql-binary-2.1.0-RC5.tar.gz
安装:
- # mkdir /usr/local/amoeba
- # mv amoeba-mysql-binary-2.1.0-RC5.tar.gz /usr/local/amoeba
- # cd /usr/local/amoeba
- # tar zxvf amoeba-mysql-binary-2.1.0-RC5.tar.gz
解压后就完成了。下面要做的就是配置。
- # cd /usr/local/amoeba \\主要是配置下面两个文件
- dbServer.xml \\ 定义连接数据库的信息
- amoeba.xml \\ 定义读写分离的节点管理信息
下面就来配置一下。
# cd /usr/local/amoeba
# vim dbServer.xml
- <?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,
- 每个dbServer需要配置一个pool,如果多台平等的mysql需要进行loadBalance,
- 平台已经提供一个具有负载均衡能力的objectPool:
- 简单的配置是属性加上virtual=”true”,该Pool不允许配置factoryConfig
- 或者自己写一个ObjectPool
- such as \’multiPool\’ dbServer
- —>
- <dbServer name=“abstractServer” 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>
- <!– 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>
- <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=“master” parent=“abstractServer”> \\定义一个主节点
- <factoryConfig>
- <!– mysql ip –>
- <property name=“ipAddress”>192.168.1.107</property>
- <property name=“user”>root</property> \\连接数据库的用户名
- <property name=“password”>123456</property> \\连接数据库的密码
- </factoryConfig>
- </dbServer>
- <dbServer name=“slave” parent=“abstractServer”> \\定义一个从节点
- <factoryConfig>
- <!– mysql ip –>
- <property name=“ipAddress”>192.168.1.139</property>
- <property name=“user”>root</property>
- <property name=“password”>123456</property>
- </factoryConfig>
- </dbServer>
- \\定义池,把master和slave加入
- <dbServer name=“server1” virtual=“true”> \\server1是要把master节点加入
- <poolConfig class=“com.meidusa.amoeba.server.MultipleServerPool”>
- <!– Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA–> < ! — 负载均衡参数1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA–>
- <property name=“loadbalance”>1</property>
- <!– Separated by commas,such as: server1,server2,server1 –>
- <property name=“poolNames”>master</property> <!–
- 参与该pool负载均衡的poolName列表以逗号分割 这里只一个主节点所以就一个
- –>
- </poolConfig>
- </dbServer>
- <dbServer name=“server2” virtual=“true”> \\server2是要把slave节点加入
- <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”>slave</property>
- </poolConfig>
- </dbServer>
- </amoeba:dbServers>
下面来配置amoeba.xml文件
- <?xml version=“1.0” encoding=“gbk”?>
- <!DOCTYPE amoeba:configuration SYSTEM “amoeba.dtd”>
- <amoeba:configuration xmlns:amoeba=“http://amoeba.meidusa.com/”>
- <proxy>
- <!– service class must implements com.meidusa.amoeba.service.Service –>
- <service name=“Amoeba for Mysql” class=“com.meidusa.amoeba.net.ServerableConnectionManager”>
- <!– port –>
- <property name=“port”>8066</property>
- \\定义amoeba读写分离proxy对外代理的端口
- <!– bind ipAddress –>
- <!–
- <property name=”ipAddress”>127.0.0.1</property> \\这个是绑定端口的ip
- 如新注释掉了,说明8066端口绑定在0.0.0.0/0.0.0.0 上面
- –>
- <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>
- <property name=“authenticator”>
- <bean class=“com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator”>
- <property name=“user”>root</property>
- \\定义通过amoeba登录的用户名
- <property name=“password”>123456</property>
- \\相应的这个就是密码了。 定义proxy的管理帐号密码,客户端和程序只需要连接proxy的帐号密码即可,相当于中间接封装
- <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 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
- \\每个ConnectionManager 都做为一个线程启动
- \\manager 负责Connection IO读写/死亡检测
- —>
- <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>
- <!– 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>
- \\定义默认的池,一些除了SELECT\UPDATE\INSERT\DELETE的语句都会在defaultPool执行
- <property name=“writePool”>server1</property>
- \\定义写的池,这里的server1就是在dbServer.xml中的server1
- <property name=“readPool”>server2</property>
- \\定义读的池,这里的server2就是在dbserver.xml中的server2
- <property name=“needParse”>true</property>
- </queryRouter>
- </amoeba:configuration>
配置完成后就可以启动amoeba了。
- # cd /usr/local/amoeba/bin
- # ./amoeba
- amoeba start|stop
- # ./amoeba start & \\会输出下面的信息
- [1] 6789
- log4j:WARN log4j config load completed from file:/usr/local/amoeba/conf/log4j.xml
- 2012-09-06 17:56:01,619 INFO context.MysqlRuntimeContext – Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-2.1.0-RC5
- log4j:WARN ip access config load completed from file:/usr/local/amoeba/conf/access_list.conf
- 2012-09-06 17:56:01,987 INFO net.ServerableConnectionManager – Amoeba for Mysql listening on 0.0.0.0/0.0.0.0:8066.
- 2012-09-06 17:56:01,992 INFO net.ServerableConnectionManager – Amoeba Monitor Server listening on /127.0.0.1:6376.
- 从上面的信息中可以看到8066端口打开了。可查看进程:
- # ps aux | grep amoeba
- root 6789 4.1 1.5 408940 31908 pts/1 Sl 17:56 0:00 /usr/java/jdk1.6.0_33/bin/java -server -Xms256m -Xmx256m -Xss12sworlds.conf=/usr/local/amoeba/bin/amoeba.classworlds -classpath /usr/local/amoeba/lib/classworlds-1.0.jar org.co
- root 6820 0.0 0.0 5112 680 pts/1 S+ 17:56 0:00 grep amoeba
- # netstat -tlnp
- Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
- tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN –
- tcp 0 0 0.0.0.0:688 0.0.0.0:* LISTEN –
- tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN –
- tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN –
- tcp 0 0 :::8066 :::* LISTEN 6789/java
- tcp 0 0 ::ffff:127.0.0.1:6376 :::* LISTEN 6789/java
- tcp 0 0 :::22 :::* LISTEN –
从上面的一些信息可以看到amoeba已经启动,下面就可以测试一下了。
下面来做一测试:
为了更好的看到测试结果,要做以下这些步骤:
测试之前要先保证amoeba-server有访问两个主从服务器test库的权限,在主mysql上执行:
- mysql> grant all privileges on *.* to \’root\’@\’192.168.1.183\’ identified by “123456”;
- mysql> flush privileges;
- 用户创建完成后就可以登录了
- # mysql -uroot -p123456 -h192.168.1.183 -P8066
下面开始测试:
先让主从开始复制,即在从服务器上执行:
mysql> slave start;
再从读写分离的服务器上登录:
# mysql -uroot -p123456 -h192.168.1.183 -P8066
进入之后,先来创建一个数据库zhou,然后在这个数据库中创建一个表test
mysql> create database zhou;
mysql> use zhou;
mysql> create table test (id int(10), name varchar(20),adress varchar(30));
做完这些,回到从服务器上执行:
mysql> slave stop;
接着在主从服务器上各加入一条不同的数据。
在主上:
mysql> use zhou;
mysql> insert into test (\’1\’,\’zhou\’,\’this_is_master\’);
在从上:
mysql> use zhou;
mysql> insert into test (\’2\’,\’zhou\’,\’this_is_slave\’);
完成后就可以在读写分离服务器上测试读写了
在读写分离服务器上:
mysql> use zhou;
mysql> select * from test;
+——+——+—————+
| id | name | address |
+——+——+—————+
| 2 | zhou | this_is_slave |
+——+——+—————+
1 row in set (0.01 sec)
从结果可以看出数据是读的从服务器上的数据,然后我们直接插入数据,再来测试
mysql> insert into test values(\’3\’,\’hhh\’,\’test_write\’);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+——+——+—————+
| id | name | address |
+——+——+—————+
| 2 | zhou | this_is_slave |
+——+——+—————+
1 row in set (0.00 sec)
结果显示出的数据没有改变,因为我们把主从复制停了,所以数据没有同步,从查询的结果可以看到,数据还是来自从服务器。
然后们再在主服务器上查询可以看到:
mysql> select * from test;
+——+——+————— +
| id | name | address |
+——+——+————— +
| 1 | zhou | this_is_master |
+——+——+————— +
| 3 | hhh | test_write |
+——+——+————— +
从上面的结果可以看出,数据的读写分离成功了。
以上就是mysql数据库的主从复制以及读写分离的整个过程。文中可能还存在不完整或者出错的地方,还请大家指出来,谢谢了。
本文出自 “linux学习” 博客,请务必保留此出处http://zhou123.blog.51cto.com/4355617/983592
http://blog.chinaunix.net/uid-26602509-id-4170596.html
一、利用amoeba实现高可用下的读写分离
1、 关于amoeba的介绍和安装我这里不做介绍了,请查看:http://blog.chinaunix.net/u3/93755/showart.php?id=2363202,有什么问题我们再一起讨论。
2、 Amoeba在mysql-mmm架构下的配置
配置的除了amoeba的监听IP外其他的均采用上面mmm分配的浮动IP,因为当出现故障后,浮动IP会自动分配到正常的server上。amoeba.xml的配置如下:
<?xml version=”1.0″ encoding=”gbk”?>
<!DOCTYPE amoeba:configuration SYSTEM “amoeba.dtd”>
<amoeba:configuration xmlns:amoeba=”http://amoeba.meidusa.com/”>
<server>
<!– proxy server绑定的端口 –>
<property name=”port”>8066</property>
<!– proxy server绑定的IP –>
<property name=”ipAddress”>192.168.1.163</property>
<!– 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>
<!– socket Send and receive BufferSize(unit:K) –>
<property name=”netBufferSize”>128</property>
<!– Enable/disable TCP_NODELAY (disable/enable Nagle\’s algorithm). –>
<property name=”tcpNoDelay”>true</property>
<property name=”user”>root</property>
<property name=”password”>password</property>
<!– query timeout( default: 60 second , TimeUnit:second) –>
<property name=”queryTimeout”>60</property>
</server>
<!–
每个ConnectionManager都将作为一个线程启动。
manager负责Connection IO读写/死亡检测
–>
<connectionManagerList>
<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>
<dbServerList>
<!–
一台mysqlServer 需要配置一个pool,
如果多台 平等的mysql需要进行loadBalance,
平台已经提供一个具有负载均衡能力的objectPool:com.meidusa.amoeba.mysql.server.MultipleServerPool
简单的配置是属性加上 virtual=”true”,该Pool 不允许配置factoryConfig
或者自己写一个ObjectPool。
–>
<dbServer name=”server1″>
<!– PoolableObjectFactory实现类 –>
<factoryConfig class=”com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory”>
<property name=”manager”>defaultManager</property>
<!– 真实mysql数据库端口 –>
<property name=”port”>3306</property>
<!– 真实mysql数据库IP –>
<property name=”ipAddress”>192.168.1.113</property>
<property name=”schema”>test</property>
<!– 用于登陆mysql的用户名 –>
<property name=”user”>zhang</property>
<!– 用于登陆mysql的密码 –>
<property name=”password”>zhang123</property>
</factoryConfig>
<!– ObjectPool实现类 –>
<poolConfig class=”com.meidusa.amoeba.net.poolable.PoolableObjectPool”>
<property name=”maxActive”>200</property>
<property name=”maxIdle”>200</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=”server2″>
<!– PoolableObjectFactory实现类 –>
<factoryConfig class=”com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory”>
<property name=”manager”>defaultManager</property>
<!– 真实mysql数据库端口 –>
<property name=”port”>3306</property>
<!– 真实mysql数据库IP –>
<property name=”ipAddress”>192.168.1.111</property>
<property name=”schema”>test</property>
<!– 用于登陆mysql的用户名 –>
<property name=”user”>zhang</property>
<!– 用于登陆mysql的密码 –>
<property name=”password”>zhang123</property>
</factoryConfig>
<!– ObjectPool实现类 –>
<poolConfig class=”com.meidusa.amoeba.net.poolable.PoolableObjectPool”>
<property name=”maxActive”>200</property>
<property name=”maxIdle”>200</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=”server3″>
<!– PoolableObjectFactory实现类 –>
<factoryConfig class=”com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory”>
<property name=”manager”>defaultManager</property>
<!– 真实mysql数据库端口 –>
<property name=”port”>3306</property>
<!– 真实mysql数据库IP –>
<property name=”ipAddress”>192.168.1.112</property>
<property name=”schema”>test</property>
<!– 用于登陆mysql的用户名 –>
<property name=”user”>zhang</property>
<!– 用于登陆mysql的密码 –>
<property name=”password”>zhang123</property>
</factoryConfig>
<!– ObjectPool实现类 –>
<poolConfig class=”com.meidusa.amoeba.net.poolable.PoolableObjectPool”>
<property name=”maxActive”>200</property>
<property name=”maxIdle”>200</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=”server4″>
<!– PoolableObjectFactory实现类 –>
<factoryConfig class=”com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory”>
<property name=”manager”>defaultManager</property>
<!– 真实mysql数据库端口 –>
<property name=”port”>3306</property>
<!– 真实mysql数据库IP –>
<property name=”ipAddress”>192.168.1.114</property>
<property name=”schema”>test</property>
<!– 用于登陆mysql的用户名 –>
<property name=”user”>zhang</property>
<!– 用于登陆mysql的密码 –>
<property name=”password”>zhang123</property>
</factoryConfig>
<!– ObjectPool实现类 –>
<poolConfig class=”com.meidusa.amoeba.net.poolable.PoolableObjectPool”>
<property name=”maxActive”>200</property>
<property name=”maxIdle”>200</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=”server5″>
<!– PoolableObjectFactory实现类 –>
<factoryConfig class=”com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory”>
<property name=”manager”>defaultManager</property>
<!– 真实mysql数据库端口 –>
<property name=”port”>3306</property>
<!– 真实mysql数据库IP –>
<property name=”ipAddress”>192.168.1.115</property>
<property name=”schema”>test</property>
<!– 用于登陆mysql的用户名 –>
<property name=”user”>zhang</property>
<!– 用于登陆mysql的密码 –>
<property name=”password”>zhang123</property>
</factoryConfig>
<!– ObjectPool实现类 –>
<poolConfig class=”com.meidusa.amoeba.net.poolable.PoolableObjectPool”>
<property name=”maxActive”>200</property>
<property name=”maxIdle”>200</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=”master” virtual=”true”>
<poolConfig class=”com.meidusa.amoeba.server.MultipleServerPool”>
<!– 负载均衡参数 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA–>
<property name=”loadbalance”>1</property>
<!– 参与该pool负载均衡的poolName列表以逗号分割 –>
<property name=”poolNames”>server1</property>
</poolConfig>
</dbServer>
<dbServer name=”slave” virtual=”true”>
<poolConfig class=”com.meidusa.amoeba.server.MultipleServerPool”>
<!– 负载均衡参数 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA–>
<property name=”loadbalance”>1</property>
<!– 参与该pool负载均衡的poolName列表以逗号分割 –>
<property name=”poolNames”>server2,server3,server4,server5</property>
</poolConfig>
</dbServer>
</dbServerList>
<queryRouter class=”com.meidusa.amoeba.mysql.parser.MysqlQueryRouter”>
<property name=”ruleConfig”>${amoeba.home}/conf/rule.xml</property>
<property name=”functionConfig”>${amoeba.home}/conf/functionMap.xml</property>
<property name=”ruleFunctionConfig”>${amoeba.home}/conf/ruleFunctionMap.xml</property>
<property name=”LRUMapSize”>1500</property>
<property name=”defaultPool”>master</property>
<property name=”writePool”>master</property>
<property name=”readPool”>slave</property>
<property name=”needParse”>true</property>
</queryRouter>
</amoeba:configuration>
3、 启动amoeba
/usr/local/amoeba/bin/amoeba &
检验启动是否成功(使用的是默认的8066端口):
[root@server3 ~]# ps aux | grep amoeba
root 15390 0.2 21.7 411800 55684 pts/0 Sl Nov09 0:13 /usr/java/jdk1.6/bin/java -server -Xms256m -Xmx256m -Xss128k -Damoeba.home=/usr/local/amoeba -Dclassworlds.conf=/usr/local/amoeba/bin/amoeba.classworlds -classpath /usr/local/amoeba/lib/classworlds-1.0.jar org.codehaus.classworlds.Launcher
4、 测试
为了有权限,请在所有mysql-server上添加上面配置的用户名和密码,比如:
grant all on test.* to zhang@\’192.168.1.%\’ identified by \’zhang123\’;
flush privileges;
测试的时候比较麻烦,因为如果把主从停掉来看效果的话,mmm会将该同步状态有问题的服务器设置成REPLICATION_FAIL并将该主机上的浮动IP移动到正常服务器,比如:我将server4停掉后,就出出现如下现象:
[root@server3 ~]# mmm_control show
db1(192.168.1.161) master/ONLINE. Roles: reader(192.168.1.114), reader(192.168.1.115)
db2(192.168.1.162) master/ONLINE. Roles: reader(192.168.1.112), writer(192.168.1.113)
db3(192.168.1.164) slave/REPLICATION_FAIL. Roles:
db4(192.168.1.165) slave/ONLINE. Roles: reader(192.168.1.111)
暂时没想到很好的测试办法。读写分离测试没有问题。
最近手头没有空闲的机器来做压力测试。等有了机器了再对这个架构做下压力测试!
二、利用keepalived实现amoeba高可用
Keepalived简介:Keepalived是Linux下面实现VRRP 备份路由的高可靠性运行件。基于Keepalived设计的服务模式能够真正做到主服务器和备份服务器故障时IP瞬间无缝交接。从而提高系统的可用性
1、 keepalived的安装(server6、server7上都要安装):
wget http://www.keepalived.org/software/keepalived-1.1.19.tar.gz
tar zxvf keepalived-1.1.19.tar.gz
cd keepalived-1.1.19
./configure –prefix=/usr/local/keepalived
make
make install
cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
mkdir /etc/keepalived
cd /etc/keepalived/
2、 keepalived的配置
配置server6的keepalived配置文件/etc/keepalived/keepalived.conf,内容如下:
bal_defs {
notification_email {
jimo291@gmail.com
}
notification_email_from jimo291@gmail.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id test1
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
smtp_alert
authentication {
auth_type PASS
auth_pass 123
}
virtual_ipaddress {
192.168.1.170
}
}
配置server6的keepalived配置文件/etc/keepalived/keepalived.conf,内容如下:
bal_defs {
notification_email {
jimo291@gmail.com
}
notification_email_from jimo291@gmail.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id test2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 80
advert_int 1
smtp_alert
authentication {
auth_type PASS
auth_pass 123
}
virtual_ipaddress {
192.168.1.170
}
}
3、 keepalived的启动:
在server6、server7上执行如下命令启动:
/etc/rc.d/init.d/keepalived start
看看server6上是否绑定了虚拟IP192.168.1.170
[root@server6 ~]# ip add | grep 192.168.1.170
inet 192.168.1.170/32 scope global eth0
可以看到已经成功绑定了192.168.1.170。
4、 测试
停掉server6,看看虚拟IP192.168.1.170会不会自动切换到server7上。以及测试mysql -uroot -ppassword -h192.168.1.170登录,看看能否实现读写操作是否正常等等!
备注:最后记得将所有的启动命令都写到/etc/rc.local文件中去,实现开机启动!
关系型数据的分布式处理系统MyCAT
——概述和基本使用教程
日期:2014/12/24
文:阿蜜果
1、 MyCAT概述
1.1 背景
随着传统的数据库技术日趋成熟、计算机网络技术的飞速发展和应用范围的扩充,数据库应用已经普遍建立于计算机网络之上。这时集中式数据库系统表现出它的不足:
(1)集中式处理,势必造成性能瓶颈;
(2)应用程序集中在一台计算机上运行,一旦该计算机发生故障,则整个系统受到影响,可靠性不高;
(3)集中式处理引起系统的规模和配置都不够灵活,系统的可扩充性差。
在这种形势下,集中式数据库将向分布式数据库发展。
1.2 发展历程
MyCAT的诞生,要从其前身Amoeba和Cobar说起。
Amoeba(变形虫)项目,该开源框架于2008年开始发布一款 Amoeba for Mysql软件。这个软件致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当SQL路由功能,专注于分布式数据库代理层(Database Proxy)开发。座落与 Client、DB Server(s)之间,对客户端透明。具有负载均衡、高可用性、SQL过滤、读写分离、可路由相关的到目标数据库、可并发请求多台数据库合并结果。 通过Amoeba你能够完成多数据源的高可用、负载均衡、数据切片的功能,目前Amoeba已在很多企业的生产线上面使用。
阿里巴巴于2012年6月19日,正式对外开源的数据库中间件Cobar,前身是早已经开源的Amoeba,不过其作者陈思儒离职去盛大之后,阿里巴巴内部考虑到Amoeba的稳定性、性能和功能支持,以及其他因素,重新设立了一个项目组并且更换名称为Cobar。Cobar 是由 Alibaba 开源的 MySQL 分布式处理中间件,它可以在分布式的环境下看上去像传统数据库一样提供海量数据服务。
Cobar自诞生之日起, 就受到广大程序员的追捧,但是自2013年后,几乎没有后续更新。在此情况下,MyCAT应运而生,它基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能,以及众多成熟的使用案例使得MyCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,MyCAT能看到更远。目前MyCAT的最新发布版本为1.2版本。
1.3介绍
1.3.1 MyCat的下载方式
MyCAT的SVN地址为:http://code.taobao.org/svn/openclouddb/
目录结构如下图所示:
读者可在doc/1.2子目录,可查看该产品1.2版本的主要文档,如下图所示:
1.3.2 什么是MyCat?
简单的说,MyCAT就是:
- 一个新颖的数据库中间件产品;
- 一个彻底开源的、面向企业应用开发的“大数据库集群”;
- 支持事务、ACID、可以替代MySQL的加强版数据库;
- 一个可以视为“MySQL”集群的企业级数据库,用来替代昂贵的Oracle集群;
- 一个融合内存缓存技术、Nosql技术、HDFS大数据的新型SQL Server;
- 结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品。
1.3.3 MyCat的目标
MyCAT的目标是:低成本的将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。
1.3.4 MyCat的关键特性
· 支持 SQL 92标准;
· 支持MySQL集群,可以作为Proxy使用;
· 支持JDBC连接ORACLE、DB2、SQL Server,将其模拟为MySQL Server使用;
· 支持galera for mysql集群,percona-cluster或者mariadb cluster,提供高可用性数据分片集群;
· 自动故障切换,高可用性;
· 支持读写分离,支持MySQL双主多从,以及一主多从的模式;
· 支持全局表,数据自动分片到多个节点,用于高效表关联查询;
· 支持独有的基于E-R 关系的分片策略,实现了高效的表关联查询;
· 多平台支持,部署和实施简单。
1.3.5 MyCat的优势
· 基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能,以及众多成熟的使用案例使得MyCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,能看到更远。
· 广泛吸取业界优秀的开源项目和创新思路,将其融入到MyCAT的基因中,使得MyCAT在很多方面都领先于目前其他一些同类的开源项目,甚至超越某些商业产品。
· MyCAT背后有一只强大的技术团队,其参与者都是5年以上资深软件工程师、架构师、DBA等,优秀的技术团队保证了MyCAT的产品质量。
· MyCAT并不依托于任何一个商业公司,因此不像某些开源项目,将一些重要的特性封闭在其商业产品中,使得开源项目成了一个摆设。
1.4 总体架构
MyCAT的架构如下图所示:
MyCAT使用MySQL的通讯协议模拟成一个MySQL服务器,并建立了完整的Schema(数据库)、Table (数据表)、User(用户)的逻辑模型,并将这套逻辑模型映射到后端的存储节点DataNode(MySQL Instance)上的真实物理库中,这样一来,所有能使用MySQL的客户端以及编程语言都能将MyCAT当成是MySQLServer来使用,不必开发新的客户端协议。
当MyCAT收到一个客户端发送的SQL请求时,会先对SQL进行语法分析和检查,分析的结果用于SQL路由,SQL路由策略支持传统的基于表格的分片字段方式进行分片,也支持独有的基于数据库E-R关系的分片策略,对于路由到多个数据节点(DataNode)的SQL,则会对收到的数据集进行“归并”然后输出到客户端。
SQL执行的过程,简单的说,就是把SQL通过网络协议发送给后端的真正的数据库上进行执行,对于MySQL Server来说,是通过MySQL网络协议发送报文,并解析返回的结果,若SQL不涉及到多个分片节点,则直接返回结果,写入客户端的SOCKET流中,这个过程是非阻塞模式(NIO)。
DataNode是MyCAT的逻辑数据节点,映射到后端的某一个物理数据库的一个Database,为了做到系统高可用,每个DataNode可以配置多个引用地址(DataSource),当主DataSource被检测为不可用时,系统会自动切换到下一个可用的DataSource上,这里的DataSource即可认为是Mysql的主从服务器的地址。
1.5 逻辑库
与任何一个传统的关系型数据库一样,MyCAT也提供了“数据库”的定义,并有用户授权的功能,下面是MyCAT逻辑库相关的一些概念:
- schema:逻辑库,与MySQL中的Database(数据库)对应,一个逻辑库中定义了所包括的Table。
- table:表,即物理数据库中存储的某一张表,与传统数据库不同,这里的表格需要声明其所存储的逻辑数据节点DataNode,这是通过表格的分片规则定义来实现的,table可以定义其所属的“子表(childTable)”,子表的分片依赖于与“父表”的具体分片地址,简单的说,就是属于父表里某一条记录A的子表的所有记录都与A存储在同一个分片上。
- 分片规则:是一个字段与函数的捆绑定义,根据这个字段的取值来返回所在存储的分片(DataNode)的序号,每个表格可以定义一个分片规则,分片规则可以灵活扩展,默认提供了基于数字的分片规则,字符串的分片规则等。
- dataNode: MyCAT的逻辑数据节点,是存放table的具体物理节点,也称之为分片节点,通过DataSource来关联到后端某个具体数据库上,一般来说,为了高可用性,每个DataNode都设置两个DataSource,一主一从,当主节点宕机,系统自动切换到从节点。
- dataHost:定义某个物理库的访问地址,用于捆绑到dataNode上。
MyCAT目前通过配置文件的方式来定义逻辑库和相关配置:
· MYCAT_HOME/conf/schema.xml中定义逻辑库,表、分片节点等内容;
· MYCAT_HOME/conf/rule.xml中定义分片规则;
· MYCAT_HOME/conf/server.xml中定义用户以及系统相关变量,如端口等。
下图给出了MyCAT 一个可能的逻辑库到物理库(MySQL的完整映射关系),可以看出其强大的分片能力以及灵活的Mysql集群整合能力。
1.6 交流方式
MyCAT的QQ群还比较活跃,都已经900多人,有兴趣的朋友可以加入,群号:106088787。
2、 基本使用教程
2.1 下载和安装
MyCAT使用Java开发,因为用到了JDK 7的部分功能,所以在使用前请确保安装了JDK 7.0,并设置了正确的Java环境变量(可在命令行窗口输入:“java –version”获知是否安装成功,以及获取JDK的版本)。
笔者的Windows操作系统的下载是:
http://code.taobao.org/svn/openclouddb/downloads/old/MyCat-Sever-1.2/
目录下的“Mycat-server-1.2-GA-win.tar.gz ”文件,解压后的目录结构如下图所示:
安装完成后,需要添加MYCAT_HOME环境变量,值对应MyCAT安装的根目录。
目录说明见下表所示:
目录名称 |
说明 |
bin |
存放window版本和linux版本,除了提供封装成服务的版本之外,也提供nowrap的shell脚本命令,方便大家选择和修改。 Windows 下 运行:mycat.bat console 在控制台启动程序,也可以装载成服务,若此程序运行有问题,也可以运行startup_nowrap.bat,确保java命令可以在命令执行。 Warp方式的命令,可以安装成服务并启动或停止。 l mycat install (可选) l mycat start 注意,wrap方式的程序,其JVM配置参数在conf/wrap.conf中,可以修改为合适的参数,参数调整参照http://wrapper.tanukisoftware.com/doc/english/properties.html。 |
conf |
存放配置文件: l server.xml:是Mycat服务器参数调整和用户授权的配置文件。 l schema.xml:是逻辑库定义和表以及分片定义的配置文件。 l rule.xml:是分片规则的配置文件,分片规则的具体一些参数信息单独存放为文件,也在这个目录下,配置文件修改,需要重启MyCAT或者通过9066端口reload。 l wrapper.conf:JVM配置参数等设置。 l log4j.xml:日志存放在logs/mycat.log中,每天一个文件,日志的配置是在conf/log4j.xml中,根据自己的需要,可以调整输出级别为debug,debug级别下,会输出更多的信息,方便排查问题。 |
lib |
MyCAT自身的jar包或依赖的jar包的存放目录。 |
logs |
MyCAT日志的存放目录。日志存放在logs/mycat.log中,每天一个文件 |
2.2 启动和停止
启动前,一般需要修改JVM配置参数,打开conf/wrapper.conf文件,如下行的内容为2G和2048,可根据本机配置情况修改为512M或其它值。
在命令行窗口中进入MyCAT安装解压文件下的bin目录,输入如下命令可安装(可选)、启动和停止MyCAT,参考结果如下所示:
2.3 简单使用教程
2.3.1 安装MySQL以及客户端
安装MySQL服务器和MySQL客户端,笔者使用的MySQL服务器是免安装版本:mysql-noinstall-5.1.73-winx64,MySQL客户端是:Navicat for MySQL,免安装版本安装方法请参考:http://blog.csdn.net/q98842674/article/details/12094777,不再赘述。
2.3.2 创建数据库和表
创建weixin、yixin和sms三个数据库,并分别建立表结构。
2.3.3 垂直切分
2.3.3.1 垂直切分定义
数据的垂直切分,也可以称为纵向切分。将数据库想象成由很多个一大块一大块的“数据块”(表)组成,垂直地将这些“数据块”切开,然后把它们分散到多台数据库主机上面。这样的切分方法就是垂直(纵向)的数据切分。
一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或多个表。而在架构设计中,各个功能模块相互之间的交互点越统一、越少,系统的耦合度就越低,系统各个模块的维护性及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。
2.3.3.2 优缺点
垂直切分优点:
(1)数据库的拆分简单明了,拆分规则明确;
(2)应用程序模块清晰明确,整合容易;
(3)数据维护方便易行,容易定位。
垂直切分缺点:
(1)部分表关联无法在数据库级别完成,要在程序中完成;
(2)对于访问极其频繁且数据量超大的表仍然存在性能瓶颈,不一定能满足要求;
(3)事务处理相对复杂;
(4)切分达到一定程度之后,扩展性会受到限制;
(5)过度切分可能会带来系统过于复杂而难以维护。
2.3.3.3 垂直切分实现
在如下的实例中,需要将
编辑MYCAT_HOME/conf/schema.xml文件,修改dataHost和schema对应的连接信息,weixin、yixin和photo垂直切分后的配置如下所示:
注意:writeHost/readHost中的location,user,password的值需要根据实际的MySQL的连接信息进行修改。
查看conf/server.xml文件,该文件是Mycat服务器参数调整和用户授权的配置文件,默认的MyCat的数据库连接的用户名/密码为test/test,文件内容参考如下:
上述文件中的schemas属性需要配置对应的schema(在schema.xml)中进行配置。
重启MyCAT,使用MySQL客户端连接MyCAT,需要注意的是,默认数据端口为8066,管理端口为9066,在MySQL客户端连接MyCAT时,注意填写端口为8066,用户名/密码根据server.xml中的配置进行填写。
连接后可查看后端连接的三个数据库,如下图所示:
2.3.4 水平分库
2.3.4.1 水平切分定义
水平切分所指的是通过一系列的切分规则将数据水平分布到不同的DB或table中,在通过相应的DB路由 或者table路由规则找到需要查询的具体的DB或者table以进行Query操作,比如根据用户ID将用户表切分到多台数据库上。
将某个访问极其频繁的表再按照某个字段的某种规则来分散到多个表之中,每个表中包含一部分数据。
例如,所有数据都是和用户关联的,那么我们就可以根据用户来进行水平拆分,将不同用户的数据切分到不同的数据库中。
现在互联网非常火爆的web 2.0类型的网站,基本上大部分数据都能够通过会员用户信息关联上,可能很多核心表都非常适合通过会员ID来进行数据的水平切分。而像论坛社区讨论系统,就更容易切分了,非常容易按照论坛编号来进行数据的水平切分。切分之后基本上不会出现各个库之间的交互。
2.3.4.2 优缺点
水平切分的优点:
l 表关联基本能够在数据库端全部完成;
l 不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;
l 应用程序端整体架构改动相对较少;
l 事务处理相对简单;
l 只要切分规则能够定义好,基本上较难遇到扩展性限制。
水平切分的缺点:
l 切分规则相对更为复杂,很难抽象出一个能够满足整个数据库的切分规则;
l 后期数据的维护难度有所增加,人为手工定位数据更困难;
应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。
2.3.4.3 水平切分实现
在一般的应用系统中,用户表及其密切相关的关联表,可根据“用户表”(eg:t_user)中的“用户ID”(user_id)进行水平切分,并基于MyCAT的E-R关系分片策略将其密切相关的表(eg:t_user_class_rel)也分到对应的库中。
(1)创建表结构
在user0~user2创建同样的表结构,t_user和t_user_class_rel的建表语句参考如下:
(2)配置schema.xml文件
首先配置schema.xml文件,添加user0~user3数据库的dataNode设置,并添加t_user和t_user_class_rel表的schema设置,修改后的schema.xml文件内容如下所示:
(3)配置rule.xml文件
在schema.xml的文件内容中可看到t_user表指定的分片规则是rule1,需要在conf/rule.xml文件中设置rule1的规则为根据user_id进行分片,并按照类“org.opencloudb.route.function.PartitionByLong”的规则进行分片,即将user_id模除1024后每256内分到一个数据库中,即模除后0~255到user0数据库库,256~511到user1数据库,512~767到user2数据库,768~1023到user3数据库。
该文件的参考内容如下所示:
(4)配置server.xml文件
在server.xml文件中的schemas属性中添加test_mycat的schema。修改后的文件如下所示:
(5)水平切分测试
重启MyCAT,使用MySQL客户端连接后,连接后可在test_mycat数据库下看到t_user和t_user_class_rel表,如下图所示:
在MySQL客户端连接的MyCat的test_mycat数据库的t_user表运行如下插入语句,插入2000条数据:
而后在MyCAT的test_mycat数据库的t_user表运行select查看记录执行情况。进入localhost的user0~user3数据库,查看数据是否按照之前确定的rule1的规则写入不同的数据库。
读者可在test_mycat数据库的t_user表执行update和delete等语句,并去分库查看执行结果,可得知MyCAT对MySQL客户端基本透明,对程序也几乎透明,在select语句运行时,MyCAT会自行去各个分库按照规则获取合并结果。
接着测试按照ER关系策略分片的t_user_class_rel表是否按照user_id的分片策略,同样user_id的数据分布在同一个user库的t_user表和t_user_class_rel表。
在MyCAT的test_mycat数据库的t_user_class_rel表运行如下语句:
而后在MyCAT的test_mycat数据库的t_user_class_rel表运行select查看记录执行情况。进入localhost的user0~user3数据库,查看数据是否按照之前确定的rule1的规则和ER分片策略写入不同的数据库。
2.3.5 读写分离
2.3.5.1 读写分离定义
为了确保数据库产品的稳定性,很多数据库拥有双机热备功能。也就是,第一台数据库服务器,是对外提供增删改查业务的生产服务器;第二台数据库服务器,仅仅接收来自第一台服务器的备份数据。一般来说,为了配置方便,以及稳定性,这两台数据库服务器,都用的是相同的配置。
在实际运行中,第一台数据库服务器的压力,远远大于第二台数据库服务器。因此,很多人希望合理利用第二台数据库服务器的空闲资源。
从数据库的基本业务来看,数据库的操作无非就是增删改查这4个操作。但对于“增删改”这三个操作,如果是双机热备的环境中做,一台机器做了这三个操作的某一个之后,需要立即将这个操作,同步到另一台服务器上。出于这个原因,第二台备用的服务器,就只做了查询操作。进一步,为了降低第一台服务器的压力,干脆就把查询操作全部丢给第二台数据库服务器去做,第一台数据库服务器就只做增删改了。
2.3.5.2 优缺点
优点:合理利用从数据库服务器的空闲资源。
缺点:本来第二台数据库服务器,是用来做热备的,它就应该在一个压力非常小的环境下,保证运行的稳定性。而读写分离,却增加了它的压力,也就增加了不稳定性。因此,读写分离,实质上是一个在资金比较缺乏,但又需要保证数据安全的需求下,在双机热备方案上,做出的一种折中的扩展方案。
2.3.5.3 读写分离实现
MyCAT的读写分离机制如下:
- 事务内的SQL,全部走写节点,除非某个select语句以注释/*balance*/开头
- 自动提交的select语句会走读节点,并在所有可用读节点中间随机负载均衡
- 当某个主节点宕机,则其全部读节点都不再被使用,因为此时,同步失败,数据已经不是最新的,MyCAT会采用另外一个主节点所对应的全部读节点来实现select负载均衡。
- 当所有主节点都失败,则为了系统高可用性,自动提交的所有select语句仍将提交到全部存活的读节点上执行,此时系统的很多页面还是能出来数据,只是用户修改或提交会失败。
例如将本机作为写库,10.18.96.133作为读库,MyCAT的读写分离的配置如下:
dataHost的balance属性设置为:
- 0,不开启读写分离机制
- 1,全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。
- 2,所有的readHost与writeHost都参与select语句的负载均衡,也就是说,当系统的写操作压力不大的情况下,所有主机都可以承担负载均衡。
一个dataHost元素,表明进行了数据同步的一组数据库,DBA需要保证这一组数据库服务器是进行了数据同步复制的。writeHost相当于Master DB Server,而其下的readHost则是与从数据库同步的Slave DB Server。当dataHost配置了多个writeHost的时候,任何一个writeHost宕机,Mycat 都会自动检测出来,并尝试切换到下一个可用的writeHost。
在没有配置数据同步复制的情况下,重启后进行测试,可使用MySQL客户端直接连接读库,插入几条数据后,使用MySQL客户端连接MyCat,运行select语句验证是否在读库上执行。
2.3.6 全局表
2.3.6.1 全局表定义
一个真实的业务系统中,往往存在大量的类似字典表的表格,它们与业务表之间可能有关系,这种关系,可以理解为“标签”,而不应理解为通常的“主从关系”,这些表基本上很少变动,可以根据主键ID进行缓存,下面这张图说明了一个典型的“标签关系”图:
在分片的情况下,当业务表因为规模而进行分片以后,业务表与这些附属的字典表之间的关联,就成了比较棘手的问题,考虑到字典表具有以下几个特性:
- 变动不频繁;
- 数据量总体变化不大;
- 数据规模不大,很少有超过数十万条记录。
鉴于此,MyCAT定义了一种特殊的表,称之为“全局表”,全局表具有以下特性:
- 全局表的插入、更新操作会实时在所有节点上执行,保持各个分片的数据一致性
- 全局表的查询操作,只从一个节点获取
- 全局表可以跟任何一个表进行JOIN操作
将字典表或者符合字典表特性的一些表定义为全局表,则从另外一个方面,很好的解决了数据JOIN的难题。通过全局表+基于E-R关系的分片策略,MyCAT可以满足80%以上的企业应用开发。
2.3.6.2 全局表实现
(1)创建表结构
在各个库分别创建全局表(例如:t_area)的表结构,表结构保持一致,例如:
(2)配置schema.xml
全局表配置比较简单,不用写Rule规则,在schema.xml中修改test_schema,添加t_area的table子元素,参考如下配置即可:
(3)全局表测试
运行如下insert语句,往test_mycat的t_area表插入10条数据,如下所示:
插入后去user0~user3数据库中查找,可看到这4个库中的t_area表都被插入10条数据。执行select语句能返回t_area表的对应记录,执行update和delete语句能对应对全局表相关的4个库中的记录进行更新和删除操作。
3、 参考文档
(1)《Amoeba使用指南》:http://docs.hexnova.com/amoeba/
(2)《MySQL-5.6.13免安装版配置方法》:
http://blog.csdn.net/q98842674/article/details/12094777
(3)《MyCat inAction中文版》