對於一個大型的互聯網應用,海量數據的存儲和訪問成爲了系統設計的瓶頸問題,對於系統的穩定性和擴展性形成了極大的問題。經過數據切分來提升網站性能,橫向擴展數據層已經成爲架構研發人員首選的方式。mysql
•水平切分數據庫:能夠下降單臺機器的負載,同時最大限度的下降了宕機形成的損失;spring
•負載均衡策略:能夠下降單臺機器的訪問負載,下降宕機的可能性;sql
•集羣方案:解決了數據庫宕機帶來的單點數據庫不能訪問的問題;數據庫
•讀寫分離策略:最大限度了提升了應用中讀取數據的速度和併發量;編程
一、單個表數據量越大,讀寫鎖,插入操做從新創建索引效率越低。服務器
二、單個庫數據量太大(一個數據庫數據量到1T-2T就是極限)mybatis
三、單個數據庫服務器壓力過大架構
四、讀寫速度遇到瓶頸(併發量幾百)併發
解決問題的思路:根據本身的實際狀況,當單表過大的時候進行分表,數據庫過大的時候進行分庫,高併發的狀況考慮讀寫分離和集羣。負載均衡
數據拆分的方式有:分區、分表、分庫
•分區
•就是把一張表的數據分紅N個區塊,在邏輯上看最終只是一張表,但底層是由N個物理區塊組成的
•分表
•就是把一張表按必定的規則分解成N個具備獨立存儲空間的實體表。系統讀寫時須要根據定義好的規則獲得對應的字代表,而後操做它。
•分庫
一旦分表,一個庫中的表會愈來愈多
將整個數據庫比做圖書館,一張表就是一本書。當要在一本書中查找某項內容時,若是不分章節,查找的效率將會降低。而同理,在數據庫中就是分區。
何時考慮使用分區?
•一張表的查詢速度已經慢到影響使用的時候。
•sql通過優化
•數據量大
•表中的數據是分段的
•對數據的操做每每只涉及一部分數據,而不是全部的數據
分區解決的問題
•主要能夠提高查詢效率
何時考慮分表?
•一張表的查詢速度已經慢到影響使用的時候。
•sql通過優化
•數據量大
•當頻繁插入或者聯合查詢時,速度變慢
分表解決的問題
•分表後,單表的併發能力提升了,磁盤I/O性能也提升了,寫操做效率提升了
•查詢一次的時間短了
•數據分佈在不一樣的文件,磁盤I/O性能提升
•讀寫鎖影響的數據量變小
•插入數據庫須要從新創建索引的數據減小
分區和分表的區別與聯繫
•分區和分表的目的都是減小數據庫的負擔,提升表的增刪改查效率。
•分區只是一張表中的數據的存儲位置發生改變,分表是將一張表分紅多張表。
•當訪問量大,且表數據比較大時,兩種方式能夠互相配合使用。
•當訪問量不大,但表數據比較多時,能夠只進行分區。
常見分區分表的規則策略(相似)
•Range(範圍)
•Hash(哈希)
•按照時間拆分
•Hash以後按照分表個數取模
•在認證庫中保存數據庫配置,就是創建一個DB,這個DB單獨保存user_id到DB的映射關係
何時考慮使用分庫?
•單臺DB的存儲空間不夠
•隨着查詢量的增長單臺數據庫服務器已經沒辦法支撐
分庫解決的問題
•其主要目的是爲突破單節點數據庫服務器的 I/O 能力限制,解決數據庫擴展性問題。
垂直拆分
•將系統中不存在關聯關係或者須要join的表能夠放在不一樣的數據庫不一樣的服務器中。
•按照業務垂直劃分。好比:能夠按照業務分爲資金、會員、訂單三個數據庫。
•須要解決的問題:跨數據庫的事務、jion查詢等問題。
水平拆分
•例如,大部分的站點。數據都是和用戶有關,那麼能夠根據用戶,將數據按照用戶水平拆分。
•按照規則劃分,通常水平分庫是在垂直分庫以後的。好比天天處理的訂單數量是海量的,能夠按照必定的規則水平劃分。須要解決的問題:數據路由、組裝。
讀寫分離
•對於時效性不高的數據,能夠經過讀寫分離緩解數據庫壓力。須要解決的問題:在業務上區分哪些業務上是容許必定時間延遲的,以及數據同步問題。
思路:
垂直分庫-->水平分庫-->讀寫分離
問題
•事務的支持,分庫分表,就變成了分佈式事務、
分庫分表後,就成了分佈式事務了。若是依賴數據庫自己的分佈式事務管理功能去執行事務,將付出高昂的性能代價; 若是由應用程序去協助控制,造成程序邏輯上的事務,又會形成編程方面的負擔。
•join時跨庫,跨表的問題
•分庫分表,讀寫分離使用了分佈式,分佈式爲了保證強一致性,必然帶來延遲,致使性能下降,系統的複雜度變高。
分庫分表後表之間的關聯操做將受到限制,咱們沒法join位於不一樣分庫的表,也沒法join分表粒度不一樣的表, 結果本來一次查詢可以完成的業務,可能須要屢次查詢才能完成。 粗略的解決方法: 全局表:基礎數據,全部庫都拷貝一份。 字段冗餘:這樣有些字段就不用join去查詢了。 系統層組裝:分別查詢出全部,而後組裝起來,較複雜。
經常使用的解決方案:
•對於不一樣的方式之間沒有嚴格的界限,特色不一樣,側重點不一樣。須要根據實際狀況,結合每種方式的特色來進行處理。
•選用第三方的數據庫中間件(Atlas,Mycat,TDDL,DRDS),同時業務系統須要配合數據存儲的升級。
單庫單表
•單庫單表是最多見的數據庫設計,例如,有一張用戶(user)表放在數據庫db中,全部的用戶均可以在db庫中的user表中查到。
單庫多表
•隨着用戶數量的增長,user表的數據量會愈來愈大,當數據量達到必定程度的時候對user表的查詢會漸漸的變慢,從而影響整個DB的性能。若是使用mysql, 還有一個更嚴重的問題是,當須要添加一列的時候,mysql會鎖表,期間全部的讀寫操做只能等待。
•能夠經過某種方式將user進行水平的切分,產生兩個表結構徹底同樣的user_0000,user_0001等表,user_0000 + user_0001 + …的數據恰好是一份完整的數據。
多庫多表
隨着數據量增長也許單臺DB的存儲空間不夠,隨着查詢量的增長單臺數據庫服務器已經沒辦法支撐。這個時候能夠再對數據庫進行水平拆分。
總的來講,優先考慮分區。當分區不能知足需求時,開始考慮分表,合理的分表對效率的提高會優於分區。
垂直分庫-->水平分庫-->讀寫分離
一、單庫多表
單庫多表是對數據的水平拆分,多張表的表結構徹底相同,數據按照不一樣的規則進行拆分,存儲到對於的數據表中。
這是我安裝數據的年份進行拆分的數據表,數據存儲的時候根據數據的年份存到對於的表中,咱們的查詢業務也都是按照年份進行,通常沒有跨年份的數據查詢,這樣就避免了多表查詢後數據的合併。
二、多庫單表
徹底相同的數據庫,安裝不一樣規則存儲各自的數據,下面是個人spring boot多數據源配置:
#更多數據源
custom.datasource.names=jiangsu,anhui,shandong,hubei,hunan,fujian
custom.datasource.jiangsu.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.jiangsu.driverClassName=com.mysql.jdbc.Driver
custom.datasource.jiangsu.url=jdbc:mysql://127.0.0.1:3306/nda_jiangsu?useUnicode=yes&characterEncoding=UTF-8
custom.datasource.jiangsu.username=root
custom.datasource.jiangsu.password=
custom.datasource.anhui.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.anhui.driverClassName=com.mysql.jdbc.Driver
custom.datasource.anhui.url=jdbc:mysql://127.0.0.1:3306/nda_anhui?useUnicode=yes&characterEncoding=UTF-8
custom.datasource.anhui.username=root
custom.datasource.anhui.password=
custom.datasource.shandong.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.shandong.driverClassName=com.mysql.jdbc.Driver
custom.datasource.shandong.url=jdbc:mysql://127.0.0.1:3306/nda_shandong?useUnicode=yes&characterEncoding=UTF-8
custom.datasource.shandong.username=root
custom.datasource.shandong.password=
custom.datasource.hubei.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.hubei.driverClassName=com.mysql.jdbc.Driver
custom.datasource.hubei.url=jdbc:mysql://127.0.0.1:3306/nda_hubei?useUnicode=yes&characterEncoding=UTF-8
custom.datasource.hubei.username=root
custom.datasource.hubei.password=
custom.datasource.hunan.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.hunan.driverClassName=com.mysql.jdbc.Driver
custom.datasource.hunan.url=jdbc:mysql://127.0.0.1:3306/nda_hunan?useUnicode=yes&characterEncoding=UTF-8
custom.datasource.hunan.username=root
custom.datasource.hunan.password=
custom.datasource.fujian.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.fujian.driverClassName=com.mysql.jdbc.Driver
custom.datasource.fujian.url=jdbc:mysql://127.0.0.1:3306/nda_fujian?useUnicode=yes&characterEncoding=UTF-8
custom.datasource.fujian.username=root
custom.datasource.fujian.password=
這是按照省進行數據拆分,保證各個省的數據完整性
在相關業務操做的時候,根據用戶所在的省份查詢對應的數據庫:
DynamicDataSourceContextHolder.setDataSourceType(provincename);
三、多庫多表
在介紹多庫多表的時候,給你們介紹一個輕量級分庫分表工具,sharding-jdbc,這是噹噹網本身實現的基本JDBC的數據庫多庫多表解決方案。可讓你在寫業務代碼的時候徹底按照單庫單表進行,多庫多表的問題有sharding-jdbc幫你解決,須要本身實現分庫分表規則接口,配置分庫分表規則。
pom.xml配置
實現分庫規則接口
public class DemoDatabaseShardingAlgorithm implements PreciseShardingAlgorithm{ @Override
public String doSharding(Collectioncollection, PreciseShardingValue preciseShardingValue) {
for (String each : collection) {
System.out.println(each+"=="+preciseShardingValue.getValue());
if (each.endsWith(Long.parseLong(preciseShardingValue.getValue().toString()) % 2+"")) {
return each;
}
}
throw new IllegalArgumentException();
}
}
實現分表規則接口
public class DemoTableShardingAlgorithm implements PreciseShardingAlgorithm{
@Override
public String doSharding(Collectioncollection, PreciseShardingValue preciseShardingValue) {
for (String each : collection) {
System.out.println(each+"=2="+preciseShardingValue.getValue());
if (each.endsWith(Long.parseLong(preciseShardingValue.getValue().toString()) % 2+"")) {
return each;
}
}
throw new IllegalArgumentException();
}
}
調用規則
@Bean(name = "shardingDataSource")
DataSource getShardingDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig;
shardingRuleConfig = new ShardingRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(getUserTableRuleConfiguration());
shardingRuleConfig.getBindingTableGroups().add("user_info");
shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", DemoDatabaseShardingAlgorithm.class.getName()));
shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", DemoTableShardingAlgorithm.class.getName()));
return new ShardingDataSource(shardingRuleConfig.build(createDataSourceMap()));
}
這樣完成之後,業務代碼就能夠徹底按照單表就行書寫,Sharding-JDBC會自動幫你實現分庫分表的數據庫插入,以及查詢時候的多表數據合併。
Sharding-JDBC 採用在 JDBC 協議層擴展分庫分表,是一個以 jar 形式提供服務的輕量級組件,其核心思路是小而美地完成最核心的事情。
Sharding-JDBC 還提供了讀寫分離的能力,用於減輕寫庫的壓力。
此外,Sharding-JDBC 能夠用在 JPA 場景中,如 JPA、Hibernate、Mybatis,Spring JDBC Template 等任何 Java 的 ORM 框架。
而後還有一個第三方插件mycat也能夠實現分庫分表的數據插入和查詢,不過mycat是基於 Proxy,它複寫了 MySQL 協議,將 Mycat Server 假裝成一個 MySQL 數據庫,而 Sharding-JDBC 是基於 JDBC 接口的擴展,是以 jar 包的形式提供輕量級服務的。
在使用中將mycat查詢啓動,它本身就成爲了一個虛擬數據庫,而業務程序是鏈接的mycat的虛擬數據庫的,而後mycat鏈接實際數據庫實現數據的分庫分表。
分庫分表方案產品介紹
目前市面上的分庫分表中間件相對較多,其中基於代理方式的有MySQL Proxy和Amoeba, 基於Hibernate框架的是Hibernate Shards,基於jdbc的有當當sharding-jdbc, 基於mybatis的相似maven插件式的有蘑菇街的蘑菇街TSharding, 經過重寫spring的ibatis template類的Cobar Client。
還有一些大公司的開源產品: