阿里巴巴分布式数据库
——原理、实现和应用
集团共享技术平台
分布式数据库
邱硕
分布式数据库中间件
性能 容量 高可用
数据消费时效性
跨机房数据同步
App
App
App
App
Cobar
Oracle
MySQL
MySQL
MySQL
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Erosa
MySQL
Eromanga
Otter
Oracle
MySQL
MySQL
Otter
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Eromanga
ASC
DW
...
解决数据的性能/容量、可用性、容灾、变更数据消费问题
分布式数据库中间件
性能 容量 高可用
数据消费时效性
跨机房数据同步
App
App
App
App
Cobar
Oracle
MySQL
MySQL
MySQL
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Erosa
MySQL
Eromanga
Oracle
MySQL
MySQL
Otter
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Eromanga
Otter
ASC
DW
...
分布式数据库中间件
性能 容量 高可用
数据消费时效性
跨机房数据同步
App
App
App
App
Cobar
Oracle
MySQL
MySQL
MySQL
Oracle
MySQL
MySQL
Otter
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Eromanga
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Erosa
MySQL
Eromanga
Otter
ASC
DW
...
分布式数据库中间件
性能 容量 高可用
数据消费时效性
跨机房数据同步
App
App
App
App
Cobar
Oracle
MySQL
MySQL
MySQL
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Erosa
MySQL
Eromanga
Oracle
MySQL
MySQL
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Eromanga
Otter
ASC
DW
...
Otter
分布式数据库中间件
性能 容量 高可用
数据消费时效性
跨机房数据同步
App
App
App
App
Cobar
Oracle
MySQL
MySQL
MySQL
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Erosa
MySQL
Eromanga
Oracle
MySQL
MySQL
Otter
Erosa
Oracle
Erosa
MySQL
Erosa
MySQL
Eromanga
Otter
ASC
DW
...
大纲
中间件引入
Cobar策略
系统实现
实施应用
Cobar之前
Oracle单点数据库
性能问题
中文站offer总数:2008年1亿 -> 2011年3亿
高峰时:load 30、cpu使用率90%
数据库连接过多
可用性问题
Standby切换故障
成本和伸缩性问题
依赖高成本的硬件设备
单点:MySQL集群替换Oracle
Oracle
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
Cobar引入 水平拆分
Oracle单点数据库
性能问题
中文站offer总数:08年1亿 -> 今天3亿
高峰时:load 30、cpu使用率90%
数据库连接过多
可用性问题
Standby切换故障
成本和伸缩性问题
依赖高成本的硬件设备
MySQL
MySQL
MySQL
Cobar
App
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
ID MEMBE_ID INFO
4 test1234 …
5 test1234 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
Oracle单点数据库
性能问题
中文站offer总数:08年1亿 -> 今天3亿
高峰时:load 30、cpu使用率90%
数据库连接过多
可用性问题
Standby切换故障
成本和伸缩性问题
依赖高成本的硬件设备
App
MySQL
MySQL
MySQL
App
App
App
App
App
App
App
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
ID MEMBE_ID INFO
4 test1234 …
5 test1234 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
Cobar引入 连接复用
App
MySQL
MySQL
MySQL
Cobar
Proxy
App
App
App
App
App
App
App
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
ID MEMBE_ID INFO
4 test1234 …
5 test1234 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
Cobar引入
Oracle单点数据库
性能问题
中文站offer总数:08年1亿 -> 今天3亿
高峰时:load 30、cpu使用率90%
数据库连接过多
可用性问题
Standby切换故障
成本和伸缩性问题
依赖高成本的硬件设备
MySQL
Cobar
App
X
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
Cobar引入 failover
MySQL Master1
Cobar
App
MySQL Master2
X
MySQL
Replication
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
Cobar引入 failover
Cobar
App
MySQL
Replication
MySQL Master1
MySQL Master2
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
ID MEMBE_ID INFO
1 pavarotti17 …
11 pavarotti17 …
大纲
中间件引入
Cobar策略
系统实现
实施应用
拆分数据表
Oracle
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
MySQL
水平拆分
水平拆分
拆分字段
水平拆分
f(pavarotti17)=库1
f(test1234)=库1
f(test1234)=库1
f(pavarotti17)=库1
f(abcd)=库2
f(abcd)=库2
f(abcd)=库2
库1
库2
拆分字段
ID MEMBE_ID INFO
1 pavarotti17 …
4 test1234 …
5 test1234 …
11 pavarotti17 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
水平拆分
f(abcd)=库2
库1
库2
拆分字段
f(pavarotti17)=库1
f(test1234)=库1
f(test1234)=库1
f(pavarotti17)=库1
f(abcd)=库2
f(abcd)=库2
路由算法
ID MEMBE_ID INFO
1 pavarotti17 …
4 test1234 …
5 test1234 …
11 pavarotti17 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
路由算法
pavarotti17
f(pavarotti17)=库1
路由算法
pavarotti17
部分截取
hash( ) = 3170972965401
路由算法
hash(pavarott) = 3170972965401 % 1024 = 537
0 1023
路由算法
hash(pavarott) = 3170972965401 % 1024 = 537
0 255
256 511
512 767
768 1023
256
256
256
256
分库1
分库2
分库3
分库4
路由算法
hash(pavarott) = 3170972965401 % 1024 = 537
0 255
256 511
512 767
768 1023
256
256
256
256
分库1
分库2
分库3
分库4
路由算法——扩容
hash(pavarott) = 3170972965401 % 1024 = 537
0 127 128 255
256 383 384 511
512 639 640 767
768 895 896 1023
128
128
128
128
128
128
128
128
分库1
分库2
分库3
分库4
路由算法——扩容
hash(pavarott) = 3170972965401 % 1024 = 537
0 127 128 255
256 383 384 511
512 639 640 767
768 895 896 1023
128
128
128
128
128
128
128
128
分库1
分库2
分库3
分库4
分库5
分库6
分库7
分库8
原
分库1
分库2
分库3
分库4
原
原
原
路由算法——非均匀分布
hash(pavarott) = 3170972965401 % 1024 = 537
0 511
512 767
768 895 896 1023
512
256
128
128
分库1
分库2
分库3
分库4
拆分表的数据访问——SQL转发
Cobar
App
select * from tb1 where
member_id=‘test1234’
ID MEMBE_ID INFO
1 pavarotti17 …
4 test1234 …
5 test1234 …
11 pavarotti17 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
Cobar 只转发SQL,不更改SQL内容
拆分表的数据访问——SQL转发
Cobar
App
select * from tb1 where
member_id=‘test1234’
ID MEMBE_ID INFO
1 pavarotti17 …
4 test1234 …
5 test1234 …
11 pavarotti17 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
拆分表的数据访问——SQL转发
Cobar
App
SELECT * FROM tb1
WHERE member_id IN
(‘test1234’,’pavarotti17’,’abcd’)
ID MEMBE_ID INFO
1 pavarotti17 …
4 test1234 …
5 test1234 …
11 pavarotti17 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
拆分表的数据访问——SQL转发
Cobar
App
select * from tb1
where member_id in
(‘test1234’,’pavarotti17’)
select * from tb1
where member_id in
(‘abcd’)
ID MEMBE_ID INFO
1 pavarotti17 …
4 test1234 …
5 test1234 …
11 pavarotti17 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
拆分表的数据访问——结果返回
Result
Merger
前台
通信
ResultSet:row1
row2
ResultSet:row3
row4
row5
ResultSet:row3
row1
row4
row5
row2
ID MEMBE_ID INFO
1 pavarotti17 …
4 test1234 …
5 test1234 …
11 pavarotti17 …
ID MEMBE_ID INFO
3 abcd …
9 abcd …
20 abcd …
多维水平拆分
visit表
SELECT *
FROM visit
WHERE user=‘A’
product user info
Coca-Cola A …
pepsi C …
Fanta D …
Coca-Cola A …
Coca-Cola C …
Fanta B …
7Up D …
pepsi A …
product user info
Coca-Cola A …
Coca-Cola A …
Coca-Cola C …
product user info
pepsi C …
pepsi A …
product user info
Fanta D …
Fanta B …
product user info
7Up D …
多维水平拆分
visit表
SELECT *
FROM visit
WHERE product
= ‘Coca-Cola’
product user info
Coca-Cola A …
pepsi C …
Fanta D …
Coca-Cola A …
Coca-Cola C …
Fanta B …
7Up D …
pepsi A …
product user info
Coca-Cola A …
Coca-Cola A …
pepsi A …
product user info
pepsi C …
Coca-Cola C …
product user info
Fanta D …
7Up D …
product user info
Fanta B …
一张表的多个字段同时作为拆分字段
分库1
分库2
分库3
分库4
分库5
分库6
分库7
分库8
分库9
分库10
分库11
分库12
分库13
分库14
分库15
分库16
product值
Hash取模
user值
Hash取模
0
1
2
3
0
1
2
3
visit表
USER PRODUCT
Hash(“A”)%4 =
分库1
分库2
分库3
分库4
分库5
分库6
分库7
分库8
分库9
分库10
分库11
分库12
分库13
分库14
分库15
分库16
product值
Hash取模
user值
Hash取模
0
1
2
3
0
1
2
3
CocaCola
A
Hash(“CocaCola”)%4 =
SELECT * FROM visit WHERE
product=‘ColaCola’ AND user=‘A’
分库1
分库2
分库3
分库4
分库5
分库6
分库7
分库8
分库9
分库10
分库11
分库12
分库13
分库14
分库15
分库16
product值
Hash取模
user值
Hash取模
0
1
2
3
0
1
2
3
CocaCola
Hash(“CocaCola”)%4 =
SELECT * FROM visit WHERE
product=‘ColaCola’
Hash(“A”)%4 =
A
分库1
分库2
分库3
分库4
分库5
分库6
分库7
分库8
分库9
分库10
分库11
分库12
分库13
分库14
分库15
分库16
product值
Hash取模
user值
Hash取模
0
1
2
3
0
1
2
3
SELECT * FROM visit WHERE
product=‘ColaCola’ AND user=‘A’
Cobar的策略
MySQL集群替代Oracle单点
基于表的水平拆分和分布
根据字段值的一致性Hash分布
多维拆分
数据查询方式
根据where中的拆分字段分发
SQL语句其他元素的处理
将Cobar收到的SQL语句做变换 分发到各个分库执行
对执行结果合并、处理 保证返回前端的内容满足语义
JOIN有限的处理
跨库JOIN问题
SELECT *
FROM tb1 INNER JOIN tb2
ON _ID=
tb1
tb1
tb2
tb2
ID MEMBE_ID
2 zzzz
4 xyzxyz
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID
1 efghijk
3 xxxxxx
5 abcd
ID NAME
2 zzzz
3 xyzxyz
ID MEMBER_ID ID NAME
1 efghijk 4 efghijk
5 abcd 6 abcd
2 zzzz 2 zzzz
4 xyzxyz 3 xyzxyz
迭代查询
SELECT *
FROM tb1 INNER JOIN tb2
ON _ID=
tb1
tb1
tb2
tb2
FOR row1 IN select * FROM tb1{
ADD(
SELECT * FROM tb2 WHERE
= _id
)TO RESULT
}
ID MEMBE_ID
2 zzzz
4 xyzxyz
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID
1 efghijk
3 xxxxxx
5 abcd
ID NAME
2 zzzz
3 xyzxyz
跨库索引
tb1
tb1
tb2
tb2
idx
idx
扫描idx,再根据每一行的id1,id2查到最终结果
ID MEMBE_ID
2 zzzz
4 xyzxyz
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID
1 efghijk
3 xxxxxx
5 abcd
ID NAME
2 zzzz
3 xyzxyz
ID1 ID2 JOIN_COL
2 2 zzzz
4 3 xyzxyz
ID1 ID2 JOIN_COL
1 4 efghijk
5 6 abcd
跨库索引
tb1
tb1
tb2
tb2
SELECT *
FROM tb1 INNER JOIN tb2
ON _ID=
WHERE = 5
SELECT * FROM idx
WHERE id1 = 5
再根据id1,id2查到最终结果
ID MEMBE_ID
2 zzzz
4 xyzxyz
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID
1 efghijk
3 xxxxxx
5 abcd
ID NAME
2 zzzz
3 xyzxyz
跨库索引
tb1
tb1
tb2
tb2
idx
idx
一定以 JOIN_COL 为索引的拆分字段吗?
ID MEMBE_ID
2 zzzz
4 xyzxyz
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID
1 efghijk
3 xxxxxx
5 abcd
ID NAME
2 zzzz
3 xyzxyz
ID1 ID2 JOIN_COL
2 2 zzzz
4 3 xyzxyz
ID1 ID2 JOIN_COL
1 4 efghijk
5 6 abcd
跨库索引
SELECT *
FROM tb1 INNER JOIN tb2
ON _ID=
WHERE >600
tb1
tb1
tb2
tb2
ID MEMBE_ID GMT
2 zzzz 525
4 xyzxyz 1010
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID GMT
1 efghijk 1205
3 xxxxxx 131
5 abcd 604
ID NAME
2 zzzz
3 xyzxyz
跨库索引
tb1
tb1
tb2
tb2
idx
idx
ID MEMBE_ID GMT
2 zzzz 525
4 xyzxyz 1010
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID GMT
1 efghijk 1205
3 xxxxxx 131
5 abcd 604
ID NAME
2 zzzz
3 xyzxyz
ID1 ID2 JOIN_COL
2 2 zzzz
4 3 xyzxyz
ID1 ID2 JOIN_COL
1 4 efghijk
5 6 abcd
跨库索引
tb1
tb1
tb2
tb2
idx
idx
SELECT , tb1.*
FROM idx INNER JOIN tb1
ON =
WHERE >600
SELECT , tb1.*
FROM idx INNER JOIN tb1
ON =
WHERE >600
SELECT *
FROM tb1 INNER JOIN tb2
ON _ID=
WHERE >600
ID MEMBE_ID
2 zzzz
4 xyzxyz
ID NAME
4 efghijk
5 aaaa
6 abcd
ID MEMBE_ID
1 efghijk
3 xxxxxx
5 abcd
ID NAME
2 zzzz
3 xyzxyz
ID1 ID2 JOIN_COL
2 2 zzzz
4 3 xyzxyz
ID1 ID2 JOIN_COL
1 4 efghijk
5 6 abcd
跨库索引
tb1
tb1
tb2
tb2
SELECT *
FROM tb1 INNER JOIN tb2
ON _ID=
WHERE >600
AND >600
idx
ID MEMBE_ID GMT
2 zzzz 525
4 xyzxyz 1010
ID NAME TIME
4 efghijk 123
5 aaaa 922
6 abcd 222
ID MEMBE_ID GMT
1 efghijk 1205
3 xxxxxx 131
5 abcd 604
ID NAME TIME
2 zzzz 1201
3 xyzxyz 1111
ID1 ID2 JOIN_COL TIME
2 2 zzzz 1201
4 3 xyzxyz 1111
跨库索引
索引表的拆分
WHERE条件中的字段所在表的拆分字段,作为索引拆分字段
索引包含
两张表的主键
JOIN字段
WHERE中的其他字段
索引的更新
分布式事务的支持
idx
idx
ID1 ID2 JOIN_COL TIME
2 2 zzzz 1201
4 3 xyzxyz 1111
ID1 ID2 JOIN_COL TIME
1 4 efghijk 123
5 6 abcd 222
Order By/Limit
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
select ... order by c1 limit 0, 6
select ... order by c1 limit 0, 6
select ... order by c1 limit 0, 6
分库1
分库2
分库3
cobar
1, 8, 9
2, 3, 4
limit 1,2
2,3,4
5,6,7
limit 1,2
Order By/Limit
分库1
分库2
分库3
4
5
6
3
2
7
8
10
6
5
1
11
13
14
9
7
3
返回结果
返回结果
返回结果
8
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit
分库1
分库2
分库3
4
5
6
3
2
7
8
10
6
5
1
11
13
14
9
7
3
返回结果
返回结果
返回结果
8
0
最终结果集
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit
分库1
分库2
分库3
4
5
6
3
2
7
8
10
6
5
11
13
14
9
7
3
返回结果
返回结果
返回结果
8
1
最终结果集
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit
分库1
分库2
分库3
4
5
6
3
7
8
10
6
5
11
13
14
9
7
3
返回结果
返回结果
返回结果
8
2
最终结果集
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit
分库1
分库2
分库3
4
5
6
7
8
10
6
5
11
13
14
9
7
3
返回结果
返回结果
返回结果
8
3
最终结果集
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit
分库1
分库2
分库3
4
5
6
7
8
10
6
5
11
13
14
9
7
返回结果
返回结果
返回结果
8
4
最终结果集
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit
最终结果集
分库1
分库2
分库3
5
6
7
8
10
6
5
11
13
14
9
7
返回结果
返回结果
返回结果
8
4
4
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit
最终结果集
分库1
分库2
分库3
4
6
7
8
10
6
5
11
13
14
9
7
返回结果
返回结果
返回结果
8
4
5
SELECT c1 FROM tb1 ORDER BY c1 LIMIT 4, 2
Order By/Limit 方案总结
所有分库都要查询100000002条数据
Cobar需要遍历100000002条数据
select c1 from tb1 order by c1
limit 100000000, 2
对如下SQL
一次交互得到结果
Offset大小有限制
Order By / Limit 优化
目标:解决
查询量大问题
遍历量大问题
前提
各个分库数据分布大致一样
step1:分成3条语句发给分库
select c1 from tb1 order by c1
limit 9999999, 4
select ... order by c1 limit 33333333, 4
select ... order by c1 limit 33333333, 4
select ... order by c1 limit 33333333, 4
分库1
分库2
分库3
找出查询结果中最小和最大值
分库1
分库2
分库3
7
4
5
3
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
step2:以最小值和最大值为界再查询
分库1
分库2
分库3
7
4
5
3
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
3
11
5
3
11
step3:反查出每一个返回结果的offset
分库1
分库2
分库3
7
4
5
3
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
3
11
5
3
11
33333331条
33333333条
33333332条
类似于原始方案
分库1
分库2
分库3
7
4
5
3
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
3
11
5
3
11
9999996
类似于原始方案
分库1
分库2
分库3
7
4
5
3
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
11
5
3
11
9999997
类似于原始方案
分库1
分库2
分库3
7
4
5
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
11
5
3
11
9999998
类似于原始方案
分库1
分库2
分库3
7
4
5
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
11
5
11
9999999
最终结果集
类似于原始方案
最终结果集
分库1
分库2
分库3
7
4
5
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
11
5
11
9999999
类似于原始方案
最终结果集
分库1
分库2
分库3
7
4
5
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
11
5
11
9999999
类似于原始方案
最终结果集
分库1
分库2
分库3
7
4
5
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
11
5
11
9999999
类似于原始方案
最终结果集
分库1
分库2
分库3
7
4
5
8
6
9
10
7
6
11
9
返回结果
返回结果
返回结果
select c1 from tb1 order by c1
limit 9999999, 4
11
5
11
9999999
Order By / Limit 再优化
Step1不必得到全部结果
select min(c1) mi, max(c1) ma from
(select c1 from tb1 order by c1 limit 3333333,4) t
Step2和Step3合并
select * from
(select * from tb1 where c1 between mi and ma) t1, (select count(*) from tb1 where c1 <mi) t2
Group By
SELECT sum(price)
FROM tb1 GROUP BY c1
ID PRICE C1
1 2222
3 131
5 604
7 131
ID PRICE C1
2 604
4 131
6 56
Group By
SELECT sum(price)
FROM tb1 GROUP BY c1
SELECT sum(price), c1
FROM tb1 GROUP BY c1
ORDER BY c1
2222
131
604
56
131
604
ID PRICE C1
1 2222
3 131
5 604
7 131
ID PRICE C1
2 604
4 131
6 56
Group By
SELECT sum(price)
FROM tb1 GROUP BY c1
SELECT sum(price), c1
FROM tb1 GROUP BY c1
ORDER BY c1
2222
131
604
131
604
最终结果集
56
ID PRICE C1
1 2222
3 131
5 604
7 131
ID PRICE C1
2 604
4 131
6 56
Group By
SELECT sum(price)
FROM tb1 GROUP BY c1
SELECT sum(price), c1
FROM tb1 GROUP BY c1
ORDER BY c1
2222
131
604
131
604
最终结果集
56
ID PRICE C1
1 2222
3 131
5 604
7 131
ID PRICE C1
2 604
4 131
6 56
Group By
最终结果集
SELECT sum(price)
FROM tb1 GROUP BY c1
SELECT sum(price), c1
FROM tb1 GROUP BY c1
ORDER BY c1
2222
131
604
604
56
ID PRICE C1
1 2222
3 131
5 604
7 131
ID PRICE C1
2 604
4 131
6 56
Group By
最终结果集
SELECT sum(price)
FROM tb1 GROUP BY c1
SELECT sum(price), c1
FROM tb1 GROUP BY c1
ORDER BY c1
2222
131
604
56
ID PRICE C1
1 2222
3 131
5 604
7 131
ID PRICE C1
2 604
4 131
6 56
Group By
最终结果集
SELECT sum(price)
FROM tb1 GROUP BY c1
SELECT sum(price), c1
FROM tb1 GROUP BY c1
ORDER BY c1
2222
131
604
56
ID PRICE C1
1 2222
3 131
5 604
7 131
ID PRICE C1
2 604
4 131
6 56
SQL执行策略总结
WHERE - 基于SQL转发
JOIN - 迭代 分布式索引
ORDER BY/LIMIT - 多次查询减小数据量
GROUP BY - 增加ORDER BY
Order by 下推限制:不能处理此类SQL: SELECT * FROM tb1, tb2 ORDER BY , ,
Cobar 事务支持
前端连接
sql1
sql2
commit
Cobar 事务支持
前端连接
分库1连接
sql1
sql2
commit
Cobar 事务支持
前端连接
分库1连接
sql1
commit
分库2连接
sql2
分库3连接
sql2
Sql执行中,有一个分库发生错误,则全部回滚。
前端的commit操作会并发转发至后端
Cobar 事务支持
Commit有先后:隔离性问题
Commit有失败:一致性问题
前端连接
分库1连接
sql1
commit
分库2连接
sql2
分库3连接
sql2
Sql执行中,有一个分库发生错误,则全部回滚。
前端的commit操作会并发转发至后端
大纲
中间件引入
Cobar策略
水平拆分的数据分布
几种SQL元素的执行策略
事务策略
系统实现
实施应用
逻辑层次 —— 接口同MySQL
schema
tableSpace
dataNode
data
source
cndb
pc2
主
备
主
备
default
offer[0]
主
备
offer[1]
主
备
detail[0]
主
备
default
default
offer
detail
detail
jdbc:mysql://cobarIp:8066/cndb?user=foo&password=bar
Cobar结构
MySQL
MySQL
MySQL
Front-end Communication
MySQL Protcol Adaptor (BIO)
Application1
MySQL
MySQL
MySQL
Data Nodes
Monitor
Configure
HA Pool
MySQL
MySQL
Processor(1)
Processor(n)
SQL Executor
SQL Router
SQL Parser
Result
Merger
SQL Executor
SQL Router
SQL Parser
Result
Merger
...
Manager
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
Management
Protocol
Cobar结构
MySQL
MySQL
MySQL
Front-end Communication
MySQL Protcol Adaptor (BIO)
Application1
MySQL
MySQL
MySQL
Data Nodes
Monitor
Configure
HA Pool
MySQL
MySQL
Processor(1)
Processor(n)
SQL Executor
SQL Router
SQL Parser
Result
Merger
SQL Executor
SQL Router
SQL Parser
Result
Merger
...
Manager
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
Management
Protocol
JDBC和Server的通信协议
Application1
MySQL
JDBC
Driver
MySQL
Server
MySQL Protocol
JDBC和Server的通信协议
PreparedStatement ps = (
"select * from tb1 where id=?"); (1, 12345);
ResultSet rs = ();
MySQL
Server
Application1
MySQL
JDBC
Driver
JDBC和Server的通信协议
MySQL
Server
Application1
MySQL
JDBC
Driver
PreparedStatement ps = (
"select * from tb1 where id=?"); (1, 12345);
ResultSet rs = ();
<PREPARED>
select * from tb1
where id=?
<OK>
stmt_id/param_num/columm_num
<FIELD>
parameter_type
<EOF>
<FIELD>
column_type
<EOF>
JDBC和Server的通信协议
PreparedStatement ps = (
"select * from tb1 where id=?"); (1, 12345);
ResultSet rs = ();
MySQL
Server
Application1
MySQL
JDBC
Driver
JDBC和Server的通信协议
PreparedStatement ps = (
"select * from tb1 where id=?"); (1, 12345);
ResultSet rs = ();
MySQL
Server
Application1
MySQL
JDBC
Driver
<EXECUTE>
stmt_id {param}+
<HEADER>
field_count
<FIELD>
column_type
<EOF>
<ROW_DATA>
{column_val}+
<ROW_DATA>
{column_val}+
<EOF>
JDBC和Server的通信协议
PreparedStatement ps = (
"select * from tb1 where id=?"); (1, 12345);
ResultSet rs = ();
Application1
MySQL
JDBC
Driver
<EXECUTE>
stmt_id {param}+
<HEADER>
field_count
<FIELD>
column_type
<EOF>
<ROW_DATA>
{column_val}+
<ROW_DATA>
{column_val}+
<EOF>
MySQL
Server
JDBC和Server的通信协议
Statement stmt = ();
ResultSet rs = (
“select * from tb1 where id=12345”);
Application1
MySQL
JDBC
Driver
<QUERY>
sql
<HEADER>
field_count
<FIELD>
column_type
<EOF>
<ROW_DATA>
{column_val}+
<ROW_DATA>
{column_val}+
<EOF>
MySQL
Server
JDBC和Server的通信协议
Statement stmt = ();
ResultSet rs = (
“select * from tb1 where id=12345”);
Application1
MySQL
JDBC
Driver
<QUERY>
sql
<HEADER>
field_count
<FIELD>
column_type
<EOF>
<ROW_DATA>
{column_val}+
<ROW_DATA>
{column_val}+
<EOF>
MySQL
Server
Cobar
Server
Cobar结构
Processor(1)
Processor(n)
MySQL
MySQL
MySQL
Front-end Communication
MySQL Protcol Adaptor (BIO)
Application1
MySQL
MySQL
MySQL
Data Nodes
Monitor
Configure
HA Pool
MySQL
MySQL
SQL Executor
SQL Router
SQL Parser
Result
Merger
SQL Executor
SQL Router
SQL Parser
Result
Merger
...
Manager
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
Management
Protocol
SQL +Parameters
ResultSetMetaData
ResultSet(Rows)
Cobar 通信层
统一管理NIO的Buffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
共16MB
Buffer Pool
Cobar 通信层
统一管理NIO的Buffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
共16MB
Buffer Pool
<QUERY>
select * from tb1 where id=?
Cobar 通信层
统一管理NIO的Buffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
共16MB
Buffer Pool
<QUERY>
select * from tb1 where id=?
Cobar 通信层
统一管理NIO的Buffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
4KB
ByteBuffer
共16MB
Buffer Pool
15万
TPS
Cobar结构
...
MySQL
MySQL
MySQL
Front-end Communication
MySQL Protcol Adaptor (BIO)
Application1
MySQL
MySQL Protocol
MySQL
MySQL
Data Nodes
Monitor
Configure
HA Pool
MySQL
MySQL
Processor(1)
Processor(n)
SQL Executor
SQL Router
Result
Merger
SQL Executor
SQL Router
Result
Merger
Manager
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
Management
Protocol
SQL Parser
SQL Parser
SELECT id, member_id FROM wp_image WHERE member_id = ‘123’
SQL Parser
select
id
member_id
wp_image
=
member_id
‘123’
exprList
from
架构演变
基于JavaCC生成SQL Parser
性能较差,优化不方便
仿照ANTLR生成的Parser结构手写
基于LL(*)的识别器,中间对象过多
基于LL(2)识别器的手写
第一版
第二版
第三版
架构调整
Lexer
token
token
token
token
Char Reader
Expression Parser
DML Parser
SQL String
Lexer
token
Expression Parser
DML Parser
SQL char[]
第三版LL(2)
第二版LL(*)
cache
功能对比
版本:
:
Druid: -r 262
手写v2: -r 95254
基本元素
语法元素
MySQL 语法结构
Identifier
Keyword
Literal
Punctuation
表达式
Table References
Limit
OrderBy
...
Delete
Update
Insert
Replace
Select
Call
Set/Show
SQL语句
Variable
基本元素
Keyword
227个关键字,不区分大小写
Identifier
schema、table、column、index、alias 、keyword…
SELECT aNy FROM t1 WHERE id IN AnY (SELECT id FROM t2)
`select`、table1 ./*spam*/id、7Up
Punctuation
,、:=、>、!、~ …
Variable
User-Def
SystemVariable:@@version
基本元素 - Literal
String Literal
N’abc’、_latin1’abc’、’abc’ ’def’
”abc””d”、’abc\’d’
Number Literal
123、.123、123.、、.123E-4
123e4 vs 123e4f
Hex/Bit Literal
0x89af、x’89af’、0b101011、b’101011’
_latin1 0x89af
基本元素
语法元素
MySQL 语法结构
Identifier
Keyword
Literal
Punctuation
表达式
Table References
Limit
OrderBy
...
Delete
Update
Insert
Replace
Select
Call
Set/Show
SQL语句
Variable
语法元素 – Table References
table_references: table_reference {',' table_reference}
table_reference: table_factor {
['INNER'|'CROSS‘] 'JOIN' table_factor [join_condition]
| 'STRAIGHT_JOIN' table_factor ['ON' conditional_expr]
| ('LEFT'|'RIGHT') ['OUTER‘] 'JOIN' table_reference join_condition
| 'NATURAL' [('LEFT'|'RIGHT') ['OUTER‘] ] 'JOIN' table_factor
}
table_factor:
tbl_name [[’AS’] alias] [index_hint_list]
| table_subquery [’AS’] alias
| '(' table_references ')'
join_condition: 'ON' conditional_expr | 'USING' '('column_list')'
index_hint_list: index_hint {index_hint}
index_hint:
'USE' ('INDEX'|'KEY') [ 'FOR' ('JOIN'|'ORDER' 'BY'|'GROUP' 'BY') ] '(' [index_list] ')'
| 'IGNORE' ('INDEX'|'KEY') [ 'FOR' ('JOIN'|'ORDER' 'BY'|'GROUP' 'BY') ] '(' index_list ')'
| 'FORCE' ('INDEX'|'KEY') [ 'FOR' ('JOIN'|'ORDER' 'BY'|'GROUP' 'BY') ] '(' index_list ')'
index_list: index_name {',' index_name}
MySQL不支持的MySQL语法
table_reference: table_factor 'JOIN' table_factor [join_condition]
table_reference: table_factor 'LEFT' 'JOIN' table_reference join_condition
LEFT JOIN
tb1
t2
JOIN
t3
USING (id)
规则1
规则2
MySQL不支持的MySQL语法
table_reference: table_factor 'JOIN' table_factor [join_condition]
table_reference: table_factor 'LEFT' 'JOIN' table_reference join_condition
LEFT JOIN
tb1
t2
JOIN
t3
USING (id)
table_factor
规则1
规则2
MySQL不支持的MySQL语法
table_reference: table_factor 'JOIN' table_factor [join_condition]
table_reference: table_factor 'LEFT' 'JOIN' table_reference join_condition
LEFT JOIN
tb1
t2
JOIN
t3
USING (id)
table_factor
规则1
规则2
table_reference
table_reference
规则2
table_factor
MySQL不支持的MySQL语法
table_reference: table_factor 'JOIN' table_factor [join_condition]
table_reference: table_factor 'LEFT' 'JOIN' table_reference join_condition
LEFT JOIN
tb1
t2
JOIN
t3
USING (id)
table_factor
table_factor
table_factor
join_condition
规则1
规则2
table_reference
table_reference
规则1
规则2
MySQL不支持的MySQL语法
table_reference: table_factor 'JOIN' table_factor [join_condition]
table_reference: table_factor 'LEFT' 'JOIN' table_reference join_condition
LEFT JOIN
tb1
t2
JOIN
t3
USING (id)
table_factor
table_factor
table_factor
join_condition
规则1
规则2
table_reference
table_reference
ERROR!
规则1
规则2
MySQL不支持的MySQL语法
table_reference: table_factor 'JOIN' table_factor [join_condition]
table_reference: table_factor 'LEFT' 'JOIN' table_reference join_condition
LEFT JOIN
tb1
t2
JOIN
t3
USING (id)
table_factor
table_factor
table_factor
table_reference
join_condition
table_reference
table_factor
table_factor
table_factor
join_condition
规则1
规则2
table_reference
table_reference
ERROR!
规则1
规则1
规则2
规则2
MySQL不支持的MySQL语法
table_reference: table_factor 'JOIN' table_factor [join_condition]
table_reference: table_factor 'LEFT' 'JOIN' table_reference join_condition
LEFT JOIN
tb1
t2
JOIN
t3
USING (id)
table_factor
table_factor
table_factor
table_reference
join_condition
table_reference
table_factor
table_factor
table_factor
join_condition
规则1
规则2
table_reference
table_reference
ERROR!
规则1
规则1
规则2
规则2
Table References的表达式特性
table_references: table_reference {',' table_reference}
table_reference : ’(’ table_references ')'
| ’(’ query { ’UNION’ query} ’)’ [’AS’] alias
query : ’(’ query ’)’ | ’SELECT ...’
( ( select ...) UNOIN (select...) ) AS t1
( ( t1, t2), t3 )
LL(1)
规则1
规则2
规则2
规则1
expr: ’(’ expr ’)’ | tableRefs | subquery
类似于表达式:
基本元素
语法元素
MySQL 语法结构
Identifier
Keyword
Literal
Punctuation
表达式
Table References
Limit
OrderBy
...
Delete
Update
Insert
Replace
Select
Call
Set/Show
SQL语句
Variable
表达式
优先级和结合型
MySQL Manual文档不精确
文档+实验
特殊函数
Keyword作为函数名:23个
INSERT('Quadratic', 3, 4,
'What')
非规则参数列表:13个
SELECT TRIM(BOTH 'x' FROM 'xxxbarx')
特殊Identifier
1 >= any + 2
1 >= any (select …)
simple: "select id from t1“
short: " seLEcT id, member_id , image_path \t , image_size , STATUS, gmt_modified from wp_image wheRe \t\t\n id = ? AND member_id\t=\"
short2: "select count(*) from MESSAGE_REC_RECORD where RECEIVER_VACOUNT =? and RECEIVER_ID in ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? ) and RECEIVER_STATUS in ( ? , ? ) and SPAM_STATUS in ( ? ) and DELETE_STATUS = ?"
long: "select ID, GMT_CREATE, GMT_MODIFIED, INBOX_FOLDER_ID, MESSAGE_ID, FEEDBACK_TYPE, TARGET_ID, TRADE_ID, SUBJECT, SENDER_ID, SENDER_TYPE, S_DISPLAY_NAME, SENDER_STATUS, RECEIVER_ID, RECEIVER_TYPE, R_DISPLAY_NAME, RECEIVER_STATUS, SPAM_STATUS, REPLY_STATUS, ATTACHMENT_STATUS, SENDER_COUNTRY, RECEIVER_COUNTRY,APP_FROM,APP_TO,APP_SOURCE,SENDER_VACOUNT,RECEIVER_VACOUNT, DISTRIBUTE_STATUS,ORG_RECEIVER_ID,CUSTOMER_ID,OPERATOR_ID,OPERATOR_NAME,FOLLOW_STATUS,DELETE_STATUS,FOLLOW_TIME,BATCH_COUNT from MESSAGE_REC_RECORD where RECEIVER_VACOUNT =? and ID = ?"
long2: "select , _CREATE , _MODIFIED , _ID , _COMPANY_ID, _ID, _IP, _TYPE, _COMPANY , _ADDRESS , _COUNTRY , _ZIP , _PHONE , _FAX , _EMAIL , _COMPANY_ID, _ID, _TYPE, _COMPANY , _ADDRESS , _COUNTRY , _ZIP , _PHONE , _FAX , _EMAIL , _ID, _TYPE, _CATEGORY, , _SOURCE , _IDS , , _DISPLAY_NAME , _DISPLAY_NAME , _FEEDBACK_IDS , _MESSAGE , , _FROM,APP_TO,_VACOUNT,_VACOUNT from MESSAGE_DETAIL A,MESSAGE_DETAIL_REMARK_PROPERTIES B where = ? and = "
性能对比
*
单位微秒
GC对比
*
Cobar结构
Processor(1)
Processor(n)
MySQL
MySQL
MySQL
Front-end Communication
Application1
MySQL
MySQL
MySQL
Monitor
Configure
MySQL
MySQL
SQL Executor
SQL Router
SQL Parser
Result
Merger
SQL Executor
SQL Router
SQL Parser
Result
Merger
...
Manager
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
Management
Protocol
MySQL Protcol Adaptor (BIO)
Data Nodes
HA Pool
后台数据访问逻辑层次
数据库连接
基于协议数据包
与MySQL交互
HA Pool
MySQL Protocol Adapter
Data Node
S
M
S
M
S
M
S
M
S
M
ip:port/offer
ip:port/offer
ip:port/ibank
ip:port/ibank
ip:port/ibank
基于MySQL协议
MySQL
新Cobar
select * from offer
select * from offer
基于MySQL协议
MySQL
新Cobar
select * from offer
select * from offer
后台数据访问逻辑层次
主备连接池
S
M
HA Pool
MySQL Protocol Adapter
Data Node
S
M
S
M
S
M
S
M
S
M
后台数据访问逻辑层次
心跳检测后端连接
S
M
S
M
S
M
S
M
S
M
S
M
HA Pool
MySQL Protocol Adapter
Data Node
X
后台数据访问逻辑层次
心跳检测后端连接
主库失效自动切换
至备库
重置池中连接
S
M
S
M
S
M
S
M
S
M
S
M
HA Pool
MySQL Protocol Adapter
Data Node
后台数据访问逻辑层次
水平拆分的分库
分库2
分库3
分库4
分库5
分库6
分库1
S
M
S
M
S
M
S
M
S
M
S
M
HA Pool
MySQL Protocol Adapter
Data Node
灵活的层间对应关系
分库2
分库3
分库4
分库5
分库6
分库1
物理机
S
M
S
M
S
M
S
M
S
M
S
M
物理机
物理机
物理机
物理机
物理机
大纲
中间件引入
Cobar策略
系统实现
MySQL协议 通信 解析 后端连接
实施应用
Cobar 的部署
Cobar集群
Cobar集群
Cobar集群
Cobar集群
Cobar集群
Cobar集群
Cobar集群
...
青岛
杭州
美国
中文站
国际站
offer/ibank/snapshot
……
message
center
hermes
product
...
...
Cobar
Manager
Cobar
Manager
Cobar
Manager
Cobar 的部署
Cobar集群
德胜机房
Cobar集群
兴义机房
Cobar集群
Cobar集群
...
青岛
杭州
美国
...
...
Cobar
Manager
Cobar
Manager
Cobar
Manager
Cobar集群
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
MySQL Protocol
HTTP
数据迁移
场景
MySQL数据库节点扩容
拆分规则更改
目标
迁移过程中应用保持可用
数据不能丢失、多余或者不一致
迁移步骤
数据的全量dump
变更数据的增量dump
路由规则切换
清理
分库1
分库2
分库1
分库2
分库3
数据分片
数量变更
全量dump
分库2
分库1
分库3
分库1
分库2
分库3
全量dump
分库2
分库1
分库3
分库1
分库2
分库3
dump
dump
全量dump
此时仍使用两份分库的拆分规则
分库2
分库1
分库3
invisible
invisible
让绿色数据对SQL语句不可见
… WHERE ( … ) AND 非绿色数据
增量dump
全量dump过程中,数据会持续变更
将binlog同步到新库中
分库2
分库1
分库3
invisible
invisible
binlog
binlog
Apply
Apply
路由规则切换
暂停写入,等待binlog全部同步到新库
将路由规则更新为三个分库
分库2
分库1
分库3
invisible
invisible
binlog
binlog
Apply
Apply
清理
删除老数据
分库2
分库1
分库3
大纲
中间件引入
Cobar策略
系统实现
实施应用
部署结构
平滑迁移
联系我们
解决数据的性能/容量、可用性、容灾、变更数据消费问题
Cobar 只转发SQL,不更改SQL内容
1, 8, 9
2, 3, 4
limit 1,2
2,3,4
5,6,7
limit 1,2
Order by 下推限制:不能处理此类SQL: SELECT * FROM tb1, tb2 ORDER BY , ,
Sql执行中,有一个分库发生错误,则全部回滚。
前端的commit操作会并发转发至后端
Sql执行中,有一个分库发生错误,则全部回滚。
前端的commit操作会并发转发至后端
版本:
:
Druid: -r 262
手写v2: -r 95254
*
单位微秒
*