2020-04-19 數(shù)據(jù)庫(kù)的分表分庫(kù)

分表分庫(kù)

垂直拆分

垂直拆分就是要把表按模塊劃分到不同數(shù)據(jù)庫(kù)表中(當(dāng)然原則還是不破壞第三范式),這種拆分在大型網(wǎng)站的演變過(guò)程中是很常見(jiàn)的。當(dāng)一個(gè)網(wǎng)站還在很小的時(shí)候,只有小量的人來(lái)開(kāi)發(fā)和維護(hù),各模塊和表都在一起,當(dāng)網(wǎng)站不斷豐富和壯大的時(shí)候,也會(huì)變成多個(gè)子系統(tǒng)來(lái)支撐,這時(shí)就有按模塊和功能把表劃分出來(lái)的需求。其實(shí),相對(duì)于垂直切分更進(jìn)一步的是服務(wù)化改造,說(shuō)得簡(jiǎn)單就是要把原來(lái)強(qiáng)耦合的系統(tǒng)拆分成多個(gè)弱耦合的服務(wù),通過(guò)服務(wù)間的調(diào)用來(lái)滿足業(yè)務(wù)需求看,因此表拆出來(lái)后要通過(guò)服務(wù)的形式暴露出去,而不是直接調(diào)用不同模塊的表,淘寶在架構(gòu)不斷演變過(guò)程,最重要的一環(huán)就是服務(wù)化改造,把用戶、交易、店鋪、寶貝這些核心的概念抽取成獨(dú)立的服務(wù),也非常有利于進(jìn)行局部的優(yōu)化和治理,保障核心模塊的穩(wěn)定性

垂直拆分用于分布式場(chǎng)景。

水平拆分

上面談到垂直切分只是把表按模塊劃分到不同數(shù)據(jù)庫(kù),但沒(méi)有解決單表大數(shù)據(jù)量的問(wèn)題,而水平切分就是要把一個(gè)表按照某種規(guī)則把數(shù)據(jù)劃分到不同表或數(shù)據(jù)庫(kù)里。例如像計(jì)費(fèi)系統(tǒng),通過(guò)按時(shí)間來(lái)劃分表就比較合適,因?yàn)橄到y(tǒng)都是處理某一時(shí)間段的數(shù)據(jù)。而像SaaS應(yīng)用,通過(guò)按用戶維度來(lái)劃分?jǐn)?shù)據(jù)比較合適,因?yàn)橛脩襞c用戶之間的隔離的,一般不存在處理多個(gè)用戶數(shù)據(jù)的情況,簡(jiǎn)單的按user_id范圍來(lái)水平切分

通俗理解:水平拆分行,行數(shù)據(jù)拆分到不同表中,垂直拆分列,表數(shù)據(jù)拆分到不同表中

水平分割案例

思路:在大型電商系統(tǒng)中,每天的會(huì)員人數(shù)不斷的增加。達(dá)到一定瓶頸后如何優(yōu)化查詢(xún)。

可能大家會(huì)想到索引,萬(wàn)一用戶量達(dá)到上億級(jí)別,如何進(jìn)行優(yōu)化呢?

使用水平分割拆分?jǐn)?shù)據(jù)庫(kù)表。

如何使用水平拆分?jǐn)?shù)據(jù)庫(kù)

使用水平分割拆分表,具體根據(jù)業(yè)務(wù)需求,有的按照注冊(cè)時(shí)間、取摸、賬號(hào)規(guī)則、年份等。


使用取摸方式分表(使用一致性hash算法,對(duì)userid取模,來(lái)分表)

首先我創(chuàng)建三張表?user0 / user1 /user2 , 然后我再創(chuàng)建?uuid表,該表的作用就是提供自增的id。


create table user0(

id int unsigned primary key ,

name varchar(32) not null default '',

pwd ?varchar(32) not null default '')

engine=myisam charset utf8;


create table user1(

id int unsigned primary key ,

name varchar(32) not null default '',

pwd ?varchar(32) not null default '')

engine=myisam charset utf8;


create table user2(

id int unsigned primary key ,

name varchar(32) not null default '',

pwd ?varchar(32) not null default '')

engine=myisam charset utf8;



create table uuid(

id int unsigned primary key auto_increment)engine=myisam charset utf8;


創(chuàng)建一個(gè)demo項(xiàng)目

POM文件

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>1.3.3.RELEASE</version>

</parent>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

</dependencies>

Service代碼

@Service

public?class?UserService {

?

@Autowired

private?JdbcTemplate jdbcTemplate;

?

public?String regit(String name, String pwd) {

// 1.先獲取到 自定增長(zhǎng)ID

String idInsertSQL?= "INSERT INTO uuid VALUES (NULL);";

jdbcTemplate.update(idInsertSQL);

Long insertId?= jdbcTemplate.queryForObject("select last_insert_id()", Long.class);

// 2.判斷存儲(chǔ)表名稱(chēng)

String tableName?= "user"?+ insertId?% 3;

// 3.注冊(cè)數(shù)據(jù)

String insertUserSql?= "INSERT INTO "?+ tableName?+ " VALUES ('"?+ insertId?+ "','"?+ name?+ "','"?+ pwd

+ "');";

System.out.println("insertUserSql:"?+ insertUserSql);

jdbcTemplate.update(insertUserSql);

return?"success";

}

?

public?String get(Long id) {

String tableName?= "user"?+ id?% 3;

String sql?= "select name from "?+ tableName?+ " ?where id="+id;

System.out.println("SQL:"?+ sql);

String name?= jdbcTemplate.queryForObject(sql, String.class);

return?name;

}

?

}


Controller

@RestController

public?class?UserController {

@Autowired

private?UserService userService;

?

@RequestMapping("/regit")

public?String regit(String name, String pwd) {

return?userService.regit(name, pwd);

}

?

@RequestMapping("/get")

public?String get(Long id) {

String name?= userService.get(id);

return?name;

}

?

}

讀寫(xiě)分離:

讀寫(xiě)分離是在優(yōu)化數(shù)據(jù)庫(kù)性能的時(shí)候,常用的技術(shù),因?yàn)樵趯?xiě)數(shù)據(jù)的時(shí)候是會(huì)造成數(shù)據(jù)不安全性能問(wèn)題的,多以比較慢,但是在讀數(shù)據(jù)庫(kù)的時(shí)候是很快的,所以分開(kāi)數(shù)據(jù)能提高性能。


使用數(shù)據(jù)庫(kù)中間件來(lái)實(shí)現(xiàn)分庫(kù)分表:

1、什么是MyCat:?

MyCat是一個(gè)開(kāi)源的分布式數(shù)據(jù)庫(kù)系統(tǒng),是一個(gè)實(shí)現(xiàn)了MySQL協(xié)議的服務(wù)器,前端用戶可以把它看作是一個(gè)數(shù)據(jù)庫(kù)代理,用MySQL客戶端工具和命令行訪問(wèn),而其后端可以用MySQL原生協(xié)議與多個(gè)MySQL服務(wù)器通信,也可以用JDBC協(xié)議與大多數(shù)主流數(shù)據(jù)庫(kù)服務(wù)器通信,其核心功能是分表分庫(kù),即將一個(gè)大表水平分割為N個(gè)小表,存儲(chǔ)在后端MySQL服務(wù)器里或者其他數(shù)據(jù)庫(kù)里。


MyCat發(fā)展到目前的版本,已經(jīng)不是一個(gè)單純的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流數(shù)據(jù)庫(kù),也支持MongoDB這種新型NoSQL方式的存儲(chǔ),未來(lái)還會(huì)支持更多類(lèi)型的存儲(chǔ)。而在最終用戶看來(lái),無(wú)論是那種存儲(chǔ)方式,在MyCat里,都是一個(gè)傳統(tǒng)的數(shù)據(jù)庫(kù)表,支持標(biāo)準(zhǔn)的SQL語(yǔ)句進(jìn)行數(shù)據(jù)的操作,這樣一來(lái),對(duì)前端業(yè)務(wù)系統(tǒng)來(lái)說(shuō),可以大幅降低開(kāi)發(fā)難度,提升開(kāi)發(fā)速度

2、MyCat有哪些作用?

目前雖然傳統(tǒng)關(guān)系數(shù)據(jù)庫(kù)存在一些列的先天弊端,但NoSQL數(shù)據(jù)庫(kù)又將其替代,但是如果傳統(tǒng)數(shù)據(jù)庫(kù)易于擴(kuò)展和分拆就可以極大的避免單機(jī)單庫(kù)在數(shù)據(jù)增刪改查方面的缺陷。MyCat就是為了解決數(shù)據(jù)庫(kù)的分拆和擴(kuò)展而生的開(kāi)源分布式數(shù)據(jù)庫(kù)系統(tǒng)。其最終的目標(biāo)就是低成本地將現(xiàn)有的單機(jī)數(shù)據(jù)庫(kù)和應(yīng)用平滑遷移到“云”端,解決數(shù)據(jù)存儲(chǔ)和業(yè)務(wù)規(guī)模迅速增長(zhǎng)情況下的數(shù)據(jù)瓶頸問(wèn)題。

舉個(gè)簡(jiǎn)單的例子

如果你只是開(kāi)一個(gè)小賣(mài)鋪(小項(xiàng)目) ,那么你一個(gè)人(數(shù)據(jù)庫(kù))就可以了,但是如果你開(kāi)一個(gè)大型購(gòu)物中心(大項(xiàng)目),如果不分部門(mén)的話,人員(數(shù)據(jù))就很難管理,所以按人員不同分了很多部門(mén)(數(shù)據(jù)庫(kù)),但是光有部門(mén),沒(méi)有一個(gè)統(tǒng)一的管理者(mycat),那么各個(gè)部門(mén)的配合和協(xié)調(diào)能力就大大降低了,超市的健康運(yùn)營(yíng)就會(huì)受到影響。而mycat就是這個(gè)管理者,它是對(duì)數(shù)據(jù)庫(kù)層做一個(gè)抽象,來(lái)管理這些數(shù)據(jù)庫(kù),而最上面的應(yīng)用只需要面對(duì)一個(gè)數(shù)據(jù)庫(kù)層的抽象或者說(shuō)數(shù)據(jù)庫(kù)中間件就好了,這就是Mycat的核心作用。?

所以可以這樣理解:數(shù)據(jù)庫(kù)是對(duì)底層存儲(chǔ)文件的抽象,而Mycat是對(duì)數(shù)據(jù)庫(kù)的抽象。

2.1.一般數(shù)據(jù)庫(kù)的拆表機(jī)制


2.2.MyCat中間件和應(yīng)用層解決方案對(duì)比


3、MyCa的原理

MyCat技術(shù)原理中最重要的一個(gè)動(dòng)詞是“攔截”,它攔截了用戶發(fā)送過(guò)來(lái)的SQL語(yǔ)句,首先對(duì)SQL語(yǔ)句做了一些特定的分析:如分片分析、路由分析、讀寫(xiě)分離分析、緩存分析等,然后將此SQL發(fā)往后端的真實(shí)數(shù)據(jù)庫(kù),并將返回的結(jié)果做適當(dāng)?shù)奶幚?,最終再返回給用戶。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容