您好,登錄后才能下訂單哦!
MySQL的分庫分表有兩種方式:垂直拆分和水平拆分。
垂直拆分:垂直拆分就是要把表按模塊劃分到不同數據庫表中(當然原則還是不破壞第三范式),這種拆分在大型網站的演變過程中是很常見的。當一個網站還在很小的時候,只有小量的人來開發和維護,各模塊和表都在一起,當網站不斷豐富和壯大的時候,也會變成多個子系統來支撐,這時就有按模塊和功能把表劃分出來的需求。其實,相對于垂直切分更進一步的是服務化改造,說得簡單就是要把原來強耦合的系統拆分成多個弱耦合的服務,通過服務間的調用來滿足業務需求看,因此表拆出來后要通過服務的形式暴露出去,而不是直接調用不同模塊的表。(垂直拆分用于分布式場景)
水平拆分:解決單表大數據量的問題,水平切分就是要把一個表按照某種規則把數據劃分到不同表或數據庫里。例如:在大型電商系統中,每天的會員人數不斷的增加。達到一定瓶頸后如何優化查詢。通過將表數據水平分割成不同的表來實現優化。(實現規則:hash、時間、不同的維度)
通俗理解:水平拆分行,行數據拆分到不同表中, 垂直拆分列,表數據拆分到不同表中。
分表原理:取模拆分(一致性hash),可以將數據分配的比較均勻。
這里我們以3張表為例:
案例:首先我創建三張表 user0 / user1 /user2 , 然后我再創建 uuid表,該表的作用就是提供自增的id。
代碼實現:
-- 建表語句
create table user0(
id int unsigned primary key ,
name varchar(22) not null default '',
pwd varchar(22) not null default '')
engine=myisam charset utf8;
create table user1(
id int unsigned primary key ,
name varchar(22) not null default '',
pwd varchar(22) not null default '')
engine=myisam charset utf8;
create table user2(
id int unsigned primary key ,
name varchar(22) not null default '',
pwd varchar(22) not null default '')
engine=myisam charset utf8;
create table uuid(
id int unsigned primary key auto_increment)engine=myisam charset utf8;
//分表邏輯
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public String regit(String name, String pwd) {
// 1.先獲取到 自定增長ID
String idInsertSQL = "INSERT INTO uuid VALUES (NULL);";
jdbcTemplate.update(idInsertSQL);
Long insertId = jdbcTemplate.queryForObject("select last_insert_id()", Long.class);
// 2.判斷存儲表名稱
String tableName = "user" + insertId % 3;
// 3.注冊數據
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;
}
}
上圖中192.168.8.40是主節點(MYSQL-A),192.168.8.41是從節點(MYSQL-B)。
影響MySQL-A數據庫的操作,在數據庫執行后,都會寫入本地的日志系統A中。 假設,實時的將變化了的日志系統中的數據庫事件操作,在MYSQL-A的3306端口,通過網絡發給MYSQL-B。 MYSQL-B收到后,寫入本地日志系統B,然后一條條的將數據庫事件在數據庫中完成。那么,MYSQL-A的變化,MYSQL-B也會變化,這樣就是所謂的MYSQL的復制,即MYSQL replication。
MYSQL的日志類型中的二進制日志,也就是專門用來保存修改數據庫表的所有動作,即bin log。【注意MYSQL會在執行語句之后,釋放鎖之前,寫入二進制日志,確保事務安全】
日志系統B,并不是二進制日志,由于它是從MYSQL-A的二進制日志復制過來的,并不是自己的數據庫變化產生的,有點接力的感覺,稱為中繼日志,即relay log。
主從復制,所產生的問題:
- 主服務器如何實現負載均衡、高可用。
- 如何保證數據不丟失。
- 如何保證主從數據一致性。
簡介:在數據庫集群架構中,讓主庫負責處理事務性查詢,而從庫只負責處理select查詢,讓兩者分工明確達到提高數據庫整體讀寫性能。當然,主數據庫另外一個功能就是負責將事務性查詢導致的數據變更同步到從庫中,也就是寫操作。
寫分離的好處:分攤服務器壓力,提高機器的系統處理效率。增加冗余,提高服務器性能,當一臺服務器宕機后可以從另一個庫以最快的方式恢復服務。
環境介紹:
① 安裝MySQL
#這里小編是通過rpm&&yum安裝的MySQL
#下載安裝包
$wget http://repo.mysql.com/mysql57-community-release-el7-8.noarch.rpm
#安裝
$rpm -ivh mysql57-community-release-el7-8.noarch.rpm
$yum install mysql-server
#啟動MySQL服務
$systemctl start mysqld
#查看root初始密碼
$grep 'temporary password' /var/log/mysqld.log
#重設root密碼
$mysql_secure_installation
注意:
這里配置N,不然的話無法使用root登錄MySQL。
#修改root密碼并設置可以遠程訪問:
mysql> use mysql;
mysql> update user set authentication_string=password("123456") where user="root";
mysql> flush privileges;
mysql> select 'host','user' from user where user='root';
mysql> UPDATE user SET grant_priv = 'Y' WHERE user = 'root';
mysql> select host,user from user;
mysql> update user set host = '%' where user = 'root';
mysql> select host,user from user;
mysql> flush privileges;
mysql> quit
#測試是否配置成功
$mysql -uroot -p -h 192.168.xxx.xxx
② 創建數據庫
分別在master和slave中創建一個數據庫:
mysql> create database test;
注意:這里從數據庫中一定要存在于主數據庫中同步的庫,否則在同步時會報錯:
③ 修改master中的配置
$vim /etc/my.cnf
#master 加入
server-id=1
log-bin=mysql-bin
log-slave-updates=1
#需要同步的數據庫
binlog-do-db=test
#被忽略的數據
binlog-ignore-db=mysql
④ 在master中創建salve同步賬號
mysql> grant replication slave on *.* to 'user1'@'192.168.130.133' identified by 'Zy.123456';
mysql> flush privileges;
⑤ 重啟master并查看日志情況
$systemctl restart mysqld
mysql> show master status;
⑥ 修改slave中MySQL的配置
#slave 加入
server-id=2
log-bin= mysql-bin
relay-log= mysql-relay-bin
read-only=1
log-slave-updates=1
#要同步的數據庫,不寫本行表示同步所有數據庫
replicate-do-db=test
⑦ 重啟slave并驗證是否可以連接master
$systemctl restart mysqld
$mysql -uuser1 -p123456 -h 192.168.130.133
mysql> show grants for user1@192.168.130.133;
⑧ 設置slave復制 并啟動slave
mysql>change master to master_host='192.168.130.134',master_user='user1',master_password='Zy.123456';
-- 啟動slave
mysql> start slave;
mysql> SHOW SLAVE STATUS;
主要查看Slave_IO_Running和Slave_SQL_Running 兩列是否都為YES。
⑨測試主從服務是否同步
在主服務器中執行:
mysql> use test;
mysql> create table test(id int,name char(10));
mysql> insert into test values(1,'zaq');
mysql> insert into test values(1,'xsw');
mysql> select * from test;
此時查看從服務器:
到此主從復制就配置完成!
主庫中已有數據的解決方案:
- 方案一:選擇忽略主庫之前的數據,不做處理。這種方案只適用于不重要的可有可無的數據,并且業務上能夠容忍主從庫數據不一致的場景。
- 方案二:對主庫的數據進行備份,然后將主數據庫中導出的數據導入到從數據庫,然后再開啟主從復制,以此來保證主從數據庫數據一致。
這里小編介紹如何使用方案二進行數據同步。
① 備份數據
假設這里我們有一個庫:weibo并且數據庫中有相應的數據:
#鎖定主表
mysql> flush tables with read lock; #保證表只能做讀操作
#查看此時主數據庫狀態,并記錄bin-file和pos
mysql>show master status;
#在/etc/my.cnf中加入:
[mysqldump]
user = root
password = rootpassword
#重啟服務:
[root@zzy ~]# systemctl restart mysqld
#備份數據庫
mysqldump weibo > weibo_back.sql
然后將備份數據文件傳入從機器中,
在mysql中執行:source /path/ weibo_back.sql
此時主從數據庫的數據已經同步!
② 修改配置
這里主從服務器的配置同上一節說道的相同。
③ 啟動slave
mysql>stop slave;
mysql>reset slave; change master to
mysql>master_host='192.168.130.134',
>master_user='user2',
>master_password='Zy.123456',
>master_log_file='mysql-bin.000004',
>master_log_pos=154;
mysql>start slave;
mysql>SHOW SLAVE STATUS;
注意:這里的master_log_file和master_log_pos一定要和從主數據庫中通過“show master status”命令查到的相同。
④ 解鎖主數據庫
mysql>unlock tables;
然后我們就可以測試,在主數據庫中插入一條記錄,看看從數據庫是否有數據同步。
mycati一個開源的分布式數據庫系統,但是因為數據庫一般都有自己的數據庫引擎,而mycat沒有屬于自己獨有的數據庫引擎,所以嚴格意義上來講并不能算是一個完整的數據庫系統,只能是一個在應用和數據庫之間的服務中間件。
在mycat中間件出現之間,MySQL主從復制集群,如果要實現讀寫分離,一般是在程序段實現,這樣就帶來了一個問題,即數據段和程序的耦合度太高,如果數據庫的地址發生了改變,那么我的程序也要進行相應的修改,如果數據庫不小心掛掉了,則同時也意味著程序的不可用,而對于很多應用來說,并不能接受;引入Mycat中間件能很好地對程序和數據庫進行解耦,這樣,程序只需關注數據庫中間件的地址,而無需知曉底層數據庫是如何提供服務的,大量的通用數據聚合、事務、數據源切換等工作都由中間件來處理;Mycat中間件的原理是對數據進行分片處理,從原有的一個庫,被切分為多個分片數據庫,所有的分片數據庫集群構成完成的數據庫存儲,有點類似磁盤陣列中的RAID0。
通過使用mycat可以很輕松的實現數據庫的讀寫分離,并且由于其特點,不僅實現負載均衡,而且提高了集群的安全性。
注意,這里mycat只是做了負載均衡,主從復制并沒有做,所以,如果想讓MySQL集群可以讀寫分離,就需要使用mycat并沿用原有的主從復制的配置。
這里小編遇到的一個坑就是,最好使用mycat1.5即以上的版本,不然對一些鏈接工具會報錯:出現no mycat database selected問題!
這里小編使用的是1.6Linux版本。
首先下載相應的版本:http://dl.mycat.io/1.6-RELEASE/
① 保證MySQL的機器環境中有JDK1.8
需要配置JAVA_HOME!
這里注意,經驗推薦配置在相應用戶的~/.bashrc下,不要都配置在/etc/profile中。
② 配置mycat
這里需要配置4個文件:server.xml 、schema.xml、 rule.xml 、log4j2.xml
這里小編就簡單介紹下:
server.xml:配置用戶
schema.xml:配置關聯的表和庫,以及連接MySQL的host和密碼
rule.xml:配置相應的分片規則
log4j2.xml:配置日志級別。
#server.xml加入:
<user name="mycat">
<property name="password">123456</property>
<property name="schemas">mycat</property>
</user>
<user name="mycat_read">
<property name="password">123456</property>
<property name="schemas">mycat</property>
<property name="readOnly">true</property>
</user>
#schema.xml修改為:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="mycat" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1" />
<dataNode name="dn1" dataHost="localhost1" database="weibo" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql"
dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="192.168.130.134:3306" user="root" password="123456">
</writeHost>
<writeHost host="hostM2" url="192.168.130.133:3306" user="root" password="123456"/>
</dataHost>
</mycat:schema>
#rule.xml基本不變
# log4j2.xml將日志修改為debug
<Loggers>
<asyncRoot level="debug" includeLocation="true">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingFile"/>
</asyncRoot>
</Loggers>
③ 啟動mycat
進入mycat的bin下
#運行
$sh mycat start /sh startup_nowrap.sh
④ 測試連接
這里可以通過MySQL進行連接:
[root@zzy bin]# mysql -umycat -P8066 -p123456 -h227.0.0.1
這里的user和password就是在server.xml中配置的。
也可以通過工具連接,但是需要注意,這里連接的數據庫一定要是mycat。
這個問題是因為:mycat啟動時需要的內存默認最大為4G,最小為1G,小編這里使用的虛擬機沒有這么大內存,所以需要修改$MYCAT_HOMT/conf/ wrapper.conf中:
把配置調整下就行。
這個問題就是需要在/etc/hosts中配置當前主機與IP的映射:
這里我們配置了mycat和主從復制,這里我們只需要連接mycat的8066端口,通過mycat用戶就可以對數據庫進行CRUD,操作。這里我們連接mycat:
在weibo庫下的t_message表中插入一條記錄:
然后分別查看master數據庫和slave數據庫:
到此,MySQL的負載均衡高可用版的讀寫分離就完成了!
以上兩張測試表的語句:
DROP TABLE IF EXISTS `t_message`;
CREATE TABLE `t_message` (
`messages_id` varchar(64) NOT NULL COMMENT '微博ID',
`user_id` varchar(64) NOT NULL COMMENT '發表用戶',
`messages_info` varchar(255) DEFAULT NULL COMMENT '微博內容',
`messages_time` datetime DEFAULT NULL COMMENT '發布時間',
`messages_commentnum` int(12) DEFAULT NULL COMMENT '評論次數',
`message_deleteflag` tinyint(1) NOT NULL COMMENT '刪除標記 1:已刪除 0:未刪除',
`message_viewnum` int(12) DEFAULT NULL COMMENT '被瀏覽量',
PRIMARY KEY (`messages_id`),
KEY `user_id` (`user_id`),
CONSTRAINT `t_message_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `t_users` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LOCK TABLES `t_message` WRITE;
;
INSERT INTO `t_message` VALUES ('0001','1001','isfnesnfw','2019-09-01 00:00:00',2,1,2),('0002','1002','isfnesnfw','2019-08-21 00:00:00',2,1,2),('0003','1002','isfnesnfw','2019-08-21 00:00:00',2,1,2);
UNLOCK TABLES;
DROP TABLE IF EXISTS `t_users`;
CREATE TABLE `t_users` (
`user_id` varchar(64) NOT NULL COMMENT '注冊用戶ID',
`user_email` varchar(64) NOT NULL COMMENT '注冊用戶郵箱',
`user_password` varchar(64) NOT NULL COMMENT '注冊用戶密碼',
`user_nikename` varchar(64) NOT NULL COMMENT '注冊用戶昵稱',
`user_creatime` datetime NOT NULL COMMENT '注冊時間',
`user_status` tinyint(1) NOT NULL COMMENT '驗證狀態 1:已驗證 0:未驗證',
`user_deleteflag` tinyint(1) NOT NULL COMMENT '刪除標記 1:已刪除 0:未刪除',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LOCK TABLES `t_users` WRITE;
INSERT INTO `t_users` VALUES ('1001','www.415511@qq.com','123456','zsa','2019-08-09 00:00:00',1,2),('1002','www.2345@qq.com','4578964','zsa','2019-07-09 00:00:00',2,3),('1003','www.41we11@qq.com','123456','zsa','2019-08-09 00:00:00',1,2),('1004','www.41523511@qq.com','1456','zasdsa','2018-08-09 00:00:00',1,2);
UNLOCK TABLES;
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。