当前位置: 首页 > news >正文

构建高性能web之路------mysql读写分离实战

一个完整的mysql读写分离环境包括以下几个部分:

  • 应用程序client
  • database proxy
  • database集群

在本次实战中,应用程序client基于c3p0连接后端的database proxy。database proxy负责管理client实际访问database的路由策略,采用开源框架amoeba。database集群采用mysql的master-slave的replication方案。整个环境的结构图如下所示:

实战步骤与详解

一.搭建mysql的master-slave环境

1)分别在host1(10.20.147.110)和host2(10.20.147.111)上安装mysql(5.0.45),具体安装方法可见官方文档

2)配置master

首先编辑/etc/my.cnf,添加以下配置:

log-bin=mysql-bin #slave会基于此log-bin来做replication
server-id=1 #master的标示
binlog-do-db = amoeba_study #用于master-slave的具体数据库

然后添加专门用于replication的用户:

mysql> GRANT REPLICATION SLAVE ON *.* TO repl@10.20.147.111 IDENTIFIED BY '111111';

重启mysql,使得配置生效:

/etc/init.d/mysqld restart

最后查看master状态:

3)配置slave

首先编辑/etc/my.cnf,添加以下配置:

server-id=2 #slave的标示

配置生效后,配置与master的连接:

mysql> CHANGE MASTER TO
-> MASTER_HOST='10.20.147.110',
-> MASTER_USER='repl',
-> MASTER_PASSWORD='111111',
-> MASTER_LOG_FILE='mysql-bin.000003',
-> MASTER_LOG_POS=161261;

其中MASTER_HOST是master机的ip,MASTER_USER和MASTER_PASSWORD就是我们刚才在master上添加的用户,MASTER_LOG_FILE和MASTER_LOG_POS对应与master status里的信息

最后启动slave:

mysql> start slave;

4)验证master-slave搭建生效

通过查看slave机的log(/var/log/mysqld.log):

100703 10:51:42 [Note] Slave I/O thread: connected to master 'repl@10.20.147.110:3306', replication started in log 'mysql-bin.000003' at position 161261

如看到以上信息则证明搭建成功,如果有问题也可通过此log找原因

二.搭建database proxy

此次实战中database proxy采用amoeba ,它的相关信息可以查阅官方文档,不在此详述

1)安装amoeba

下载amoeba(1.2.0-GA)后解压到本地(D:\openSource\amoeba-mysql-1.2.0-GA),即完成安装

2)配置amoeba

先配置proxy连接和与各后端mysql服务器连接信息(D:\openSource\amoeba-mysql-1.2.0-GA\conf\amoeba.xml):

<server> <!-- proxy server绑定的端口 --> <property name="port">8066</property> <!-- proxy server绑定的IP --> <!-- <property name="ipAddress">127.0.0.1</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">root</property> </server>

以上是proxy提供给client的连接配置

<dbServerList> <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">10.20.147.110</property> <property name="schema">amoeba_study</property> <!-- 用于登陆mysql的用户名 --> <property name="user">root</property> <!-- 用于登陆mysql的密码 --> <property name="password"></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">10.20.147.111</property> <property name="schema">amoeba_study</property> <!-- 用于登陆mysql的用户名 --> <property name="user">root</property> <!-- 用于登陆mysql的密码 --> <property name="password"></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> </dbServerList>

以上是proxy与后端各mysql数据库服务器配置信息,具体配置见注释很明白了

最后配置读写分离策略:

<queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter"> <property name="LRUMapSize">1500</property> <property name="defaultPool">server1</property> <property name="writePool">server1</property> <property name="readPool">server2</property> <property name="needParse">true</property> </queryRouter>

从以上配置不然发现,写操作路由到server1(master),读操作路由到server2(slave)

3)启动amoeba

在命令行里运行D:\openSource\amoeba-mysql-1.2.0-GA\amoeba.bat即可:

log4j:WARN log4j config load completed from file:D:\openSource\amoeba-mysql-1.2.0-GA\conf\log4j.xml
log4j:WARN ip access config load completed from file:D:\openSource\amoeba-mysql-1.2.0-GA/conf/access_list.conf
2010-07-03 09:55:33,821 INFO net.ServerableConnectionManager - Server listening on 0.0.0.0/0.0.0.0:8066.
三.client端调用与测试

1)编写client调用程序

具体程序细节就不详述了,只是一个最普通的基于mysql driver的jdbc的数据库操作程序

2)配置数据库连接

本client基于c3p0,具体数据源配置如下:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:8066/amoeba_study" /> <property name="user" value="root" /> <property name="password" value="root" /> <property name="minPoolSize" value="1" /> <property name="maxPoolSize" value="1" /> <property name="maxIdleTime" value="1800" /> <property name="acquireIncrement" value="1" /> <property name="maxStatements" value="0" /> <property name="initialPoolSize" value="1" /> <property name="idleConnectionTestPeriod" value="1800" /> <property name="acquireRetryAttempts" value="6" /> <property name="acquireRetryDelay" value="1000" /> <property name="breakAfterAcquireFailure" value="false" /> <property name="testConnectionOnCheckout" value="true" /> <property name="testConnectionOnCheckin" value="false" /> </bean>

值得注意是,client端只需连到proxy,与实际的数据库没有任何关系,因此jdbcUrl、user、password配置都对应于amoeba暴露出来的配置信息

3)调用与测试

首先插入一条数据:insert into zone_by_id(id,name) values(20003,'name_20003')

通过查看master机上的日志/var/lib/mysql/mysql_log.log:

100703 11:58:42 1 Query set names latin1
1 Query SET NAMES latin1
1 Query SET character_set_results = NULL
1 Query SHOW VARIABLES
1 Query SHOW COLLATION
1 Query SET autocommit=1
1 Query SET sql_mode='STRICT_TRANS_TABLES'
1 Query SHOW VARIABLES LIKE 'tx_isolation'
1 Query SHOW FULL TABLES FROM `amoeba_study` LIKE 'PROBABLYNOT'
1 Prepare [1] insert into zone_by_id(id,name) values(?,?)
1 Prepare [2] insert into zone_by_id(id,name) values(?,?)
1 Execute [2] insert into zone_by_id(id,name) values(20003,'name_20003')

得知写操作发生在master机上

通过查看slave机上的日志/var/lib/mysql/mysql_log.log:

100703 11:58:42 2 Query insert into zone_by_id(id,name) values(20003,'name_20003')

得知slave同步执行了这条语句

然后查一条数据:select t.name from zone_by_id t where t.id = 20003

通过查看slave机上的日志/var/lib/mysql/mysql_log.log:

100703 12:02:00 33 Query set names latin1
33 Prepare [1] select t.name from zone_by_id t where t.id = ?
33 Prepare [2] select t.name from zone_by_id t where t.id = ?
33 Execute [2] select t.name from zone_by_id t where t.id = 20003

得知读操作发生在slave机上

并且通过查看slave机上的日志/var/lib/mysql/mysql_log.log发现这条语句没在master上执行

通过以上验证得知简单的master-slave搭建和实战得以生效

相关文章:

  • 厦门行
  • iPad 应用感受
  • 浅谈Android系统开发中LOG的使用
  • 系统治理
  • div+css兼容性问题学习总结
  • 英国诗人兰德(1775-18)
  • MEF程序设计指南一:在应用程序中宿主MEF
  • 解决Linux(Fedora Ubuntu)笔记本的待机休眠
  • ExtJS 4中自定义Grid列标题的对齐方式
  • MEF程序设计指南二:Silverlight中使用CompositionInitializer宿主MEF
  • abstract virtual interface区别
  • OpenGL教程之Alpha混合
  • 模式识别与机器学习读书笔记——2.1 Binary Variables
  • 【转】【翻译】Orx官方教程:0.基础(Basic)
  • ASP.NET——/应用程序中的服务器错误
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • Java Agent 学习笔记
  • Java小白进阶笔记(3)-初级面向对象
  • Python打包系统简单入门
  • Shadow DOM 内部构造及如何构建独立组件
  • 读懂package.json -- 依赖管理
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 利用jquery编写加法运算验证码
  • 使用common-codec进行md5加密
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • ​一些不规范的GTID使用场景
  • #WEB前端(HTML属性)
  • (9)STL算法之逆转旋转
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (Java数据结构)ArrayList
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (七)c52学习之旅-中断
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (转)Oracle 9i 数据库设计指引全集(1)
  • (转)winform之ListView
  • .apk文件,IIS不支持下载解决
  • .java 9 找不到符号_java找不到符号
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net FrameWork简介,数组,枚举
  • .NET Reactor简单使用教程
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .net和php怎么连接,php和apache之间如何连接
  • .NET学习全景图