参考: https://www.jianshu.com/p/5e0062f6cf62
图中是两组分片,红色我们称为shard1,蓝色我们称为shard2
51 52是服务器
两个3307互为主从(双主),3309是本地3307的从库
说明:没有明确说明是只在某一个节点上做的,就是两个节点都做
两台虚拟机 db01 db02
每台创建四个mysql实例:3307 3308 3309 3310
mysql软件我们之前已完成二进制安装,直接初始化即可
我们server-id规划为:db01上是7/8/9/10,db02上是17/18/19/20
"箭头指向谁是主库"
10.0.0.51:3307<-----> 10.0.0.52:3307
10.0.0.51:3309------> 10.0.0.51:3307
10.0.0.52:3309------> 10.0.0.52:3307
两个分片,每个分片四个mysql节点
shard1:
Master:10.0.0.51:3307
slave1:10.0.0.51:3309
Standby Master:10.0.0.52:3307
slave2:10.0.0.52:3309
shard2:
Master:10.0.0.52:3308
slave1:10.0.0.52:3310
Standby Master:10.0.0.51:3308
slave2:10.0.0.51:3310
shard1
10.0.0.51:3307 <----->10.0.0.52:3307
db02
db01
db02
10.0.0.51:3309 ------>10.0.0.51:3307
db01
10.0.0.52:3309 ------>10.0.0.52:3307
db02
shard2
10.0.0.52:3308 <----->10.0.0.51:3308
db01
db02
db01
10.0.0.52:3310 ----->10.0.0.52:3308
db02
10.0.0.51:3310 ----->10.0.0.51:3308
db01
这个复制用户在谁上建都行
注:如果中间出现错误,在每个节点进行执行以下命令
常见方案:
360 Atlas-Sharding 360
Alibaba cobar 阿里
Mycat 开源
TDDL 淘宝
Heisenberg 百度
Oceanus 58同城
Vitess 谷歌
OneProxy
DRDS 阿里云
我们装的是openjdk,不是官方的那个
Mycat-server-xxxxx.linux.tar.gz
http://dl.mycat.io/
配置环境变量
我们mycat的命令也是在bin目录下
启动
8066就是对外提供服务的端口,9066是管理端口
连接mycat:
默认123456
db01:
我们一般先把原schema.xml备份,然后自己新写一个:
xml和html看起来差不多,xml是从下往上调用的
前三行我们不用看,直接从第四行schema开始看起:
定义了schema,然后以/schema结尾
为什么要用逻辑库?
业务透明化
此配置文件就是实现读写分离的配置
重启mycat
读写分离测试
总结:
以上案例实现了1主1从的读写分离功能,写 *** 作落到主库,读 *** 作落到从库.如果主库宕机,从库不能在继续提供服务了。
我们推荐这种架构
一写三读,
不设置双写的原因是:性能没提升多少,反而引起主键冲突的情况
配置文件:
之后重启:mycat restart
真正的 writehost:负责写 *** 作的writehost
standby writeHost :和readhost一样,只提供读服务
我们此处写了两个writehost,默认使用第一个
当写节点宕机后,后面跟的readhost也不提供服务,这时候standby的writehost就提供写服务,
后面跟的readhost提供读服务
测试:
读写分离测试
对db01 3307节点进行关闭和启动,测试读写 *** 作
结果应为另一台(52)的3307(17)是写,3309(19)是读
一旦7号节点恢复,此时因为7落后了,写节点仍是17
balance属性
负载均衡类型,目前的取值有3种:
writeType属性
负载均衡类型,目前的取值有2种:
switchType属性
-1 表示不自动切换
1 默认值,自动切换
2 基于MySQL主从同步的状态决定是否切换 ,心跳语句为 show slave status
datahost其他配置
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
maxCon="1000":最大的并发连接数
minCon="10" :mycat在启动之后,会在后端节点上自动开启的连接线程,长连接,好处是连接速度快,弊端是占内存
tempReadHostAvailable="1"
这个一主一从时(1个writehost,1个readhost时),可以开启这个参数,如果2个writehost,2个readhost时
<heartbeat>select user()</heartbeat> 监测心跳
其他参数sqlMaxLimit自动分页,必须在启用分表的情况下才生效
创建测试库和表:
我们重启mycat后连接到8066
发现跟一个库一样,实际上已经分到不同的物理硬件上了
分片:对一个"bigtable",比如说t3表
热点数据表 核心表
(1)行数非常多,800w下坡
(2)访问非常频繁
分片的目的:
(1)将大数据量进行分布存储
(2)提供均衡的访问路由
分片策略:
范围 range 800w 1-400w 400w01-800w 不适用于业务访问不均匀的情况
取模 mod(取余数) 和节点的数量进行取模
枚举 按枚举的种类分,如移动项目按省份分
哈希 hash
时间 流水
优化关联查询(否则join的表在不同分片上,效率会比单库还要低)
全局表
ER分片
案例:移动统一:先拆出边缘业务,再按地域分片,但对应用来说是统一的
vim rule.xml
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
===================================
vim autopartition-long.txt
0-10=0
11-20=1
创建测试表:
mysql -S /data/3307/mysql.sock -e "use taobaocreate table t3 (id int not null primary key auto_increment,name varchar(20) not null)"
mysql -S /data/3308/mysql.sock -e "use taobaocreate table t3 (id int not null primary key auto_increment,name varchar(20) not null)"
测试:
重启mycat
mycat restart
mysql -uroot -p123456 -h 127.0.0.1 -P 8066
insert into t3(id,name) values(1,'a')
insert into t3(id,name) values(2,'b')
insert into t3(id,name) values(3,'c')
insert into t3(id,name) values(4,'d')
insert into t3(id,name) values(11,'aa')
insert into t3(id,name) values(12,'bb')
insert into t3(id,name) values(13,'cc')
insert into t3(id,name) values(14,'dd')
取余分片方式:分片键(一个列)与节点数量进行取余,得到余数,将数据写入对应节点
vim schema.xml
<table name="t4" dataNode="sh1,sh2" rule="mod-long" />
vim rule.xml
<property name="count">2</property>
准备测试环境
创建测试表:
mysql -S /data/3307/mysql.sock -e "use taobaocreate table t4 (id int not null primary key auto_increment,name varchar(20) not null)"
mysql -S /data/3308/mysql.sock -e "use taobaocreate table t4 (id int not null primary key auto_increment,name varchar(20) not null)"
重启mycat
mycat restart
测试:
mysql -uroot -p123456 -h10.0.0.52 -P8066
use TESTDB
insert into t4(id,name) values(1,'a')
insert into t4(id,name) values(2,'b')
insert into t4(id,name) values(3,'c')
insert into t4(id,name) values(4,'d')
分别登录后端节点查询数据
mysql -S /data/3307/mysql.sock
use taobao
select * from t4
mysql -S /data/3308/mysql.sock
use taobao
select * from t4
t5 表
id name telnum
1 bj 1212
2 sh 22222
3 bj 3333
4 sh 44444
5 bj 5555
sharding-by-intfile
vim schema.xml
<table name="t5" dataNode="sh1,sh2" rule="sharding-by-intfile" />
vim rule.xml
<tableRule name="sharding-by-intfile">
<rule><columns>name</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
<property name="type">1</property>
<property name="defaultNode">0</property>
</function>
partition-hash-int.txt 配置:
bj=0
sh=1
DEFAULT_NODE=1
columns 标识将要分片的表字段,algorithm 分片函数, 其中分片函数配置中,mapFile标识配置文件名称
准备测试环境
mysql -S /data/3307/mysql.sock -e "use taobaocreate table t5 (id int not null primary key auto_increment,name varchar(20) not null)"
mysql -S /data/3308/mysql.sock -e "use taobaocreate table t5 (id int not null primary key auto_increment,name varchar(20) not null)"
重启mycat
mycat restart
mysql -uroot -p123456 -h10.0.0.51 -P8066
use TESTDB
insert into t5(id,name) values(1,'bj')
insert into t5(id,name) values(2,'sh')
insert into t5(id,name) values(3,'bj')
insert into t5(id,name) values(4,'sh')
insert into t5(id,name) values(5,'tj')
a b c d
join
t
select t1.name ,t.x from t1
join t
select t2.name ,t.x from t2
join t
select t3.name ,t.x from t3
join t
使用场景:
如果你的业务中有些数据类似于数据字典,比如配置文件的配置,
常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大,
而且大部分的业务场景都会用到,那么这种表适合于Mycat全局表,无须对数据进行切分,
要在所有的分片上保存一份数据即可,Mycat 在Join *** 作中,业务表与全局表进行Join聚合会优先选择相同分片内的全局表join,
避免跨库Join,在进行数据插入 *** 作时,mycat将把数据分发到全局表对应的所有分片执行,在进行数据读取时候将会随机获取一个节点读取数据。
vim schema.xml
<table name="t_area" primaryKey="id" type="global" dataNode="sh1,sh2" />
后端数据准备
mysql -S /data/3307/mysql.sock
use taobao
create table t_area (id int not null primary key auto_increment,name varchar(20) not null)
mysql -S /data/3308/mysql.sock
use taobao
create table t_area (id int not null primary key auto_increment,name varchar(20) not null)
重启mycat
mycat restart
测试:
mysql -uroot -p123456 -h10.0.0.52 -P8066
use TESTDB
insert into t_area(id,name) values(1,'a')
insert into t_area(id,name) values(2,'b')
insert into t_area(id,name) values(3,'c')
insert into t_area(id,name) values(4,'d')
A
join
B
为了防止跨分片join,可以使用E-R模式
A join B
on a.xx=b.yy
join C
on A.id=C.id
<table name="A" dataNode="sh1,sh2" rule="mod-long">
<childTable name="B" joinKey="yy" parentKey="xx" />
</table>
(1)首先需要下载C#访问MySQL数据库的ADO.NET驱动程序下载地址为:
http://dev.mysql.com/downloads/connector/net/6.0.html
我下载的版本为: mysql-connector-net-6.3.8.msi
下载地址如下url:
http://dev.mysql.com/downloads/mirror.php?id=405442
(2)安装mysql-connector-net
然后直接在Windows *** 作系统安装 mysql-connector-net-6.3.8.msi
默认是安装在C盘:
C:\Program Files\MySQL\MySQL Connector Net 6.3.8\Assemblies
v2.0
v4.0
安装完后我选择的是v2.0版本的
然后在应用工程中引用组件MySQL.Data.dll
(3)封装数据库访问组件DbConnectionMySQL
/// <summary>
/// MySQL数据库
/// 版本 mysql-connector-net-6.3.8.msi
/// vp:hsg
/// create date:2012-02-28
/// </summary>
[Serializable]
public class DbConnectionMySQL : DbConnectionWrapper
{
public DbConnectionMySQL(string pConnectionString)
: base(pConnectionString)
{
this.m_dbconn = new MySqlConnection(pConnectionString)
this.m_DbConnState = DbConnState.Free
}
//--
public override DbDataAdapter GetDbDataAdapter()
{
return new MySqlDataAdapter()
}
public override DbDataAdapter GetDbDataAdapter(DbCommand dbCommand)
{
return new MySqlDataAdapter(dbCommand as MySqlCommand)
}
public override DbCommand GetDbCommand()
{
return new MySqlCommand()
}
public override DbConnection GetDbConnection()
{
return new MySqlConnection()
}
public override DbCommandBuilder GetDbCommandBuilder()
{
return new MySqlCommandBuilder()
}
public override DataProviderType GetCurrentDataProviderType()
{
return DataProviderType.Sql
}
public override bool IsExistsTable(string TableName, string UserName)
{
#region information
bool rbc = false //TABLES表中去查询 table_name
string dSql = "select * from TABLES where table_name='" + TableName + "'"
DataSet ds = this.ExecuteDataSet(dSql)
if (ds != null)
{
if (ds.Tables[0].Rows.Count >0)
{
rbc = true
}
else
{
rbc = false
}
}
else
{
rbc = false
}
return rbc
#endregion
}
public override bool IsExistsField(string FieldName, string TableName)
{
#region information
bool rbc = false
string dSql = ""
dSql = "select * from " + TableName + " where 1<>1"
DataSet ds = this.ExecuteDataSet(dSql)
if (ds != null)
{
DataTable dt = ds.Tables[0]
for (int j = 0j <dt.Columns.Countj++)
{
if (dt.Columns[j].ColumnName.ToString().ToUpper() == FieldName.ToString().ToUpper())
{
rbc = true
goto Return_End
}
}
dt.Dispose()
dt = null
}
ds.Dispose()
ds = null
Return_End:
return rbc
#endregion
}
public override char ParameterChar
{
get
{
return ':' //SQLite的参数符号为:
}
}
public override DbParameter CreateParameter(string name, object value)
{
return new MySqlParameter(name, value)
}
public override DbParameter CreateParameter(string name)
{
DbParameter dbp = new MySqlParameter()
dbp.ParameterName = name
return dbp
}
public override DbParameter CreateParameter(string name, DbType dbtype, object value)
{
DbParameter dbp = new MySqlParameter()
dbp.ParameterName = name
dbp.Value = value
dbp.DbType = dbtype
return dbp
}
public override DbParameter CreateParameter(string name, DbType dbtype, int size, object value)
{
DbParameter dbp = new MySqlParameter()
dbp.ParameterName = name
dbp.Value = value
dbp.DbType = dbtype
dbp.Size = size
return dbp
}
}
(4)客户端访问测试开发实例
public void TestCShape_MySQL()
{
string constr = "server=localhostUser Id=rootpassword=rootDatabase=xp_users"
DbConnectionWrapper dbw = new DbConnectionMySQL(constr)
bool rbc=dbw.TestConnection()
this.Context.Response.Write(rbc)
string x = ""
//删除语句
x = "delete from xp_users"
if (dbw.ExecuteQuery(x) >0)
{
this.Context.Response.Write("删除语句成功!下面是SQL语句<br>" + x)
}
//插入语句
x = "insert into xp_users(gid,uid,uname,sex,email,pwd) values('"
x += "1','hsg77','何XXX',1,'hsg77@163.com','1')"
if (dbw.ExecuteQuery(x) >0)
{
this.Context.Response.Write("插入语句成功!下面是SQL语句<br>"+x)
}
//查询语句
DataTable dt = dbw.ExecuteDataTable("select * from xp_users")
if (dt != null &&dt.Rows.Count >0)
{
this.Context.Response.Write("<br>用户数:"+dt.Rows.Count)
}
if (dt != null)
{
dt.Dispose()
dt = null
}
dbw.Dispose()
dbw = null
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)