一:什么是資料庫
資料庫是一個長期存盤在計算機內,有組織的,有共享的,統一化管理資料集合,
它簡便而言之就是一個資料存盤倉庫,為了方便資料存盤和管理,它將資料按照特定的規律存盤在磁盤上,通過資料庫管理系統,可以有效的組織和管理存盤在資料中的資料,
二:資料庫的現狀
資料庫型別:
1.層次資料庫 2.網格狀資料庫 3.關系型資料庫 4.NOSQL(非關系型資料庫)
三:資料庫系統
(1)資料庫:用于存盤資料的地方,
(2)資料庫管理系統:為了提高資料庫系統的處理能力所使用的管理資料庫的軟體
(3)資料庫應用程式:資料庫管理系統的軟體補充,
資料庫(database)提供了一個存盤空間用來存盤資料,可以把資料庫看成是以存放資料的容器,一個資料庫肯定能包含許多檔案,一個資料庫系統中包含多個資料庫
資料庫管理系統(database management system.dbms):是用戶創建,管理和維護資料庫時使用的軟體,位于用戶與作業系統之間,對資料庫進行統一的管理,dbms能定義資料存盤結構,提供資料的操作機制,維護資料庫的安全性,完整性和可靠性,
資料庫應用程式:(database application):雖然已經有資料庫管理系統,但是在很多情況下,dbms無法滿足對資料管理要求,資料庫的應用程式算是dbms的一個軟體補充,它能夠滿足對資料管理的更高要求,還可以使資料庫管理程序更加直觀,資料庫應用呈現負責與dbms進行通信,訪問和管理dbms中存盤和資料,用戶插入,修改,洗掉DB中的資料
mysql
1.什么是mysql
mysql是一個開源的資料管理系統(DBMS),他是由mysql AB公司開發的,
mysql是一個跨平臺開源關系資料庫管理系統,廣泛的應用在小型的互聯網公司的生產和開發環境中,
mysql是一個小型的關系型資料庫,與其他的大型資料庫管理系統如:oracle,db2,sql server相比,mysql的規模更小,功能有限,但是體積小,速度快,成本低,并且它的功能對一些小企業或者復雜一點應用來說已經足夠用了,所以mysql就為目前最受歡迎的開源資料庫,
2.mysql的版本
針對不同的用戶mysql分為Community server(社區版),enterprise server(企業版)
mysql的命名機制由3個數字和1個后綴組成,例如:mysql-5.5.13.
第一個5.是主版本號,描述了檔案格式,所有版本5的發型版都有相同的檔案格式,
第二個5.是發型級別,主版本號和發型別組合在一起便構成了發行序列號
第三個數字13.是發型序列的版本號
3.mysql的優勢:
(1)速度:運行速度快;
(2)價格:開源免費
(3)容易使用:它的配置和管理非常簡單,易于學習,
(4)可移植性強:能夠在眾多不同的系統平臺運行,比如:widows,linux,ios等等,
(5)豐富的介面:提供了c c++,Java,Perl,PHP
(6)支持查詢語言:MySQL可以使用sql語法支持ODBC(開放式資料庫鏈接)的應用程式
(7)安全性和連續性:十分靈活和安全的權限和密碼系統,允許基于主機的驗證,連接到服務器時,所有密碼傳輸均采用加密的方式,從而保證安全性,并且由于mysql是網路化的,可以在因特網上的任何地方訪問,提高了資料的共享效率,
4.mysql的服務架構:
client/server–C/S架構(客戶端/服務器)
5.mysql的表:database資料庫(最大的資料存盤單位)
table表(資料存盤的基本單在關系型資料庫中,資料庫的表是一系列二維陣列的集合,用來存盤資料和操作資料的邏輯的邏輯結構,
它是由縱向的列和橫向的行組成,行被稱為記錄,是組織資料的單位;列被稱為欄位,每一串列示記錄的一個屬性,都有相應的描述資訊,如資料型別,資料寬度等,
6.資料型別:
資料型別決定了資料子計算機中的存盤格式,代表不同資訊型別,通常的資料型別有:整數資料型別
浮點數資料型別,二進制資料型別,字串資料型別,日期/時間資料型別等,
7.sql語言:
對資料庫進行查詢和修改操作的語言,SQL的含義(structured query language)結構化查詢語言
他有3個主要的標準:ANSI(美國國家標準機構)SQL,ANSI對SQL在1992進行了修改,SQL-92或者SQL2,近年又進行了修改,SQL-99,
SQL語言的4個部分:
1.資料定義語言data definition language(DDL):drop(洗掉),create(創建),alter()等陳述句,
2.資料的操作語言data manipulation language(DML):insert,update(修改)delete(洗掉)陳述句,
3.資料查詢語言data query language(DQL):select(查找)陳述句,
4.資料控制語言data control language(DCL):grant,revoke,commit,rollba等陳述句
8.MySQL的命令列工具:
9.陳述句:
1.show databases:用于查看當前mysql服務器中包含的庫,
2.show tables:用于查看當前所在的庫中包含的表,需要先使用use陳述句切換到所使用的庫use mysql
mysql資料庫檔案存放在/usr/local/mysql/data 目錄下,每個資料庫對應一個子目錄,用于存盤資料表檔案,每個資料表對應為三個檔案,擴展名分 別為".frm",".myd",".myi"
3.create database陳述句:用于創建一個新的庫,需要指定資料庫名稱作為引數(auth資料庫名稱) 例:(create database auth)
4.create table陳述句:用于在當前庫中創建新的表,需要指定資料表名稱作為引數(zhy表名稱)例:(create database zhy)
5.drop table陳述句:用于洗掉資料庫中的表,需要指定’庫名 表名’作為引數,若只指定表明引數,則需要通過執行use陳述句切換到目標庫,執行一下操作 可以洗掉users表 例:(drop table auth.users)
6.drop database陳述句:用于洗掉指定的庫,需要指定庫名作為引數 例:(drop database auth)
7.Insert into陳述句:用于向表中插入新的資料記錄 例:(insert into 表名)執行以下操作將會向auth庫中的users表插入一條記錄
8.Select陳述句:用于從指定的表中查找符合條件的資料記錄
9.Describe:用于顯示表結構,則需先通過use陳述句切換到目標庫(use mysql切換到mysql資料庫)查看mysql庫中的user表結構(describe mysql.user) 或者(describe user)這倆陳述句相同
10.Update陳述句:用于修改,更新表中的資料記錄,
11.Delete:用于洗掉表中指定的資料記錄,例如:Delete * from 表名 where 條件運算式
12.insert into陳述句:用于向表中插入資料記錄,例:insert into 表名(欄位1,欄位2,…) values(欄位1的值,欄位2的值,…)
注意!
【在執行Update Delete陳述句時,通常都帶where條件,不帶條件的Update陳述句和Delete陳述句會修改或洗掉所有記錄,是非常危險的行為】
12.Crant陳述句:專門設定資料庫用戶的訪問權限,當指定的用戶不存在時,Crant陳述句將會創建新的用戶,否則Crant陳述句用戶資訊,
13.show global varlables like’%datadir%’;查看mysql資料存盤路徑
14.執行MySQL操作陳述句
驗證成功以后將會進入提示符“mysql>”的資料操作環境,用戶可以輸入各種操作陳述句對資料庫進行管理,每條MySQL操作陳述句以分號“;”表示結束,輸入時不區分大小寫,
第二章 資料庫的基本操作
一.mysql的4個默認自帶的4個庫:
1.information_schema:保存了關于資料的資訊,例如:資料庫名,資料庫中的表名,
2.mysql:記錄資料庫的用戶,密碼,權限,關鍵字等,還有mysql自己需要使用的控制和管理資訊,
3.performance_schema:5.5版本之后新增的一個庫,用于收集服務器的性能引數,該庫中所有的表的一個引擎均為performance_schema,
4.tsst:測驗庫,所有的用戶在該資料庫中都擁有root權限(一般不會存盤有用的資料),
二.1.創建資料庫:create database databasename; databasename是指資料庫名稱
2.移動到指定的資料庫里:use databasename;
3.洗掉資料庫:drop database databasename;
其它用法
1、使用SHOW陳述句找出在服務器上當前存在什么資料庫:
mysql> SHOW DATABASES;
2、創建一個資料庫MYSQLDATA
mysql> CREATE DATABASE MYSQLDATA;
3、選擇你所創建的資料庫
mysql> USE MYSQLDATA; (按回車鍵出現Database changed 時說明操作成功!)
4、查看現在的資料庫中存在什么表
mysql> SHOW TABLES;
5、創建一個資料庫表
mysql> CREATE TABLE MYTABLE (name VARCHAR(20), sex CHAR(1));
6、顯示表的結構:
mysql> DESCRIBE MYTABLE;
7、往表中加入記錄
mysql> insert into MYTABLE values (”hyq”,”M”);
8、用文本方式將資料裝入資料庫表中(例如D:/mysql.txt)
mysql> LOAD DATA LOCAL INFILE “D:/mysql.txt” INTO TABLE MYTABLE;
9、匯入.sql檔案命令(例如D:/mysql.sql)
mysql>use database;
mysql>source d:/mysql.sql;
三,資料庫的存盤引擎:
1.什么是存盤引擎:資料庫的存盤引擎是資料庫的底層軟體組件,資料庫管理系統(Dbms)就是依賴存盤引擎來對資料表進行創建,查詢,更新和洗掉操作的,不同的存盤引擎提供了不同的存盤機制,索引技巧和鎖定水平等功能,還可以獲得某些特定的功能,現在不同的資料庫的管理系統都支持多種不同的存盤引擎,mysql的核心就是存盤引擎,
2.MySQL的存盤引擎,包括處理事務安全表的引擎和處理非事物安全表的引擎,在MySQL中不需要所有的表都使用同一種引擎,針對具體的需求每一張表都可以選擇不同的存盤引擎,
MySQL5.5支持的存盤引擎有:InnoDB,MyiSAM,Memory,CVS等,
查看mysql中所有的存盤引擎的命令:show engines\g
1.myisam存盤引擎的特點:
(1)myisam引擎讀取速度快,占用資源少,不支持事務,不支持外鍵約束,但支持全文索引
(2)讀寫相互阻塞,也就是說讀資料的時候就不能寫資料,寫資料的時候就不能讀資料;
(3)myisam引擎只能快取索引,而不能快取資料;
(4)mysql5.5之前的默認引擎,
使用場景:
(1)適用于讀資料比較多的業務,不適用于讀寫頻繁的業務;
(2)并發相對較低的業務(純讀或者純寫的高并發也可以),資料修改相對較少的業務;
(3)硬體資源比較差的機器可以考慮多使用myisam引擎,
2.InnoDB存盤引擎的特點:
(1)事物類資料表的首選引擎,支持事物安全表,支持行級別鎖定和外鍵,mysql5.5之后的默認引擎;
(2)具有提交,回滾和崩潰恢復能力的事物安全存盤引擎,能處理巨大的資料量,性能及效率高,完全支持外鍵完整約束條件;
(3)具有非常高的效的快取特性,能快取索引也能快取資料,對硬體要求高,
(4)使用InnoDB時,將在mysql資料目錄創建一個名為ibdata的10M帶大小的自動擴展檔案,以及兩個名為ib_logfile0和ib_logfile1的5M帶大小的日志檔案,
使用場景:
(1)需要事物支持的業務,高并發的業務;
(2)資料更新較為頻繁的場景,比如:BBS(美國論壇網站),SNS,微博等;
(3)資料一致性要求較高的業務,比如充值轉賬,銀行卡轉賬等,k
memory存盤引擎的特點:
(1)memory存盤引擎將表中的資料存盤記憶體中,為查詢和參考其他表資料提供快速訪問;
(2)memory存盤引擎執行HASH和BETREE索引,不支持BLOB和TEXT列,支持AUTO_INCREMENT列,和對可包括NULL值的列的索引;
(3)當不在需要memory表的內容時,要釋放memory表占用的記憶體,可以執行delete from或者truncate table,或者洗掉整個表,
CSV:將資料保存為CSV格式檔案,可以匯入到其它資料庫中;
ARCHIVE:歸檔,將資料zlib進行壓縮,被當做倉庫使用,一般對他只進行insert和select操作,他適合存盤日志,
mrg_myisam:相當于將多個myisam的合并版,將多個myisam表合并為一個,
MySQL 修改root密碼的四種方法
1 用set password命令
首先登陸MySQL
格式 MySQL > set password for 用戶名@localhost=password(‘新密碼’)
例子 MySQL > set password for root@localhost=password(‘123’);
2 在命令列用 mysqladmin
格式 mysqladmin -u 用戶名 -p 舊密碼 password 新密碼
列子mysqladmin -uroot -p123456 password 123
方法3 用update直接編輯user表
首先登陸MySQL
MySQL>use MySQL;
MySQL> update user set password=password(‘123’)where user=‘root’ and
host=‘localhost’;
mysql>flush privileges;
方法4 :忘記root密碼的時候
vim /etc/my.cnf
在[mysqld]下面添加一行skip-grant-tables
然后重啟,在登陸MySQL(此時密碼為空)使用命令 update mysql.user set password=password(‘密碼’)where user=root host=‘localhost’;
回到組態檔,洗掉剛剛添加的那行,在重啟服務就可以用新密碼登陸了,
第三章:資料表的基本操作
我們要進行表的操作,我們首選需要進入一個庫里面,
1.創建表的命令格式:
create table <表名> (
–>欄位1 資料型別 [完整性約束條件]
–>欄位2 資料型別 [完整性約束條件]
…
);
2.洗掉表:drop table表名;
3.如何在表中插入資料:insert into表名 [(插入資料的欄位)] values(欄位一的值,欄位二的值,欄位n的值);
4.擦汗尋表資料:select */欄位 from 表明;
完整性約束條件:
1.什么是完整性約束條件:
完整性約束條件時用來對欄位進行限制,要求用戶只能向該欄位中寫入符合條件的資料,如果不滿足條件資料將會不執行該操作,
2.常用的完整性約束條件:
primary key 主鍵 標識該表的主鍵,可以唯一的標識資料,(特點: 非空,唯一)
FOREIGN KEY 外鍵 標識該欄位為該表的外鍵,是與之聯系的某表的主鍵;
NOT NULL 非空 標識該欄位的值不能為空;
UNIQUE 唯一 標識該欄位的值是唯一的;
AUTO_INCREMENT 標識該欄位的值自動增加,一般該欄位的資料型別是int;
DEFAULT 默認值 為該欄位設定一個默認值,在不插入值的時候使用默認值,
給欄位添加主鍵的方法:
1.單欄位主鍵:
語法:
創建表的時候添加主鍵
1.欄位名 資料型別 PRIMARY KEY,
2.在定義完所有的欄位之后添加主鍵
PRIMARY KEY(欄位名);
多欄位的聯合主鍵:
RIMARY KEY(欄位1,欄位2,欄位3…)
使用修改表的命令也可以添加主鍵:
LTER TABLE 資料表名 ADD PRIMARY KEY(欄位名)
使用外鍵:外鍵用來在兩個表資料之間建立關系,它可以是一系列或多系列
創建外鍵的語法:
在創建表的時候添加在所有欄位后面
[CONSTRAINT<外鍵名>]FOREIGN KEY(欄位名1,欄位2…)REFERENCES 父表(主鍵1,主鍵2…)
用修改表的語法來添加一個外鍵:
ALTER TABLE 子表名 ADD CONSTRAINT 外鍵名 FOREIGN KEY(子表外鍵列)REFERENCES父表名(父表主鍵列);
子表外鍵列的資料型別必須和父表的主鍵列的資料型別一致,否則無法創建
洗掉外鍵:
ALTER TABLE 表名 DROP FOREIGN KEY(外鍵)
NO NULL 創建表的時候:
欄位 資料型別 NOT NULL
UNIQUE
欄位 資料型別 UNIQUE
[CONSTRAINT(約束名稱)]UNIQUE(欄位名)
DEFAULT 默認值
欄位名 資料型別 DEFAULT(默認值)
AUTO_INCREMENT 自增
欄位名 資料型別 AUTO_INCREMENT
所有的約束條件都是可選的,每一個欄位可以設定多個約束條件,
查看資料表結構語法;desc+表名;
2.show create table 表明;
二,修改資料表:
1.給表改名:
alter table<舊表名>rename[to] <新表名>;
使用這條命令還可以將資料表移動到其他庫中
alter table<舊表名> rename to <庫名>.<表名>
2.修改欄位的資料型別
alter table<表名>modify<欄位名><新的資料型別>;
3.修改欄位名:
alter table<表名>change<舊的欄位> <新欄位> <新資料型別>;
4.添加欄位:
alter table<表名> add <新欄位> <資料型別> [完整性約束條件] [first/after已經存在的欄位](first移動到第一)(after移動到其他欄位后面)
5.修改欄位的所在位置:
alter table <表名> modify <新欄位名> <資料型別> [完整性約束條件] after <舊欄位>;
6,洗掉欄位的語法:
alter table<表名>drop <欄位名稱>
7.更改表的引擎:
alter table <表名> engine=引擎名稱;
8.洗掉主鍵:
alter table <表名> drop promary key;
9.洗掉外鍵:
alter table <表名> drop foreign key <外鍵名>;
10.洗掉外鍵:
ALTER TABLE 表名 DROP FOREIGN KEY(外鍵)
如果表b的外鍵關聯表a的主鍵
,那么我們無法洗掉表a,必須洗掉表b的外鍵或者是直接洗掉表b,才可以洗掉表a;
NOT NULL 非空
UNIQUE唯一
PRIMARY KEY主鍵
FOREIGN KEY外鍵
t_name老師名字
t_birthday性別
t_prof出生年月日
t_depart職稱
t_id編號
資料型別;
(1)資料表由多列欄位構成,每個欄位指定不同的資料型別,指定資料型別后,也就決定向欄位插入資料的內容;
(2)不同的資料型別也決定了MySQL在存盤他們的時候使用方式,以及在使用他們的時候選擇什么運算子號進行運算;
(3)資料型別分為:數值類資料型別,日期/時間資料型別,字串資料型別,
數值資料型別: (1)整數 (2)浮點數 (3)定點數;
日期/時間資料型別:DATE ,TIME,DATETIME,TIMESTAMP等等;
字串資料型別:文本字串,二進制字串,
一,數值類資料型別:
浮點數和定點數:
(1)他們都是用來表示小數的,浮點數有兩種型別:單精度浮點數(FLOAT)和雙精度浮點數(DOUBLE),定點數只有DECIMAL
(2)浮點數和定點數都可以用(M,D)來表示,其中M是精度,表示總共的位數(不算點號),D是標數,表示小數的位數;
(3)DECIMAL 實際是以字串的形式存放的,在對精度要求比較高的時候(比如貨幣,科學資料等使用DECIMAL型別比較好;
(4)浮點數相對于定點數的優點是在長度一定的情況下,浮點數能夠表示更大的資料范圍,它的缺點是精度沒有定點數高,
型別名稱 日期格式 日期范圍 存盤需求
YEAR YYYY 1901 ~ 2155 1位元組
TIME HH:MM:SS -838:59:59 ~ 838:59:59 3位元組
DATE YYYY-MM-DD 1000-01-01 ~ 9999-12-31 3位元組
DATETIME YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 8位元組
TIMESTAMP YYYY-MM-DD HH:MM:SS 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC 4位元組
2、TIME
(1) TIME 型別的格式為 HH:MM:SS ,HH 表示小時,MM 表示分鐘,SS 表示秒
(2) 格式:以 ‘HHMMSS’ 格式表示的 TIME ,例如 ‘101112’ 被理解為 10:11:12 ,但如果插入不合法的時間,如 ‘109712’ ,則被存盤為 00:00:00
(3) 格式:以 ‘D HH:MM:SS’ 字串格式表示的 TIME ,其中 D 表示日,可以取 0 ~ 34 之間的值,在插入資料庫的時候 D 會被轉換成小時,如 ‘2 10:10’ 在資料庫中表示為 58:10:10 ,即 2x24+10 = 58
3、DATE
(1) DATE 型別的格式為 YYYY-MM-DD ,其中,YYYY 表示年,MM 表示月,DD 表示日
(2) 格式:‘YYYY-MM-DD’ 或 ‘YYYYMMDD’ ,取值范圍為 ‘1000-01-01’ ~ ‘9999-12-31’
(3) 格式:‘YY-MM-DD’ 或 ‘YYMMDD’ ,這里 YY 表示兩位的年值,范圍為 ‘00’ ~ ‘99’ ,其中,‘00’ ~ ‘69’ 被轉換為 2000 ~ 2069 ,‘70’ ~ ‘99’ 被轉換為 1970 ~ 1999
(4) 格式:YY-MM-DD 或 YYMMDD ,數字格式表示的日期,其中 YY 范圍為 00 ~ 99 ,其中,00 ~ 69 被轉換為 2000 ~ 2069 ,70 ~ 99 被轉換為 1970 ~ 1999
查詢:
查詢的基礎語法:
SELECT{*|欄位} [FROM表1,表2,… ] [WHERE條件判斷]
[GROUP BY 欄位] [having expr]
[order by 欄位] [limit…(偏移量,行數)] ORDER BY 欄位
我們知道從MySQL表中使用SQL SELECT 陳述句來讀取資料,
1.如需有條件的從表中選取資料,可以將WHERE子句添加到SELECT陳述句中,
2.查詢陳述句中你可以使用一個或多個表,表之間用逗號隔開,并使用WHERE陳述句來設定查詢條件;
3.你可以用WHERE陳述句來指定任何條件
4.你可以用AND或者OR指定多個條件;
5.WHRE子句也可以用在DELECT或者UPDATE命令里面,
WHERE中常用到的:
(1)=,<>, !=, <, >, <=, >=,
(2)BETWEEN AND 介于兩者之間用來限制一個范圍
(3)LIKE 通配符查詢(%匹配任意個數字符,_匹配任意單個字符)
(4)REGEXP正則運算式查詢(^表示以什么開頭,$表示以什么結尾,[…]表示匹配方括號內的任意字串 | 表示匹配管道符前后字串)
(5)IN判斷是否在IN串列之中;
(6)AND滿足AND前后所有條件,OR滿足OR前后任意添加;
(7)在WHERE子句中我們binary這個引數可以區分大小寫,默認不區分;
(8)ORDER BY 欄位 ASC:(升序排列)默認就是升序排列;
(9)ORDER BY 欄位 DESC(降序排列);
可以同時給多個欄位進行排序,排序依然依照第一個欄位進行排序,在第一個欄位排序過后的基礎上,在給其他進行排序,后面的排序不影響第一個欄位的順序;
分組查詢:GROUP BY
GROUP BY 是對select查詢出來結果按照某個欄位或者運算式進行分組,獲取一組組的集合,然后從每組中取出一個指定的欄位或者運算式的值,
having:用于where和group by 查詢出來的分組進行過濾,查出滿足條件的分組結果,他是一個過濾宣告,是在查詢回傳結果集以后對查詢結果進行過濾操作,
[GROUP BY 欄位] [HAVING 條件運算式]
分組經常和聚合函式一起使用,MAX(), MIN(), COUNT(), AVG(), SUM()
SUM() 求和 MAX() 求最大值 MIN() 求最小值 AVG() 求平均數
COUNT() 表示統計數量 (行數)可以用*表示所有記錄的行數,欄位來顯示特定欄位的行數;
GROUP_CONCAT(欄位)將分組過后的資料顯示完整,
LIMIT限制查詢結果數量:
LIMIT[位置偏移量], 行數 默認偏移量從0開始,行數限制了顯示結果輸出多少行;列:從3行到7行,就是2,5
列:select * from zhy LIMIT 2,5
連接查詢:UNION [all | distinct] 用來連接兩個查詢陳述句,將兩個查詢的結果集,合并為一個結果集;
結果集:不加引數all的時候默認去掉重復的結果,相同的值只顯示一次,加上引數all,顯示所有查詢內容,不會去掉重復的值,
聯合查詢:
主要進行多表查詢的時候使用,
INNER JOIN 內連接 連接兩個表,輸出符合條件的資料;
語法:表1 [INNER] JOIN 表2 ON 限定條件
如果連接的是同一個表,叫做自連接,
LEFT 表1 [OUTER] JOIN 表2 ON 限定條件 “左連接”它會顯示左表)表1)的全部內容,和右表(表2) 限定條件的內容;
RIGHT 表1 [OUTER] JOIN 表2 ON 限定條件 “右連接” 它顯示右表
的全部內容和左表的限定條件的內容;
子查詢:指一個查詢陳述句嵌套在另一個查詢陳述句的內部,,子查詢在版本4.1版本開始上線,
子查詢在執行查詢的程序中會出現一個零時表,查詢完成后會自動消失,
ALL 需要符合所有條件才能輸出;
ANY 只需要符合其中一個條件就可以輸出
EXITS 會將子查詢中的所有資料進行判斷是否存在,如果存在,外層查詢陳述句進行查詢,如果不存在,則停止查詢,回傳NULL,
NOT EXITS 對子查詢的資料進行判斷是否不存在,如果不存在,執行外部查詢,存在則回傳NULL
索引:
索參考于快速找出在某個列中有一特定值的行,不使用索引,MySQL必須從第一條記錄開始讀完整個表,指導找出相關的行,表越大,查詢資料所花費的時間就越多,如果表中查詢的列有一個索引,MySQL能夠快速到達一個位置去搜索資料檔案,而不必查看所有資料,那么將會節省很大一部分時間,
其中MySQL中的索引的存盤型別有兩種:BTREE,HASH,
在MySQL中最常用的存盤引擎就是InnoDB和MyISAM這兩個存盤引擎主要支出的索引的存盤方就是BTREE,MEMORY引擎支持
HASH
HASH 主要以KEY-value的方式進行存盤資料,多個key可以指向一個value,但是同一個key不可以指向多個值,
索引的分類:
1.唯一索引和普通索引
2.單列索引和組合索引
3.全文索引fulltext
4.空間索引spatial
單列索引指給單行的資料添加索引,組合索引指,將多個欄位添加為一個索引;
唯一索參考來限制我們的資料的唯一性UNIQUE INDEXT,可以包含NULL,PRIMARY KEY
是一個特殊的唯一索引,唯一,非空;
全文索引:可以用于全文搜索,只有MyISAM存盤引擎支持,并且只能為CHAR,VARCHAR,TEXT列添加;
空間索引:只有MYISAM引擎支持,添加空間索引的欄位必須非空;
空間型別支持的資料型別:GEOMETRY,POINT,LINESTRING,POLYGON
組合索引默認的索引名是我們定義的最左側的第一個欄位的名稱,組合索引遵循最左側原則,就是說
索引的添加方式:
1.在創建表時添加:
CREATE TABLE 表名 (欄位名 資料型別) (UNIQUE 唯一索引 | fulltext 全文索引 | spatial 空間索引)[INDEX|KEY][索引名(len)]
2.修改表時添加索引:
ALTER TABLE 表名 ADD UNIQUE |FULLTEXT|SPATLAL [INDEX|KEY] [索引名] (索引欄位)
3.CREATE UNIQUE | FULLTEXT | SPATIAL [INDEX|KEY] [索引名]
ON 表名 [索引欄位] ;
查看創建的索引:
show create table 表名\G
洗掉索引:
ALTER TABLE DROP INDEX 索引名;
DROP INDEX 索引名 ON 表名;
創建索引注意:
(1)創建索引并非越多越好;
(2)資料量小的表沒有必要創建索引
(3)避免對經常更新的資料創建索引
(4)在條件運算式中經常使用的欄位可以創建索引
(5)當唯一性是某種資料本身的特征時,我們創建唯一索引
(6)在頻繁進行排序或者分組的列上創建索引,如果排序的列有多個,可以創建全文索引
索引作用:
1.加快查詢速度
2.創建唯一索引來保證表中資料的唯一性
3.實作資料的完整性,加速表和表之間的連接
4.介紹分組和排序時間
EXPLAIN + 查詢陳述句 用來測驗我們的索引有沒有生效或者有沒有在作業;
EXPLAIN列的解釋
table 顯示這一行的資料是關于哪張表的
type 這是重要的列,顯示連接使用了何種型別,從最好到最差的連接型別為const、eq_reg、ref、range、indexhe和ALL
possible_keys 顯示可能應用在這張表中的索引,如果為空,沒有可能的索引,可以為相關的域從WHERE陳述句中選擇一個合適的陳述句
key 實際使用的索引,如果為NULL,則沒有使用索引,
key_len 使用的索引的長度,在不損失精確性的情況下,長度越短越好
ref 顯示索引的哪一列被使用了,如果可能的話,是一個常數
rows MYSQL認為必須檢查的用來回傳請求資料的行數
Extra 關于MYSQL如何決議查詢的額外資訊,
視圖優點
? 簡單
– 使用視圖的用戶完全不需要關心視圖中的資料是通過什么查詢得到的,
– 視圖中的資料對用戶來說已經是過濾好的符合條件的結果集,
? 安全
– 用戶只能看到視圖中的資料,
? 資料獨立
– 一旦視圖的結構確定了,可以屏蔽表結構變化對用戶的影響,
視圖:視圖是一張虛擬表;
他和我們真實的表的區別:視圖它里面的資料是通過查詢陳述句從一張或者多張真實的表里面獲取到的;
我們可以通過insert,update, delete來操作視圖(和操作表是一樣的),當通過視圖修改資料時,對應的原表資料也會被修改,同樣,我們修改表資料時,也會自動反映到視圖中,
視圖他會真實的保存到我們的磁盤里,隨時都能夠查詢里面的資料;
視圖對應的真實表,我們叫做基表;
創建視圖:
CREATE [algorithm=undefind|merge|temptable] VIEW 視圖名 [視圖的欄位名] AS SELEST [*|欄位]
FROM 表名|視圖名 WHERE…
例:create view zhy as select * from;
algorithm 用來定義視圖的演算法;
undefined 未定義 默認使用merge
merge 替換;
temptable 零時表;
with check option 默認cascaded
with cascaded check option 更新視圖的時候,滿足視圖以及相關的基表或視圖的限制條件;
with local check option 更新視圖的時候,只需要滿足本身的條件即可;
查看視圖結構:DESC 視圖名稱; SHOW FILEDS FROM 視圖名稱;
查看視圖的創建詳情:SHOW CREATE VIEW 視圖名稱;
查看視圖的基本資訊:
SHOW TABLE STATUS LIKE ‘視圖名’\G
在MySQL中,information_schema資料庫下的views表中存盤了所有視圖的定義,通過對views表的查詢,可以查看資料庫中所有視圖的詳細資訊;
修改視圖:
CREATE OR REPLACE VIEW 視圖名 AS SELECT… ‘用來修改視圖’
ALTER VIEW 視圖名 AS SELECT…
更新視圖內容:update
UPDATE 視圖名 set 欄位名=‘值’ WHERE …
試圖存在以下情況時,更新操作無法執行:
1.視圖中不包含基表中被定義為非空的列;
2.在定義視圖的select陳述句的欄位串列中使用了數學運算式或者聚合函式,不接受更新操作;
3.select中,使用了union、group by、having無法接受更新,
洗掉視圖:
DROP VIEW [IF EXISTS] 視圖名1,視圖名2,…
加上IF EXISTS 可以使假如沒有要洗掉的這個視圖存在,也不會報錯,但是會回傳1條warning;
視圖和真實表的區別;
(1)視圖是已經編譯好的SQL陳述句,是基于SQL陳述句的結果的可視化表,而表不是;
(2)視圖沒有實際的記錄,而表有;
(3)表是內容,試圖可以看成是視窗;
(4)表和視圖雖然都占用物理空間,但是視圖只是邏輯概念存在,而表可以及時對資料進行修改,但是視圖只能用創建語言來修改;
(5)視圖是查看資料表的一種方法,可以查詢資料表中的某些欄位構成的資料,只是一些SQL陳述句的集合,從安全角度來說,視圖可以防止用戶接觸資料表,因而不知道表結構;
(6)表屬于全域模式的表,是實表,而視圖屬于區域模式的表,是虛表;
(7)視圖的建立和洗掉只影響視圖本身,而不影響對應的基本表,
視圖和基本表的聯系:
視圖是在基本表之上建立的表,他的結構和內容都來自基本表,它依賴基本表存在而存在,
一個視圖可以對應一個基本表,也可以對應多個基本表,視圖是基本表的抽象和邏輯意義上建立的關系,
事務:
什么叫事務:多條SQL陳述句,要么全部成功,要么全部失敗,MySQL的事務是在存盤引擎層實作
事務主要用于處理操作量大,復雜度高的資料,比如說,在人員管理系統中,你要洗掉一個人員,你既要洗掉人員的基本資料,也要洗掉該人員的相關資訊,如信箱,文章等等,這樣,這些資料庫操作陳述句就構成一個事務!
事務的四大特性:ACID
A.原子性(atomicity):一個事務必須視為完整不可分割的單位,其中的操作要么都做,要么都不做;如果事務中的一個SQL陳述句執行失敗,則已執行的陳述句必須回滾,資料庫退回到事務開始前的狀態,
C:一致性(consistency):是指事物執行結束后,資料庫的完整性約束沒有被破壞,事物執行的前后都是合法的資料狀態,資料庫的完整性約束包括不限于:物體完整性(如欄位的型別,大小,長度要符合要求),外鍵約束,用戶自定義完整性(如轉賬前后,兩個賬戶余額的和應該不變),事物支持的操作主要有:INSERT,UPDATE,DELETE等;
D:持久性(durability):一旦事物提交,所有修改的資料將永久保存到資料庫中,即使系統崩潰也不會改變或丟失;
I:隔離性:與原子性,持久性側重于研究事物本身不同,隔離性研究的是不同事物之間的相互影響,隔離性是指,事物內部的操作與其他事物是隔離的,并發執行的各個事物之間不能相互干擾,嚴格的隔離性,對應了事物隔離級別中的serializable(可串行化),但實際應用中出于性能方面的考慮很少會使用可串行化,
事物操作命令:
開啟事務:begin,start transaction
事務提交:commit
事務回滾:rollback
我們用begin或者start transaction 開啟的事務叫做顯式事務,
查看自動提交模式是否開啟:SHOW VARIABLES LIKE’AUTOCOMMIT‘
關閉自動提交模式:SET AUTOCOMMIT=0
開啟自動提交模式:SET AUTOCOMMIT=1
事務的4種隔離級別:
1.read uncommitted(未提交讀);
2.read committed(已提交讀);
3.repreatable read(可重復讀);
4.serealizable(可串行化);
這4種隔離級別是由低到高的,隔離級別越低,并發能力越強,性能越好,但是安全性越差;
隔離級別也高,并發越差,但是安全性好;
1.未提交讀:事務中修改沒有提交對其他事務也是可見的,俗稱臟讀;
2.以提交讀:許多資料庫默認為此級別呢(MySQL不是),已提交讀一個事務只有在提交了之后,另一個事務才對他可見;
以提交讀可以解決臟讀的問題,但是會產生不可重復讀的問題;
3.可重復讀:能夠解決臟讀和不可重復讀的問題;
4.可串行讀:是最高隔離級別,強制事務串行執行,執行串行也就解決問題了,這個級別只有在對資料一致要求非常嚴格并且沒有并發的情況下使用,
當我們在事務a里面查詢id<10的時候,我們在事務b里執行insert陳述句被阻塞執行了,原因是事務a執行了查詢stud同時滿足id<10,以被鎖定,如果查詢表stud同時滿足id<3,則新增的陳述句執行成功
觸發器(trigger):是一個特殊的存盤程序,都是嵌入到MySQL的一段程式,觸發器是由事件來觸發某個操作,由于MySQL只支持行級別的觸發器功能,所以這些事件只能是SQL語言DML陳述句,也就是inster、delete、update這三種,如果定義了觸發程式,當資料庫執行這些陳述句的時候就會激發觸發器執行相應的操作,觸發器可以查詢其他的表,而且可以包含復雜的SQL陳述句,不需要手動啟動,只要一個預定義事件發生時,就會被MySQL自動呼叫,
簡單來理解:觸發器就是你執行一條DML SQL陳述句,這條SQL執行會自動觸發執行其他的SQL陳述句,
sql ->觸發 ->sqln, 一條觸發一個或多個sql,
觸發器的4個要素:
(1)監視點(table)
(2)監視事件(insert、update、delete)
(3)觸發時機(before/after)
(4)觸發事件(sql陳述句)
NEW和OLD詳解:
MySQL中定義了new和old,用來表示觸發器的所在表中,觸發了觸發器的那一行資料,來參考觸發器中發生變化的記錄內容,具體的:
(1)在insert型觸發器中,NEW用來表示將要(before)或已經(after)插入或修改后的新資料,old表示沒有插入或修改之前的資料;
(2)在uptate型觸發器中,new表示將要(before)或已經(after)修改后的新資料,old表示沒有修改之前的資料;
(3)在delete型觸發器中,old表示已經被洗掉或將要被洗掉的資料;
使用方法:NEW.欄位名 OLD.欄位名
創建語法:
CREATE TRIGGER 觸發器名 before(之前)或after(之后) 觸發事件(insert、delete、update) ON 表名 for each row begin 要執行的sql陳述句 end
DELIMITER // 這個命令是將我們的sql陳述句結束符從’;‘改為’//’
觸發單條sql陳述句:
mysql> CREATE TABLE goods(num INT);
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE sale(snum INT);
Query OK, 0 rows affected (0.06 sec)
mysql> INSERT INTO goods VALUES(100);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO sale VALUES(0);
Query OK, 1 row affected (0.01 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER gs1 AFTER UPDATE ON goods FOR EACH ROW
BEGIN UPDATE sale SET snum=OLD.num-NEW.num; END//
Query OK, 0 rows affected (0.07 sec)
mysql> DELIMITER ;
mysql> UPDATE goods SET num=num-20;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM goods;
±-----+
| num |
±-----+
| 80 |
±-----+
1 row in set (0.00 sec)
mysql> SELECT * FROM sale;
±-----+
| snum |
±-----+
| 20 |
±-----+
1 row in set (0.00 sec)
觸發多條sql陳述句:DELIMITER
m
y
s
q
l
>
C
R
E
A
T
E
T
R
I
G
G
E
R
t
e
s
t
r
e
f
B
E
F
O
R
E
I
N
S
E
R
T
O
N
t
e
s
t
1
F
O
R
E
A
C
H
R
O
W
B
E
G
I
N
I
N
S
E
R
T
I
N
T
O
t
e
s
t
2
S
E
T
a
2
=
N
E
W
.
a
1
;
D
E
L
E
T
E
F
R
O
M
t
e
s
t
3
W
H
E
R
E
a
3
=
N
E
W
.
a
1
;
U
P
D
A
T
E
t
e
s
t
4
S
E
T
a
4
=
a
4
+
1
W
H
E
R
E
a
4
=
N
E
W
.
a
1
;
E
N
D
mysql> CREATE TRIGGER testref BEFORE INSERT ON test1 FOR EACH ROW BEGIN INSERT INTO test2 SET a2=NEW.a1; DELETE FROM test3 WHERE a3=NEW.a1; UPDATE test4 SET a4=a4+1 WHERE a4=NEW.a1; END
mysql>CREATETRIGGERtestrefBEFOREINSERTONtest1FOREACHROWBEGININSERTINTOtest2SETa2=NEW.a1;DELETEFROMtest3WHEREa3=NEW.a1;UPDATEtest4SETa4=a4+1WHEREa4=NEW.a1;END
Query OK, 0 rows affected (0.01 sec)
查看觸發器:
show triggers;或者show triggers\G
由于觸發器的資訊統一存盤在information_schema.triggers 這個表里,所以我們查看這個表就能看到所有的觸發器資訊了;
SELECT * from information_schema.triggers WHERE TRIGGER_NAME=‘tsetref’\G
洗掉觸發器:DROP TRIGGERS 觸發器名:
MySQL用戶與權限:
1.是否允許用戶連接MySQL的server端;usre host password
2.用戶是否擁有對于MySQL庫表的操作權限;privileges
這些權限都記錄在mysql.user這個表里
1.用戶列:
user表里用戶列包含Host、User、password,分別表示主機名、用戶名、密碼,其中user和host為user表里的聯合主鍵,當用戶與服務器之間建立連接時,輸入的賬戶資訊中的用戶名稱,主機名,和密碼必須匹配user表里對應的欄位值,才能夠建立連接,我們修改用戶實際上就是修改user表里password列對應的值;
2.權限列:
權限列的欄位決定了用戶的權限,描述了在全域范圍內允許用戶對 資料進行的操作,包括
查詢權限,修改權限等普通權限,還包括了關閉服務器,超級權限和加載用戶等高級權限,普通的權限用來操作資料庫,高級權限用來管理資料庫;user表中對應的權限是針對所有用戶資料庫的,
這些欄位值的型別為ENUM,可以取的值只有Y和N,Y表示該用戶沒有對應的權限,修改權限,可以使用GRANT陳述句或者UPDATE陳述句更改user表的這些欄位對應的值,來修改對應的權限,
3.安全列 :
安全列只有6個欄位,其中兩個是SSL相關的,2個是x509相關的,另外2個事授權插件相關的,SSI用于加密,x509標準可用于標識用戶,Plugin欄位標識可以用于驗證用戶身份的插件,如果該欄位為空,服務器使用內建授權驗證機制驗證用戶 身份,可以通過SHOW VARIABLES LIKE 'have_openssl’陳述句來查詢服務器是否支持SSL功能;
4.資源控制列 :
資源控制列的欄位用來限制用戶使用的資源,包含4個欄位,分別為:
(1)Max_questions用戶每小時運行執行的查詢操作次數;
(2)Nax_updates用戶每小時允許執行更新操作的次數;
(3)Max_connections用戶每小時允許執行的連接操作次數;
(4)Max_user_connections用戶允許同時建立的連接次數;
db表和host表
這兩個表是MySQL資料中非常重要的權限表,db表中存盤了用戶對某個資料庫的操作權限,決定用戶能從哪個主機存取哪個資料庫,host表中存盤某個主機對資料庫的操作權限,配合db權限表對給主機上資料庫級操作權限做更細致的控制,這個權限表不守GRANT和REVOKE陳述句的影響,db表比較常用,host表一般很少使用,db表和host表結構相似,欄位大致可以分為兩類:用戶列和權限列,
新建普通用戶:
1.使用CREATE USER陳述句來創建新用戶:
CREATE USER user@host [IDENTIFIED BY PASSWORD’password’]
IDENTIFIED BY 表示用來設定用戶密碼;[password]:表示使用哈希值設定密碼;‘password’:用于登錄的明文密碼;
2.使用GRANT陳述句創建用戶:
GRANT’privileges’ ON db.table TO user@host [IDENTIFIED BY’password’] [with grant option]
FLUSH PRIVILEGES:這個命令
privileges 表示賦予用戶的權限型別;db.table:表示用戶的權限鎖作用的資料庫中的表;
with grant option 可選項,表示對新建立的用戶賦予grant權限;
3.直接操作mysql.user:
mysql> INSERT INTO mysql.user(Host,User,Password) VALUES(‘localhost’,‘wangwu’,‘123.com’);
Query OK, 1 row affected, 3 warnings (0.00 sec)
mysql> SHOW warnings;
±--------±-----±--------------------------------------------------+
| Level | Code | Message |
±--------±-----±--------------------------------------------------+
| Warning | 1364 | Field ‘ssl_cipher’ doesn’t have a default value |
| Warning | 1364 | Field ‘x509_issuer’ doesn’t have a default value |
| Warning | 1364 | Field ‘x509_subject’ doesn’t have a default value |
±--------±-----±--------------------------------------------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM user WHERE user=‘wangwu’\G
*************************** 1. row ***************************
Host: localhost
User: wangwu
Password: 123.com
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
通過上面三種方法創建的新用戶還不能直接登錄到MySQL,我們需要重繪權限才可以登錄:FLUSH PRIVLEGES;
INSERT 這種方法創建用戶,我們最好把密碼提前進行加密,然后把加密過的密碼插入到user表里,
mysql> SELECT password(‘123.com’);
±------------------------------------------+
| password(‘123.com’) |
±------------------------------------------+
| *AC241830FFDDC8943AB31CBD47D758E79F7953EA |
±------------------------------------------+
1 row in set (0.02 sec)
洗掉普通用戶:
1.使用DROP USER user@host;洗掉;
mysql> DROP USER ‘zhangsan’@‘localhost’;
Query OK, 0 rows affected (0.00 sec)
2.使用DELETE陳述句洗掉用戶:
DELETE FROM mysql.user WHERE host=‘localhost’ and user=‘zhangsan’;
root用戶修改自己的密碼:
1.使用mysqladmin命令來修改密碼:
mysqladmin -u root -h localhost -p password “newpassword”
Enter password: //這里輸入root的舊密碼
2.修改mysql庫的user表:
mysql> UPDATE mysql.user SET password=password(‘123.com’) WHERE user=‘root’ and host=‘localhost’;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> flush privileges;(重繪權限)
Query OK, 0 rows affected (0.00 sec)
3.使用SET陳述句來修改root用戶的密碼(修改當前登錄用戶的密碼):
SET PASSWORD=PASSWORD(‘newpassword’);
4.那當然你set陳述句還可以修改其他普通用戶的密碼:
SET PASSWORD FOR user@host=password(‘newpassword’);
mysql> SET PASSWORD FOR ‘zhangsan’@‘localhost’=password(‘123.com’);
Query OK, 0 rows affected (0.00 sec)
修改普通用戶的密碼我們還可以用grant授權的方式:
mysql>grant usage on . to ‘zhangsan’@'localhost’identified by ‘321.com’;
Query OK rows affected (0.00 sec)
mysql>flush privileges;
root密碼忘記了怎么辦?
使用–skip-grant-tables選項啟動mysql然后在設定密碼:
[root@localhost ~]# /etc/init.d/mysqld restart --skip-grant-tables
Shutting down MySQL. SUCCESS!
Starting MySQL… SUCCESS!
[root@localhost ~]# mysql -uroot -p
Enter password: //這里直接回車進入mysql
mysql> UPDATE mysql.user SET password=password(‘1234.com’) WHERE user=‘root’ and host=‘localhost’;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
[root@localhost ~]# systemctl restart mysqld
權限管理:
權限管理主要是對登錄到mysql的用戶進行權限驗證,所有用戶的權限都儲存在mysql的權限表里,不合理的權限規劃給mysql服務器帶來安全隱患,mysql權限系統的主要功能是證實連接到一臺給主機的用戶,并賦予該用戶在資料庫中SELECT /INSERT/UPDATE和DELETE等權限,賬戶權限資訊被存盤在MySQL資料庫 的user、db、host、tables_priv、columns_priv等權限表里,在MySQL啟動時,服務器將這些庫表中的權限資訊讀入記憶體中,
1.CREATE和DROP權限,可以創建新資料和表,或洗掉已有的資料庫和表,如果將mysql資料庫中的DROP權限授予某個用戶,這個用戶就可以洗掉它有訪問權限的資料庫和表,
2.SELECT、INSERT、UPDATE和DELETE權限允許在一個資料庫現有的表里實施操作,
3.SELECT權限只有在他們真正從一個表中檢索行時才被用到;
4.INDEX權限允許創建或洗掉索引,INDEX使用已有表,如果具有表的CREATE權限,可以在CREATE TABLE陳述句中包括索引定義,
5.ALTER 權限,可以使用ALTER TABLE來更改表的結構和重新命名表,
6.GRANET權限,允許授權給其他用戶,可用于資料庫、表和保存的程式,
7.file權限給與用戶使用LOAD DATA INFILE和SELECT…INTO OUTFILE陳述句讀或者寫服務器上的檔案,任何被授予file權限的用戶都能讀或寫mysql服務器上的任何檔案,(說明用戶可以讀任何資料目錄下的檔案,因為服務器可以訪問這些檔案),file權限允許用戶在MySQL服務器具有寫權限目錄下創建檔案,但不能覆寫已有檔案,
授權:
授權就是為某個用戶授予授權,合理的授權可以保證資料庫的安全,MySQL中可以使用grant陳述句為用戶授權,
1.全域層級
全域權限適用于一個給定服務中的所有資料庫,這些權限存盤在MySQL表中,CRANT ALL ON *.*和REVOKE ALL ON *.*指收于和撤銷全域權限,
2.資料庫層級
資料庫權限適用于一個給定資料庫中的所有目標,這些權限存盤在mysql.db和mysql.host表中,
GRANT ALL ON db_name 和REVOKE ALL db_name; 只授予和撤銷資料庫權限,
3.表層級:
表權限適用于一個給定表中的所有列,這些權限存盤在mysql.tables_priv表中,CRANT ALL ON table_name;和REVOKE ALL ON table_name;只針對表授予或撤銷權限,
4.列層級:
列權限適用于一個給定表中的某單一的列,這些權限保存在mysql.column_priv表中,當使用REVOKE時,必須指定與被授權相同的列,
在mysq中,必須擁有GRANT權限的用戶才可以執行grant陳述句,要使用grant或revoke,必須有grant option權限,
GRANT語法:
CRANT priv_type1, priv_type2, priv_type3,…ON dbname.tablename,dbname.tablename…TO user@host;
REVOKE(識訓權限)語法:
REVOKE priv_type1, priv_type2, priv_type3,…ON dbname.tablename,dbname.tablename…TO user@host;
查看權限:
SHOW GRANTS陳述句可以顯示指定用戶的權限資訊;
SHOW GRANTS FOR ‘user’@‘host’;
用SELECT陳述句查看user表中的各個權限欄位以確定用戶的權限資訊
SELECT privileges_llist FRO mysql.user WHERE user
mysql的日志:
mysql日志記錄了mysql資料庫日常操作和錯誤資訊,mysql有不同型別的日志檔案(各自存盤了不同型別的日志),從日志當中可以查詢到mysql資料庫的運行情況、用戶的操作、錯誤的資訊等,
MySQL日志分為4大類:
1.錯誤日志:記錄mysql服務的啟動,運行或停止mysql服務時出現問題;
2.一般查詢日志:記錄建立連接客戶端的執行的sql陳述句(耗費時間在<=long_query_tme設定的時間內);
3.慢查詢日志:記錄所有執行的sql陳述句的時間超過long_query_time的所有查詢;
4.二進制日志:記錄所有更改資料的陳述句,可以用于資料復制和恢復,
默認情況下,所有日志創建于mysql資料目錄中,通過重繪日志,可以強制mysql關閉和重新打開日志檔案,flush logs重繪日志或執行mysqladmin flush-logs 如果正在使用mysql復制功能,在復制服務器上可以維護更多日志檔案,這種日志我們稱為接替日志,啟動日志檔案可能會降低mysql資料庫的性能(官方表示,降低的性能不大于1%),
二進制日志:
主要記錄mysql資料的變化,二進制日志以一種有效的格式并且是事務安全的方式包含更新日志中可用的資訊,二進制日志包含了所有更新了的資料,二級制日志還包含關于每個更新資料的陳述句的執行時間,它不包含沒有修改任何資料的陳述句(select、show等),
使用二進制日志的主要目的是最大可能的恢復資料,
啟動二進制日志,默認情況下二進制日志關閉的(開啟日志會降低服務器性能),編輯匹配檔案my.cnf來開啟二進制日志:
格式:
[mysqld]
log-bin=/date/logs/mysql-bin
expire_logs_days=10
Max_binlog_size=100M
log-bin [=path/[filename]] //二進制日志[路徑]指定日志檔案的名字
Expire_logs_days=10
Max_binlog_size=100M
默認為1GB
binlog_format=mixed
重啟mysql,重啟mysql也會產生二進制日志,flush logs 也會出現二進制日志,
二進制日志默認和mysql資料目錄下(/var/mysql),我們也可以自定義,
查看二進制日志是否開啟:SHOW VARIABLES LIKE’log_%’\G
【查看二進制日志】
MySQL二進制日志存盤了所有變更資訊,mysql二進制日志經常使用,,當mysql創建二進制日志檔案時,首先創建一個以‘filename’(默認bin-log)為名稱,以‘index’為后綴的索引檔案(這個檔案是用來記錄二進制日志的檔案名的);在創建一個以‘filename’為名稱,以‘000001’為后綴日志檔案,當mysql服務重啟一次,以‘000001’為后綴的檔案會增加一個,并且后綴加1遞增,如果日志長度超過max_binlog_size的上限,也會創建一個新的日志,
show binary/master logs;可以查看當前的二進制日志檔案個數及其檔案名,
想要查看二進制內容,需要通過mysqlbinlog工具,
【洗掉二進制日志】
mysql的二進制檔案可以匹配自動洗掉,也可以手動洗掉:
1.RESET MASTER;用來洗掉所有二進制日志檔案
2.PPURGE MASTER/BINARY LOGS TO ‘二進制日志檔案名’;用來洗掉單個日志檔案,
mysql> SHOW BINARY LOGS;
±-----------------±----------+
| Log_name | File_size |
±-----------------±----------+
| mysql-bin.000001 | 27130 |
| mysql-bin.000002 | 1031892 |
| mysql-bin.000003 | 1857 |
| mysql-bin.000004 | 478 |
| mysql-bin.000005 | 1398 |
| mysql-bin.000006 | 479 |
| mysql-bin.000007 | 126 |
| mysql-bin.000008 | 462 |
| mysql-bin.000009 | 126 |
| mysql-bin.000010 | 516 |
±-----------------±----------+
10 rows in set (0.00 sec)
mysql> PURGE MASTER LOGS TO ‘mysql-bin.000002’;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW BINARY LOGS;
±-----------------±----------+
| Log_name | File_size |
±-----------------±----------+
| mysql-bin.000002 | 1031892 |
| mysql-bin.000003 | 1857 |
| mysql-bin.000004 | 478 |
| mysql-bin.000005 | 1398 |
| mysql-bin.000006 | 479 |
| mysql-bin.000007 | 126 |
| mysql-bin.000008 | 462 |
| mysql-bin.000009 | 126 |
| mysql-bin.000010 | 516 |
±-----------------±----------+
9 rows in set (0.00 sec)
3.PERGE BINARY/MASTER LOGS BEFORE ‘date(日期名字)’
mysql> PURGE MASTER LOGS BEFORE ‘20200227’;
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW BINARY LOGS;
±-----------------±----------+
| Log_name | File_size |
±-----------------±----------+
| mysql-bin.000010 | 516 |
±-----------------±----------+
1 row in set (0.00 sec)
【還原】
如果mysql服務器啟用了二進制日志,使用二進制日志還原資料庫,使用最后一次備份還原,或指定一個時間恢復資料,
MYSQLBINLOG [option] 日志檔案名 mysql -u usre -p ‘password’
[option]里面的選項–start-date 開始時間 --stop-positon=結束的位置;
[root@localhost bin]# ./mysqlbinlog --start-datetime=‘2020-02-26 23:23:56’ /usr/local/mysql/data/mysql-bin.000010 -uroot -p1234.com
【暫時停止二進制日志的功能】
如果mysql的組態檔已經啟動了二進制日志,mysql會一直記錄二進制日志,修改組態檔,可以停止二進制日志,但是需要從起mysql,mysql提供了暫時停止二進制日志的功能,通過SET SQL_LOG_BIN陳述句可以是mysql暫時停止二進制
mysql>SET SQL_LOG_BIN=0; 暫停二進制
錯誤日志:
錯誤日志檔案包含了當mysql啟動和停止時,以及服務器在運行程序中發生任何嚴重錯誤時的相關資訊,
設定錯誤日志:
在默認的情況下錯誤日志是開啟的,它默認被記錄到資料目錄下/var/mysql/data/,如果,沒有在組態檔中指定檔案名,檔案默認為hostname.err(localhost.localdomain.err),執行flushlogs;錯誤日志檔案會重新加載,在my.cnf中添加 log-error=路徑/檔案名 來自定義錯誤日志檔案,
【查看錯誤日志的存盤路徑】
通過錯誤日志可以見識系統的運行狀態,便于即使發現故障、修復故障,mysql錯誤日志是以文本檔案的形式存盤的,可以使用文本編輯器直接查看;
洗掉錯誤日志:
mysql的錯誤日志是以文本檔案的形式存盤的,可以直接洗掉,
在運行狀態下洗掉錯誤日志檔案后,則會自動創建,
【重繪所有日志】
一般查詢日志:
它記錄了所有用戶的操作,寶庫啟動和關閉服務、執行查詢和更新陳述句等,mysql默認沒有開啟
一般查詢日志,如果需要可以修改my.cnf來開啟,在my.cnf里添加log = /路徑/檔案名,一般查詢
日志是以文本格式檔案存盤的,日知名.Pid, 可以直接洗掉,開啟一般查詢并且mysql服務在
運行狀態下,洗掉了日志檔案,它會自動創建新的,
慢查詢日志:
慢查詢日志是記錄查詢時長超過指定時間的日志,慢查詢日志主要用來優化查詢陳述句的,慢查詢
日志默認是關閉的,我們可以修改組態檔來開啟:
[mysqld]
log-slow-queries //開啟慢查詢
long_query_time = 1 //設定慢查詢時間,默認10秒
查看慢查詢日志
MySQL慢查詢日志是以文本檔案的形式存盤的,可以直接使用文本編輯器查看,
洗掉慢查詢日志可以直接洗掉,洗掉后不再重啟服務器的情況,需要執行
mysqladmin -u root -p flush-logs 重新生成日志檔案,或者在客戶端登陸到服務器執行
flush logs陳述句重建日志檔案,
MySQL主從復制概念MySQL主從復制是指資料可以從一個MySQL資料庫服務器主節點復制到一個或多個從節點,MySQL默認采用異步復制方式,這樣從節點不用一直訪問主服務器來更新自己的資料,資料的更新可以在遠程連接
MySQL主從復制主要用途讀寫分離
在開發作業中,有時候會遇見某個sql陳述句需要鎖表,導致暫時不能使用讀的服務,這樣就會影響現有業務,使用主從復制,讓主庫負責寫,從庫負責讀,這樣即使主庫出現了
MySQL主從形式:一主一從、一主多從、多主一從、雙主復制、
一主一從和一主多從
杜興宇 16:04:50
MySQL 主從復制概念MySQL 主從復制是指資料可以從一個MySQL資料庫服務器主節點復制到一個或多個從節點,MySQL 默認采用異步復制方式,這樣從節點不用一直訪問主服務器來更新自己的資料,資料的更新可以在遠程連接上進行,從節點可以復制主資料庫中的所有資料庫或者特定的資料庫,或者特定的表,
MySQL 主從復制主要用途l 讀寫分離
在開發作業中,有時候會遇見某個sql 陳述句需要鎖表,導致暫時不能使用讀的服務,這樣就會影響現有業務,使用主從復制,讓主庫負責寫,從庫負責讀,這樣,即使主庫出現了鎖表的情景,通過讀從庫也可以保證業務的正常運作,
l 資料實時備份,當系統中某個節點發生故障時,可以方便的故障切換
Mysql在3.25.15版本開啟復制功能,mysql復制是將一個服務器(master)中的資料復制到其他服務器(slave)的程序,Mysql將存放DDL和DML的二進制日志發送到其他服務器上,然后從服務器(slave)將得到的二進制日志進行執行,從而保證主從服務器上的資料保持同步,
l 高可用HA 讀寫分離,分擔服務器的壓力;
l 架構擴展 并發量增大,我們可以通過增加主從服務器的數量來擴展并發,
隨著系統中業務訪問量的增大,如果是單機部署資料庫,就會導致I/O訪問頻率過高,有了主從復制,增加多個資料存盤節點,將負載分布在多個從節點上,降低單機磁盤I/O訪問的頻率,提高單個機器的I/O性能,
MySQL 主從形式:一主一從、一主多從、多主一從、雙主復制、級聯復制
一主多從,提高系統的讀性能
一主一從和一主多從是最常見的主從架構,實施起來簡單并且有效,不僅可以實作HA,而且還能讀寫分離,進而提升集群的并發能力,
多主一從 (從5.7開始支持)
雙主復制
雙主復制,也就是互做主從復制,每個master既是master,又是另外一臺服務器的slave,這樣任何一方所做的變更,都會通過復制應用到另外一方的資料庫中,
級聯復制
級聯復制模式下,部分slave的資料同步不連接主節點,而是連接從節點,因為如果主節點有太多的從節點,就會損耗一部分性能用于replication,那么我們可以讓3~5個從節點連接主節點,其它從節點作為二級或者三級與從節點連接,這樣不僅可以緩解主節點的壓力,并且對資料一致性沒有負面影響,
MySQL 主從復制原理MySQL主從復制涉及到三個執行緒,一個運行在主節點(log dump thread),其余兩個(I/O thread, SQL thread)運行在從節點,如下圖所示:
主節點 binary log dump 執行緒
當從節點連接主節點時,主節點會創建一個log dump 執行緒,用于發送bin-log的內容,在讀取bin-log中的操作時,此執行緒會對主節點上的bin-log加鎖,當讀取完成,甚至在發送給從節點之前,鎖會被釋放,
l 從節點I/O執行緒
當從節點上執行start slave命令之后,從節點會創建一個I/O執行緒用來連接主節點,請求主庫中更新的bin-log,I/O執行緒接收到主節點binlog dump 行程發來的更新之后,保存在本地relay-log中,
l 從節點SQL執行緒
SQL執行緒負責讀取relay log中的內容,決議成具體的操作并執行,最終保證主從資料的一致性,
杜興宇 16:05:24
對于每一個主從連接,都需要三個行程來完成,當主節點有多個從節點時,主節點會為每一個當前連接的從節點建一個binary log dump 行程,而每個從節點都有自己的I/O行程,SQL行程,從節點用兩個執行緒將從主庫拉取更新和執行分成獨立的任務,這樣在執行同步資料任務的時候,不會降低讀操作的性能,比如,如果從節點沒有運行,此時I/O行程可以很快從主節點獲取更新,盡管SQL行程還沒有執行,如果在SQL行程執行之前從節點服務停止,至少I/O行程已經從主節點拉取到了最新的變更并且保存在本地relay日志中,當服務再次起來之后,就可以完成資料的同步,
要實施復制,首先必須打開Master 端的binary log(bin-log)功能,否則無法實作,
因為整個復制程序實際上就是Slave 從Master 端獲取該日志然后再在自己身上完全順序的執行日志中所記錄的各種操作,如下圖所示:
復制的基本程序如下:
從節點上的I/O 行程連接主節點,并請求從指定日志檔案的指定位置(或者從最開始的日志)之后的日志內容;主節點接收到來自從節點的I/O請求后,通過負責復制的I/O行程根據請求資訊讀取指定日志指定位置之后的日志資訊,回傳給從節點,回傳資訊中除了日志所包含的資訊之外,還包括本次回傳的資訊的bin-log file 的以及bin-log position;從節點的I/O行程接收到內容后,將接收到的日志內容更新到本機的relay log中,并將讀取到的binary log檔案名和位置保存到master-info 檔案中,以便在下一次讀取的時候能夠清楚的告訴Master“我需要從某個bin-log 的哪個位置開始往后的日志內容,請發給我”;Slave 的 SQL執行緒檢測到relay-log 中新增加了內容后,會將relay-log的內容決議成在主節點上實際執行過的操作,并在本資料庫中執行,
MySQL 主從復制模式MySQL 主從復制默認是異步的模式,MySQL增刪改操作會全部記錄在binary log中,當slave節點連接master時,會主動從master處獲取最新的bin log檔案,并把bin log中的sql relay,
l 異步模式(mysql async-mode)
異步模式如下圖所示,這種模式下,主節點不會主動push bin log到從節點,這樣有可能導致failover的情況下,也許從節點沒有即時地將最新的bin log同步到本地,
l 半同步模式(mysql semi-sync)
這種模式下主節點只需要接收到其中一臺從節點的回傳資訊,就會commit;否則需要等待直到超時時間然后切換成異步模式再提交;這樣做的目的可以使主從資料庫的資料延遲縮小,可以提高資料安全性,確保了事務提交后,binlog至少傳輸到了一個從節點上,不能保證所有從節點將此事務更新到db中,性能上會有一定的降低,回應時間會變長,如下圖所示:
半同步模式不是mysql內置的,從mysql 5.5開始集成,需要master 和slave 安裝插件開啟半同步模式,
l 全同步模式
全同步模式是指主節點和從節點全部執行了commit并確認才會向客戶端回傳成功,
杜興宇 16:05:43
binlog記錄格式MySQL 主從復制有三種方式:基于SQL陳述句的復制(statement-based replication,SBR),基于行的復制(row-based replication,RBR),混合模式復制(mixed-based replication,MBR),對應的binlog檔案的格式也有三種:STATEMENT,ROW,MIXED,
l Statement-base Replication (SBR)就是記錄sql陳述句在bin log中,Mysql 5.1.4 及之前的版本都是使用的這種復制格式,優點是只需要記錄會修改資料的sql陳述句到binlog中,減少了binlog日質量,節約I/O,提高性能,缺點是在某些情況下,會導致主從節點中資料不一致(比如sleep(),now()等),
l Row-based Relication(RBR)是mysql master將SQL陳述句分解為基于Row更改的陳述句并記錄在bin log中,也就是只記錄哪條資料被修改了,修改成什么樣,優點是不會出現某些特定情況下的存盤程序、或者函式、或者trigger的呼叫或者觸發無法被正確復制的問題,缺點是會產生大量的日志,尤其是修改table的時候會讓日志暴增,同時增加bin log同步時間,也不能通過bin log決議獲取執行過的sql陳述句,只能看到發生的data變更,
l Mixed-format Replication(MBR),MySQL NDB cluster 7.3 和7.4 使用的MBR,是以上兩種模式的混合,對于一般的復制使用STATEMENT模式保存到binlog,對于STATEMENT模式無法復制的操作則使用ROW模式來保存,MySQL會根據執行的SQL陳述句選擇日志保存方式,
GTID復制模式@ 在傳統的復制里面,當發生故障,需要主從切換,需要找到binlog和pos點,然后將主節點指向新的主節點,相對來說比較麻煩,也容易出錯,在MySQL 5.6里面,不用再找binlog和pos點,我們只需要知道主節點的ip,埠,以及賬號密碼就行,因為復制是自動的,MySQL會通過內部機制GTID自動找點同步,
@ 多執行緒復制(基于庫),在MySQL 5.6以前的版本,slave的復制是單執行緒的,一個事件一個事件的讀取應用,而master是并發寫入的,所以延時是避免不了的,唯一有效的方法是把多個庫放在多臺slave,這樣又有點浪費服務器,在MySQL 5.6里面,我們可以把多個表放在多個庫,這樣就可以使用多執行緒復制,
基于GTID復制實作的作業原理主節點更新資料時,會在事務前產生GTID,一起記錄到binlog日志中,從節點的I/O執行緒將變更的bin log,寫入到本地的relay log中,SQL執行緒從relay log中獲取GTID,然后對比本地binlog是否有記錄(所以MySQL從節點必須要開啟binary log),如果有記錄,說明該GTID的事務已經執行,從節點會忽略,如果沒有記錄,從節點就會從relay log中執行該GTID的事務,并記錄到bin log,在決議程序中會判斷是否有主鍵,如果沒有就用二級索引,如果有就用全部掃描,
總結Mysql 主從復制是mysql 高可用,高性能的基礎,有了這個基礎,mysql 的部署會變得簡單、靈活并且具有多樣性,從而可以根據不同的業務場景做出靈活的調整,
MySQL的備份:
1.備份的重要性:
在生產環境中,為了防止硬體故障、軟體故障、自然災害、誤操作等各種原因導致的資料庫資料丟失后能恢復到事故之前的狀態,我們需要對資料庫進行備份和恢復操作,資料庫的備份和恢復是非常重要的作業,資料的備份不是最終目的,資料的恢復才是;
2.備份時應該注意的事項:
1.最多能容忍多少資料丟失;決定了備份間隔時間、備份的方式;
2.恢復資料需要在多長時間之內完成;備份方式、備份的工具;
3.需要恢復哪些資料;決定了備份的內容;
4.定期測驗備份的可用性并提高恢復操作的效率;
5.備份時的服務器負載;
6.鎖定資源的時長;
備份的型別
a.按照備份的資料集的范圍分類:
完全備份:整個資料集都進行備份;
部分備份:資料集的一部分,比如部分表;
b.按照資料的變化分類:
全量備份:將整個mysql的所有庫表進行備份;
增量備份:僅備份自上一次完全備份或增量備份以來變數的那部分資料;
差異備份:僅備份自上一次完成全量備份以來變數的那部分資料;
c.按照操作物件分類:
物理備份:直接從磁盤復制資料檔案進行備份;
邏輯備份:從資料庫匯出資料另存在一個或多個文本中,將資料轉化為具體的sql陳述句;
d.按照資料服務備份時的運行狀態分類:
熱備:讀寫操作均可正常運行的狀態下所做的備份;
溫備:可讀但不可寫狀態下進行的備份;
冷備:讀寫操作均不可進行,服務需要停止的狀態下進行的備份,
3.備份策略:
備份策略一般都是 全量+差異+binlogs 或者是:全量+增量+binlogs,
需要注意的是,如果需要更完整的備份資料,還需要依靠binlongs(二進制日志),binlogs是mysql最重要的日志之一,他記錄了所有的DDL和DML,以事件的形式記錄,這里強烈建議在生產環境中,將資料與二進制日志分開存放并對二進制日志也做備份,
4.mysql備份工具:
(1)mysqldump:mysql服務自帶的備份工具,mysqldump是一個邏輯備份工具,mysqldump的本質是將資料庫轉為可執行sql腳本,檔案名以sql結尾,可以用來做完全備份和部分備份,
支持InnoDB存盤引擎的熱備份功能,MyISAM存盤引擎的溫備功能,
(2)系統自帶的cp/tar工具:這是一種物理備份,它屬于冷備份,需要注意的是不能僅僅備份資料,要同時備份事務日志,并且要求資料和日志在同一邏輯卷,
(3)xtrabackup:由Percona開發的很強大的開源工具,支持對InnoDB做熱備,物理備份工具,
(4)mysql hotcopy:通過復制庫表目錄來實作mysql的備份;
mysqldump的語法:
備份:mysqldump -u root -p 庫 表>路徑/檔案名.sql
1.對單個庫進行備份:
mysqldump -u user -p databasename> /路徑/檔案名.sql
2.對單個庫中的表進行備份:
mysqldump -u user -p databasename tablename1 tablename2 tablename3…> /路徑/檔案名.sql
3.對多個庫進行備份:
mysqldump -u user -p -B/–databases 庫1 庫2 庫3…>/路徑/檔案名.sql
4.對所有庫的所有內容進行備份:
mysqldump -u user -p -A/–databases > /路徑/檔案名.sql
還有幾個引數:
-R 匯出存盤程序和自定義函式;
-t 只備份資料而不備份表結構;
-d 只備份表結構,不備份資料;
–lock-table 在備份時進行鎖表;
–add-locks 在執行insert之前和之后進行鎖表
–default-character-set 字串 指定字符集
–single-transaction 備份期間不會鎖表也不會組織任何的事務;
注意!【在命令列創建一個路徑:mkdir /zhy】
備份恢復:
第一種方法:
1.在mysql里面:CREATE DATABASE databasename;
2.在命令列執行:mysql -u user -p databasename < /備份路徑/檔案名.sql
第二種方法:
1.CREATE DATABASE databasename;
2.USE databasename;
3.source /備份路徑/檔案名.sql
第二種:cp/tar 這是一種冷備份:他需要關閉服務情況下才行,
冷備份的優點:
1.非常快速的備份方法(直接拷貝檔案);
2.容易歸檔(簡單拷貝即可)
3.容易恢復到某個時間點上(只需要將檔案在拷貝回去);
4.低度維護,告訴安全,
缺點:
1.單獨使用時,只能提供到’某個時間點上’的恢復,
2.備份和還原的全程序必須停止服務;
3.若磁盤空間有限,只能拷貝到外部存盤設備上,速度會慢,
4.不能按表或者用戶來還原資料,
第三種:mysqlhotcopy:適用于MyISAM引擎,不適用于InnoDB,它是屬于熱備,而且速度快 ,適合資料量大的資料庫備份;
原理:它使用LOCK TABLES,FLUSH TABLE和cp或者scp來快速備份資料庫,
他是備份資料庫或單個表的最快的途徑,
mysqlhotcopy 他是perl語言一個工具,所以它需要per的支持:
yum -y install per per-DBI perl-DBI-MySQL
備份語法:
mysqlhotcopy -u user -p ‘password’ db_name tablename /備份路徑/檔案名
還原語法:
cp -R /備份路徑/檔案名 /var/mysql/data
chown -R /var/mysql/data
重啟服務;
冷備份:在資料庫關閉狀態下進行備份操作,
熱備份:早資料庫處于運行時進行備份操作,該備份方法依賴資料庫的日志檔案,
溫備份:資料庫鎖定表格(不可寫入但可讀)的狀態下進行備份操作,
MySQL的優化:
mysql性能優化就是通過合理安排資源,調整系統引數使mysql運行更快、
更節省資源,mysql優化,一方面是找出系統瓶頸,提高mysql資料庫整體的性能,,另一方面需要合理的結構設計和引數調整,以提高用戶操作回應的速度,同時還要盡可能節省系統資源,以便系統可以提供更大負荷的服務,mysql資料庫優化是多方面的,原則是減少系統的瓶頸,減少資源的占用,提高系統反應速度,包含,性能優化、查詢優化、資料庫結構和mysql服務器優化,
mysql中可以使用SHOW STATUS陳述句查詢一些mysql資料庫的性能引數,
SHOW STATUS LIKE ‘value’;
value指的是性能引數;
1.connection,連接mysql服務器的次數;
2.update,mysql服務器上線的時間;
3.slow_queries,慢查詢的次數;
4.com_insert,插入操作的次數,
5.com_select,查詢的次數;
6.com_update,更新的次數;
7.com_delete,洗掉操作的次數;
設定最大連接數:
SET GLOBAL MAX_CONNECTIONS=5000;
最大可以設定16384,超過了沒用
查看當前被使用的connection
show variables like max_user_connections;
分析查詢陳述句:
通過分析查詢陳述句,可以了解查詢陳述句執行的情況,找出查詢陳述句的瓶頸,從而優化查詢陳述句,
mysql中提供了EXPLAIN陳述句和DESCRIBE(可以縮寫為DESC)陳述句,來分析查詢陳述句,
EXPLAIN的語法:
EXPLAIN [EXTENDED]SELECT options;
EXTENDED 關鍵字,EXPAIN陳述句會產生附加資訊;options是select陳述句的查詢選項,包括from、where子句等等,
執行這個陳述句可以分析EXPLAIN 后面的查詢陳述句的執行情況,并且能夠分析出所查詢的表的一些特征,
mysql>EXPLAIN SELECT * FROM db_info;
1.SIMPLE(simple)表示簡單查詢,其中不包括子查詢和連接查詢;
2.PRIMARY(primary)表示主查詢,或者是最外層的查詢陳述句;
3.UNION(union)表示連接查詢的第2個或者后面的查詢陳述句,
4.DEPENDENT UNION(dependent union)表示連接查詢中的第二個或者后面的select陳述句,取決于外面的查詢,
5.UNION RESULT 表示連接查詢的結果;
6.SUBQUERY 表示子查詢的第1個select陳述句;
7.DEPENDENT SUBQUERY 子查詢的第1個select,取決于外面的查詢;
8.DERIVED 表示匯出表的select(from子句的查詢),
c.type:表示連接型別:
1.ALL:對于前面的表的任意的行組合,進行完整的表掃描,通常可以增加更多的索引來避免使用all連接;
2.index,它只掃描索引數,而不是全表資料,通常比ALL 型別要快,因為索引檔案通常比資料檔案小;
3.system,表示僅有一行的系統表,是const連接型別一個特例,
4.const:資料表最多只有一個匹配行,他將在查詢開始時被讀取,并在余下的查詢優化中作為常量對待,const表查詢速度很快,因為它只讀一次,const與使用常數值比如primary key 或者union索引的所有部分的場合,
mysql>explain select * from db_info WHERE id=2;
5.eq_ref:對于某個來自前面的表的行組合,從該表中讀取一行,當一個索引的所有部分都在查詢中使用并且索引是unique或primary key時候即可使用這種型別,eq_ref 可以用于使用‘=’運算子比較帶索引的列,比較值可以為常量或者一個在該表前面所讀取的表的列的運算式,
EXPLAIN SELECT * FROM user,db_info WHERE user.com_id_info.com_id;
6.RE對于來自前面的表的任意行組合,將從該表中讀取所有匹配行,這種型別用于所既不是unique也不是primary key 的情況,或者查詢中使用了所引例的左子集,即索引中左邊的部分組合ref可以用于使用=或者<=>運算子的帶索引的列,
7.ref_or_null,該鏈接型別是如果是ref型別,但是添加了mysql可以專門搜索包含null值得行,在解決子查詢中經常使用該鏈接型別得優化;
8.index_merge:該鏈接型別表示使用了索引合并優化方法,在這種情況下,key列包含了使用得索引得清單,key_len包含了 使用得索引得最長得關鍵元素;
9.index_subquery,:該鏈接型別類似于unique_subquery,可以替換in子查詢,但是只適合下列形式得子查詢中非唯一索引,
10.range:只檢索給定范圍得行,使用一個索引來選擇行,key列顯示使用得那個索引,key_len包含所使用得最長關鍵元素,當使用=,<>,<=,is null, <=>, between或者in運算子,用常量比較關鍵字列時,型別為range,
possible_keys:它列出的是mysql能使用哪個索引在該表中找到行,如果該列是null,則沒有相關的索引,在這種情況下,可以通過檢查 where子句看他是否參考某些列或者適合索引的列來提高查詢性能,如果是這樣,可以創建適合的索引來提高查詢的性能,
ref:表示使用哪個列或者常熟或者索引一起來查詢記錄,
rows:顯示mysql在表中進行查詢必須檢查的行數,
extra:顯示mysql在處理查詢時的詳細資訊,
DESCRIBE陳述句和EXPLAIN陳述句的用法以及效果一樣,
索引對于查詢速度的影響:
mysql中提高性能的最有效的方式就是對資料表設計合理的索引,索引提供了高效的方法,
因此,索引對查詢的速度有著至關重要的影響,使用所有可以快速的定位的某條記錄,從而調高資料庫的查詢速度,提高資料庫的性能,如果查詢的時候沒有使用索引,mysql將掃描全表的所有記錄,在資料量大的情況下,這樣的查詢的速度會很慢,如果使用索引進行查詢,查詢陳述句可以依據索引快速定位到待查詢的記錄,從而減少查詢的記錄數,達到提高查詢速度的目的,
使用索引的幾種特殊情況:
1.使用like關鍵字的查詢陳述句,如果匹配字串的第一個字符為‘%’,索引不會起作用,只有‘%’不在第一個位置的時候,索引才會起到作用,
mysql> EXPLAIN SELECT * FROM db_info WHERE name LIKE ‘%jack’;
±—±------------±--------±-----±--------------±-----±--------±-----±-----±------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
±—±------------±--------±-----±--------------±-----±--------±-----±-----±------------+
| 1 | SIMPLE | db_info | ALL | NULL | NULL | NULL | NULL | 3 | Using where |
±—±------------±--------±-----±--------------±-----±--------±-----±-----±------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM db_info WHERE name LIKE ‘jack%’;
±—±------------±--------±------±--------------±------±--------±-----±-----±------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
±—±------------±--------±------±--------------±------±--------±-----±-----±------------+
| 1 | SIMPLE | db_info | range | in_dx | in_dx | 62 | NULL | 1 | Using where |
±—±------------±--------±------±--------------±------±--------±-----±-----±------------+
1 row in set (0.00 sec)
2.使用多組合引的查詢陳述句,一個組合索引最多可以包含16個欄位,對于組合索引,只有查詢條件中使用了最左邊的索引欄位,
3.使用or關鍵字的查詢陳述句,查詢條件中有or關鍵字,且or前后的兩個條件中的欄位都有索引時,查詢中才使用索引,否則,查詢將不適用索引,
優化資料庫表結構:
分庫和分表:
垂直分和水平分:
什么時候需要分庫:當一個庫里面的數量很多時,并且查詢率很高,為了降低單個庫的負荷,我們把一個庫里面的表按照不同的業務型別放到多個庫里面,這個叫做垂直分,水平分指庫里面的表的資料量特別大,我們把同一個表里不常用的欄位給他分離到其他庫里面,
什么時候分表:當一個資料庫里面的欄位和數量特別龐大的時候,為了提高查詢速度,我們根據業務把不同的欄位分到多個表里,這個叫垂直分表,把一個表里的資料從一個位置分離到多個表里,
優化插入資料的速度:
(1)禁止索引:alter table 表名 disable keys;
(2)禁用唯一性檢查:set unique_checks=0 (1開啟,0禁用);
(3)禁用外鍵檢查:set foreign_checks=0;
(4)盡量自動提交:set autocommit=0;
(5)盡量使用批量插入:insert into db_info(name,sex)value(‘lucy’,2),(‘tom’,1),(‘jack’,男);
(6)
第一章:初識redis
redis(Remote dictionary server)是一個開源(BSD許可),是一種基于鍵值對(key-value)的NoSQL資料庫,redis是一個記憶體存盤結構的服務器,可以做告訴快取和訊息列隊代理,
與很多鍵值對資料庫不同的是,redis支持字串(string)、哈希表(hash)、串列(list)、集合(set)、有序集合(zset)、位圖(bitmaps)、Hyperloglogs、GEO等資料結構和演算法組成,因此redis可以滿足很多的應用場景,而且因為redis會將資料存放在記憶體中,所以它的讀寫速度非常驚人,讀:110000/s 寫:85000/s 不僅如此,redis還可以將記憶體中的資料利用快照和日志的形式保存到磁盤上,這樣在發生斷電或者機器故障的時候,記憶體中的資料不會‘丟失’,
redis還提供了鍵過期、流水線、哨兵、內置復制、lua腳本語言、LRU識訓、事務、同時通過redis sentinel 提供高可用,通過redis cluster 提供自動磁區,
redis的特性:
1.速度快:
正常情況下,redis執行命令的速度非常快,讀:110000/s 寫:80000/s
為什么快?
(1)把資料存放在記憶體中,是redis速度快的主要原因;
(2)redis是用C語言撰寫的,一般來說C語言實作的程式‘距離’ 作業系統更近,執行速度更快;
(3)redis使用了單執行緒架構,預防了多線可能產生的競爭問題,
2.基于鍵值對的資料結構服務器:
幾乎所有的編程語言都提供了類似字典的功能,例如java里的map,Python里的dict,類似于這種組織資料的方式,與很多鍵值對資料庫不同的是,redis中的值不僅可以是字串,而且還可以是具體的資料結構,這樣不僅能便于在許多應用場景的開發,同時也能夠提高開發效率,
主要的資料結構有5種:
字串(string)、哈希表(hash)、串列(list)、集合(set)、有序集合(zset)、
同時在字串的基礎上演變出了位圖和Hyperloglog這兩種神奇的資料結構,并且隨著LBS(loclation based server基于位置服務)的不斷發展,redis3.2版本中加入有關GEO(地理資訊定位的功能,總之在這些資料結構的幫助下,開發者可以開發出各種’有意思’的應用)
3.豐富的功能:
除了多種資料結構,redis還提供了許多額外的功能:
(1)提供了鍵過期功能,還可以來實作快取;
(2)提供了發布訂閱功能,可以來實作訊息系統;
(3)支持Lua腳本功能,可以利用Lua創造出心得redis命令;
(4)提供了簡單得事務功能,能在一定程度上保證事務特性;
(5)提供了流水線(Pipeline)功能,這樣客戶端能將一批命令一次性傳到redis,減少了網路得開銷;
4.簡單穩定:
redis的簡單主要表現在三個方面,首先,redis的原碼很少,早期版本只有2萬,3.0版本后添加了集群特性,代碼增至5萬行左右,相對于很多NoSQL資料庫來說代碼量要少很多,其次redis,redis使用單執行緒模型,這樣不僅使redis服務端處理模型變得簡單,而且也是使用客戶端開發變得簡單,最后redis不需要依賴于作業系統中的類別庫(例如Memcache需要依賴libevent這樣的系統類別庫),redis自己實作了事件處理的相關功能,
5.客戶端語言多:
redis提供了簡單的TCP通信協議,很多編程語言可以很方便地介入redis,并且由于redis受到社區和大公司的廣泛認可,所以支持redis的客戶端語言也非常多,幾乎涵蓋了主流的編程語言,
例如:java、php、python、C、C++、Nodejs等;
6.持久化:
通常看,將資料放在記憶體中是不安全的,一旦發生斷電或者機器故障,重要的資料可能丟失,因此redis提供了兩種持久化方式:RDB和AOF,即可以用兩種策略將記憶體資料保存到磁盤中,這樣就保證了資料的持久性;
7.主從復制:
redis提供了復制功能,實作了多個相同資料的redis副本,復制功能是分布式redis的基礎,
8.高可用和分布式
redis從2.8版本正式提供高可用實作redis sentinel,它能夠保證redis節點的故障發現和故障自動轉移,redis從3.0版本正式提供了分布實作redis cluster,他是redis真正的分布式實作,提供了高可用、讀寫和容量的擴展性,
redis的使用場景:
1.快取
快取機制幾乎在所有的大型網站都有使用,合理地使用快取不僅可以加快資料的訪問速度,而且能夠有效的降低后端資料源的壓力,redis提供了鍵值對過期時間設定,并且也提供了靈活控制最大記憶體和存溢位后的淘汰策略,可以這么說,一個合理的快取設計能夠稱謂一個網站的穩定保駕護航,
2.排行榜系統:
排行榜系統幾乎存在于所有的網站,例如按照熱搜度的排行榜,按照發布時間的排行榜,按照各種復雜維度計算出的排行榜,redis提供了串列和有序合數架構,合理地使用這些資料結構,可以很方便的構建各種排行系統,
3.計算器的應用:
計算器在網站中的作用至關重要,例如視屏網站有瀏覽數,為了保證資料的實時性,每次播放和瀏覽要做加1的操作,如果并發量很大對于傳統關系資料庫的性能是一種挑戰,redis天然支持技術功能而且計數的性能也非常好,可以i說是計算器系統的重要選擇,
4.社交網路:
贊/踩、粉絲、共同好友/喜好、推送、下拉重繪等是社交網站的必備功能,由于社交網站訪問量通常比較大,而且傳統的關系型資料庫不太適合保存這種型別的資料,redis提供的資料結構可以相對容易地實作這些功能,
5.訊息列隊系統:
訊息列隊系統可以說是一個大型網站的必備基礎組件,因為其具有業務解耦、非實時業務肖峰等特征,redis提供了發布訂閱功能和阻塞佇列的功能,雖然和專業的訊息佇列比還不夠強大,但是對于一般的訊息佇列功能基本可以滿足,
redis的缺點:
實際上任何一門技術都一樣,他都有自己的應用場景和邊界,也就是說redis不是萬能的,有很多問題也是redis不適合解決的,我們從資料的規模和冷熱的角度來分析:
站在資料規模的角度看,資料可以分為大規模和小規模,我們redis將資料存盤在記憶體中,雖然目前記憶體的價格已經相對便宜了,但是資料量太大,例如每天有幾億的用戶行為資料,使用redis的話,基本是無底洞,經濟成本會非常高,
站在資料冷熱的角度看,資料分冷資料和熱資料,熱資料就是需要頻繁操作的資料,反之為零冷資料,例如對于視頻網站來說,視頻基本資訊在各個業務線都是經常操作的資料,而用戶的觀看記錄不一定經常需要訪問,所以視頻資訊就屬于熱資料,而用戶觀看記錄屬于冷資料,如果將冷資料也放在redis里,就會造成對于記憶體資源的浪費,但是對于熱資料,就可以放在redis中加速讀寫,也可以減輕后端存盤的負載,可以說是事半功倍,
所以redis的使用也要根據實際情況來決定,
第二章 redis得全域命令和資料結構
安裝目錄下src/里面的可執行命令:
redis-server 啟動redis服務的命令
redis-cli 啟動redis客戶端的
resis-server redis的哨兵服務
redis-check-aof redis-check-rdb 持久化檔案的檢查修復
redis-benchmark redis的基準測驗工具
redis的日志級別:debug、varbose、notice、warning
debug:記錄很多資訊,用于開發和測驗
varbose:有用的資訊,比debug記錄的資訊少
notice:普通的varbose,常用于生產環境
warning:只有非常重要的資訊會記錄到日志
redis的全域命令:
keys * 查看所有的鍵
dbsize 統計鍵的總和(個數)
exists ‘key’ 判斷這個key是否存在,回傳1表示存在,回傳0表示不存在
del key1 key2 … 洗掉鍵值對
鍵過期:
1.set key value [EX seconds] [PX milliseconds] 給新添加的鍵值對設定過期時間
2.expire key seconds 給已有的鍵值對設定過期時間
ttl key 查看鍵的過期時間,回傳+數表示還有多少時間過期,回傳-1表示未給這個key設定過期時間,回傳-2表示這個key已經過期,并且被洗掉或者是這個鍵就不存在了,
redis的資料型別:
1.string(字串):
字串型別是redis最基礎的資料結構,首先鍵都是字串型別,而且其他幾種資料結構都是在字串型別的基礎上構建的,所以字串型別能為其他四種資料結構的學習奠定基礎,字串實際上可以是字串(簡單的字串、復雜的字串),也可以是數字,甚至是二進制(圖片、音頻、視頻),但是最大不能超過512M,
命令格式:
set key value [ex seconds] [px mileseconds] [nx|xx]
[ex seconds] 為鍵設定過期時間,單位是秒
[px mileseconds] 單位是毫秒
nx 鍵必須不存在,才可以設定成功,用于添加;
xx 鍵必須存在,才可以設定成功,用于更新;
命令:
setnx key value [xx]
setnx這個命令在新添加鍵值對的時候非常有用,它能夠避免我們把已有鍵的值誤修改,回傳0說明這個鍵已存在,并且我們的命令不會被執行;回傳1,說明這個鍵不存在,鍵值對添加成功,
獲取值的命令:get key
批量設定鍵值對:
mset key1 value1 key2 value2…
例:mset a 1 b 2 c 3 d 4
計數:
incr key
incr只能對數字自增
值不是整數的時候,回傳錯誤,值是整數,回傳整數+1,如果鍵不存在,按0開始自增,回傳結果是1
列:
127.0.0.1:6379> incr a
(integer) 2
127.0.0.1:6379> get a
“2”
127.0.0.1:6379> incr a
(integer) 3
127.0.0.1:6379> get a
“3”
127.0.0.1:6379> incr f
(integer) 1
127.0.0.1:6379> incr f
(integer) 2
127.0.0.1:6379> incr f
(integer) 3
127.0.0.1:6379> get f
“3”
decr key(自減)
例:
127.0.0.1:6379> decr f
(integer) 2
127.0.0.1:6379> decr f
(integer) 1
127.0.0.1:6379> decr f
(integer) 0
127.0.0.1:6379> decr f
(integer) -1
127.0.0.1:6379> decr f
(integer) -2
127.0.0.1:6379> keys *
- “a”
- “e”
- “f”
- “b”
- “c”
- “d”
127.0.0.1:6379> decr g
(integer) -1
127.0.0.1:6379> decr g
(integer) -2
如果這個鍵不存在,那就從0開始遞減,回傳結果是-1
incrby key 數字 (自增指定數字)
例:
127.0.0.1:6379> incrby a 5
(integer) 6
127.0.0.1:6379> incrby a 5
(integer) 11
127.0.0.1:6379> incrby h 5
(integer) 5
127.0.0.1:6379> incrby h 5
(integer) 10
127.0.0.1:6379>
如果這個鍵不存在,從0開始增加
decrby key 數字 (自減指定個數字)
incrbyfloat key 小數 (帶小數點的數)
例:
127.0.0.1:6379> incrbyfloat h 1.5
“11.5”
127.0.0.1:6379> incrbyfloat h 1.5
“13”
127.0.0.1:6379> incrbyfloat h 1.5
“14.5”
沒有自減小數的命令
append key value 追加值:相當于在原在值后面再加上現在的值
例:
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> append hello friends
(integer) 12
127.0.0.1:6379> get hello
“worldfriends”
strlen key 回傳這個key他的值的字串長度
例:
127.0.0.1:6379> strlen hello
(integer) 12
設定key的新值,回傳原值
getset key value
例:
127.0.0.1:6379> strlen hello
(integer) 12
setrange key value的位置下標 value 把key的值的某一個位置上的字符改為value
例:
127.0.0.1:6379> get hello
“world”
127.0.0.1:6379> setrange hello 0 x
(integer) 5
127.0.0.1:6379> get hello
“xorld”
用 value 引數覆寫(overwrite)給定 key 所儲存的字串值,從偏移量 offset 開始,
不存在的 key 當作空白字串處理,
SETRANGE 命令會確保字串足夠長以便將 value 設定在指定的偏移量上,如果給定 key 原來儲存的字串長度比偏移量小(比如字串只有 5 個字符長,但你設定的 offset 是 10 ),那么原字符和偏移量之間的空白將用零位元組(zerobytes, “\x00” )來填充,
注意你能使用的最大偏移量是 2^29-1(536870911) ,因為 Redis 字串的大小被限制在 512 兆(megabytes)以內,如果你需要使用比這更大的空間,你可以使用多個 key ,
當生成一個很長的字串時,Redis 需要分配記憶體空間,該操作有時候可能會造成服務器阻塞(block),在2010年的Macbook Pro上,設定偏移量為 536870911(512MB 記憶體分配),耗費約 300 毫秒, 設定偏移量為 134217728(128MB 記憶體分配),耗費約 80 毫秒,設定偏移量 33554432(32MB 記憶體分配),耗費約 30 毫秒,設定偏移量為 8388608(8MB 記憶體分配),耗費約 8 毫秒, 注意若首次記憶體分配成功之后,再對同一個 key 呼叫 SETRANGE 操作,無須再重新記憶體,
哈希:
幾乎所有的編程語言都提供了哈希(hash)型別,他們的叫法可能是哈希、字典、關聯陣列等,
在redis中,哈希型別是指鍵值本身又是一種鍵值對結構,例如value=[field,vlue1 field2 value2…fieldN valueN]
哈希型別中的映射關系叫做field-value,這里的value是指field對應的值,不是鍵對應的值,
命令:
1.設定值
hset key field1 value1 fiels2 value2…
127.0.0.1:6379> hset redis a 1 b 2 c 3
(integer) 3
127.0.0.1:6379> hset redis d 4
(integer) 1
2.獲取值:
hget key filed
例:
127.0.0.1:6379> hget redis a
“1”
127.0.0.1:6379> hget redis c
“3”
127.0.0.1:6379> hget redis
(error) ERR wrong number of arguments for ‘hget’ command
127.0.0.1:6379> hget redis b
“2”
key后面必須跟field 并且只能跟1個field
3.洗掉值:
hdel key field1 field2…
127.0.0.1:6379> hdel redis a b c
(integer) 3
4.hlen key 計算key里面field的個數
127.0.0.1:6379> hlen redis
(integer) 1
5.批量設定和獲取field value
hmset
127.0.0.1:6379> hmset hello a 1 b 2 c 3
OK
127.0.0.1:6379> hmget hello a b c
- “1”
- “2”
- “3”
6.判斷key里面是否存在field
hexists key field 回傳1代表有,回傳0代表沒有
127.0.0.1:6379> hexists hello a
(integer) 1
127.0.0.1:6379> hexists hello b
(integer) 1
127.0.0.1:6379> hexists hello d
(integer) 0
7.獲取所有的field
hkeys key
例:
127.0.0.1:6379> hkeys hello
- “a”
- “b”
- “c”
8.獲取所有的值
hvals key
例:
127.0.0.1:6379> hvals hello
- “1”
- “2”
- “3”
9.hgetall key 獲取key里面每組field和value
127.0.0.1:6379> hgetall hello - “a”
- “1”
- “b”
- “2”
- “c”
- “3”
10.hincrby key field 數字 使key里面field的值自增的指定的數字
127.0.0.1:6379> hincrby hello a 4
(integer) 5
127.0.0.1:6379> hget hello a
“5”
11.計算value的字串長度:
hstrlen key field
127.0.0.1:6379> hstrlen hello a
(integer) 1
list串列:
串列型別是用來存盤多個有序的字串,比如a,b,c,e五個元素從左到右組成了一個有序的串列,串列中的每個字串稱為元素,一個串列最多可以存盤2^32-1個元素,在redis中,可以對串列兩端進行插(push)和洗掉(pop),還可以獲取指定范圍的元素串列、獲取指定索引下標的元素等,串列是一種比較靈活的資料結構,
串列型別有兩個特點:第一、列獲取表中的元素是有序的,這就意味著可以通過索引下標某個元素或者某個范圍內的元素串列;第二、串列中的元素可以是重復的,
命令:
1.lpush 在串列的最左端添加元素,rpush 在串列的最右端添加元素,
linsert 在已有串列某個元素的前面或后面添加新的元素,
lpush key value1 value2…
rpush key value1 value2…
linsert key before | after pivot value
例:
127.0.0.1:6379> lpush list a b c
(integer) 3
127.0.0.1:6379> rpush list2 a b c
(integer) 3
127.0.0.1:6379> lrange list 0 -1
- “c”
- “b”
- “a”
127.0.0.1:6379> lrange list2 0 -1 - “a”
- “b”
- “c”
127.0.0.1:6379> linsert list2 before b d
(integer) 4
127.0.0.1:6379> linsert list2 after c e
(integer) 5
127.0.0.1:6379> lrange list2 0 -1 - “a”
- “d”
- “b”
- “c”
- “e”
2.查看串列
(1)lrange key start end 查看指定范圍的串列元素
127.0.0.1:6379> lrange list2 1 3
- “d”
- “b”
- “c”
(2)lindex key index 查看指定索引下標的元素
(3)llen key 獲取串列的長度
3.洗掉:
lpop 從左邊洗掉1個元素
rpop 從右邊洗掉1個元素
lrem key count(數字) value
count>0 從左往右刪,洗掉count范圍內的這個value,如果范圍內沒有這個value,則不刪;
count<0 從右往左刪,洗掉count范圍內的這個value,如果范圍內沒有這個value,則不刪;
count=0 洗掉串列中所有和value相等的元素;
例:
127.0.0.1:6379> lrange list2 0 -1
- “b”
- “a”
- “b”
- “c”
- “d”
- “c”
- “b”
- “e”
- “d”
- “f”
- “a”
- “b”
- “c”
- “d”
- “a”
- “b”
- “c”
127.0.0.1:6379> lrem list2 1 a
(integer) 1
127.0.0.1:6379> lrange list2 0 -1 - “b”
- “b”
- “c”
- “d”
- “c”
- “b”
- “e”
- “d”
- “f”
- “a”
- “b”
- “c”
- “d”
- “a”
- “b”
- “c”
127.0.0.1:6379> lrem list2 -1 a
(integer) 1
127.0.0.1:6379> lrange list2 0 -1 - “b”
- “b”
- “c”
- “d”
- “c”
- “b”
- “e”
- “d”
- “f”
- “a”
- “b”
- “c”
- “d”
- “b”
- “c”
127.0.0.1:6379> lrem list2 0 b
(integer) 5
127.0.0.1:6379> lrange list2 0 -1 - “c”
- “d”
- “c”
- “e”
- “d”
- “f”
- “a”
- “c”
- “d”
- “c”
4.lset key index newvalue 修改指定下標的元素為newvalue
例:
127.0.0.1:6379> lset list2 2 java
OK
127.0.0.1:6379> lrange list2 0 -1
- “c”
- “d”
- “java”
- “e”
- “d”
- “f”
- “a”
- “c”
- “d”
- “c”
5.阻塞操作 blpop brpop 并發太大的時候,用阻塞的方法緩解服務器的壓力,
blpop key1 key2… timeout 從第一個串列的最左邊開始,彈出一個元素,回傳串列名稱和被洗掉的元素,如果所有串列中都沒有元素了,那就會阻塞timeout秒,然后回傳’nil’ 和阻塞的時間;
blpop key1 key2… timeout 從第一個串列的最右邊開始,彈出一個元素,回傳串列名稱和被洗掉的元素,如果所有串列中都沒有元素了,那就會阻塞timeout秒,然后回傳’nil’ 和阻塞的時間;
127.0.0.1:6379> rpush list a b c d
(integer) 4
127.0.0.1:6379> brpop list list2 3
- “list”
- “d”
127.0.0.1:6379> brpop list 3
(nil)
(3.08s)
6.集合:(set)型別也是用來保存多個字串元素,但和串列型別不同的是,集合中不允許有重復的元素,并且集合中的元素是無序的,不能通過索引下標獲取元素,一個集合最多可以存盤2^32-1個元素,redis處理支持集合內的增刪改查,同時還支持多個集合取交集、并集、差集,
a=[0,2,3] b=[2,3,4,5,6,7,8]
命令:
1.往集合里添加元素:sadd key value1 value2… 注意:添加重復的元素只能添加進去一個;
127.0.0.1:6379> sadd set1 a b c d
(integer) 4
127.0.0.1:6379> sadd set1 e e
(integer) 1
127.0.0.1:6379> sadd set1 a b
(integer) 0
2.洗掉元素:srem key value
127.0.0.1:6379>srem set1 a
(integer) 1
3.顯示集合中元素的個數:scard key
127.0.0.1:6379>scard set1
(intrger)4
4.判斷元素是否在這個集合中:
sismember key value 回傳1,表示有這個元素,回傳0表示沒有,
5.隨機從集合中回傳指定個數的元素:
srandmember key [count] 不寫count就回傳1
6.從集合中隨機洗掉元素:
spop key [count] 不寫count默認是1
7.查看集合內所有元素:
smember key
集合間的操作:
1.求多個集合的交集:
sinter key1 key2…
例:
127.0.0.1:6379> sadd set 1 2 3 4 5 6
(integer) 6
127.0.0.1:6379> sadd set1 1 3 5 6 8 9 10
(integer) 7
127.0.0.1:6379> sinter set set1
- “1”
- “3”
- “5”
- “6”
2.求多個集合的并集:sunion key1 key2…
例:
127.0.0.1:6379> sunion set set1
- “1”
- “2”
- “3”
- “4”
- “5”
- “6”
- “8”
- “9”
- “10”
2.求多個集合的差集:sdiff key1 key2
例:
127.0.0.1:6379> sdiff set set1
- “2”
- “4”
將多個集合中的交集、并集、差集作為集合保存到redis當中:
sinterstore destination key1 key2…
sunionstore destination key1 key2…
sdiffdtore
5.有序集合:
有序集合相對于哈希、串列、集合來說算是比較陌生的一種資料結構,但是他和我們這些熟悉的資料型別有很多聯系,它保留了集合不能有重復值的特性,但不同的是,有序集合里邊的元素是可以排序,他和串列使用下標的方式排序不同,它給每個元素設定了一個分數(score)作為排序依據,合理的利用有序集合,能幫助我們在實際開發中解決很多問題,
命令:
1.添加成員:zadd key 【NX|XX】[CH] [INCR] score member [score member…]
NX:必須不存在才可以設定,用于添加;
XX:必須存在才可以設定,用于更新;
INCR:對分數做增加,zincrby 可以自定義增加的分數;
CH:此次操作完成后,有序集合元素和分數變化的個數;
2.計算成員的個數:zcard key
3.求成員的分數:
zscore key member
4.求成員的排名(根據分數):
(1)zrank key member 按照分數由低到高排
(2)zrevrank key member 按照分數由高到低排(回傳位置資訊是從0開始的);
127.0.0.1:6379> zrank zset1 c
(integer) 2
127.0.0.1:6379> zrank zset1 a
(integer) 0
5.洗掉成員:
zrem key member1 member2…
6.增加某個成員的分數:
zincrby key increment member 若次成員不存在,則會添加此成員并且它的分數就是
increment
127.0.0.1:6379> zincrby zset1 3 a
“4”
127.0.0.1:6379> zscore zset1 a
“4”
127.0.0.1:6379> zincrby zset1 5 e
“5”
127.0.0.1:6379> zscore zset1 e
“5”
7.指定排名范圍的成員:
zrange key start end [withscores] 由低到高
zrevrange key start end [withscores] 由高到低
127.0.0.1:6379> zrange zset1 0 3 withscores
- “b”
- “2”
- “c”
- “3”
- “a”
- “4”
- “d”
- “4”
127.0.0.1:6379> zrevrange zset1 1 3 withscores
- “d”
- “4”
- “a”
- “4”
- “c”
- “3”
127.0.0.1:6379> zrevrange zset1 1 3 - “d”
- “a”
- “c”
8.指定分數范圍內的成員排名:
zrangebyscore key minscore maxscore [withscores] [limit offset count] 由低到高
zrevrangebyscore key minscore maxscore [withscores] [limit offset count] 由低到高
[limit offset count] 限制輸出的起始位置和個數
127.0.0.1:6379> zrangebyscore zset1 1 10 withscores
- “b”
- “2”
- “c”
- “3”
- “a”
- “4”
- “d”
- “4”
- “e”
- “5”
127.0.0.1:6379> zrevrangebyscore zset1 3 1 withscores - “c”
- “3”
- “b”
- “2”
minscore 和 maxscore 可以選擇-inf(無限小)+inf(無限大)
127.0.0.1:6379> zrangebyscore zset1 200 +inf withscores
- “g”
- “201”
- “f”
- “290”
127.0.0.1:6379> zrevrangebyscore zset1 300 -inf withscores - “f”
- “290”
- “g”
- “201”
- “e”
- “5”
- “d”
- “4”
- “a”
- “4”
- “c”
- “3”
- “b”
- “2”
8.求指定分數范圍的成員個數:zcount key min max
9.洗掉指定排名內的升序元素
zrem range by rank ey start end
127.0.0.1:6379> zremrangebyrank zset1 0 2
(integer) 3
10.洗掉指定分數范圍的成員:
zremrangebyscore key min max
127.0.0.1:6379> zremrangebyscore zset1 1 5
(integer) 2
有序集合間的操作:
1.交集:zinterstore destination numkeys key1 key2…[weights weight] [aggregate sum|min|max]
destination :交集結果要保存的集合名稱;
numkeys:用來求交集的集合個數;
weights:權重,后面的weight是權重的數字,可以是多個,根據key的數量定,默認是1;
aggregate:交集取出元素的分數可以按照sum|main|max這三種方式進行計算取值;
zinterstore user 2 user1 user2 weights 1 0.5
并集:zunionstore destination numkeys key1 key2…[weights weight] [aggregate sum|min|max]
第三章 鍵管理與redis的一些小功能
前面學過了type、del、object encoding 、exists、expire等
1.鍵的重命名:rename key newkey
127.0.0.1:6379> set python study
OK
127.0.0.1:6379> rename python java
OK
2.隨即回傳一個鍵:randomkey
127.0.0.1:6379> randomkey
“user”
3.查看有多少個鍵:dbsize
127.0.0.1:6379> dbsize
(integer) 16
4.鍵過期:expire 以秒為單位,expireat 后面跟時間戳(1970年1月1日0時0分0秒)
127.0.0.1:6379> expireat user 1469980800
(integer) 1
鍵過期后面可以不跟時間和時間戳,而是跟ttl值來給鍵設定鍵過期
ttl值: >0 -1 -2
0的整數表示:鍵過期的時間還剩多少秒;
-1表示:鍵沒有設定過期時間;
-2表示:鍵不存在;
127.0.0.1:6379> EXPIRE user -2
(integer) 0
127.0.0.1:6379> get user
(nil)
- 遷移鍵:
(1)move :同一個redis的不同的庫之間遷移; redis的庫的索引 :0-15
move key dbindex(庫的索引)
怎么讓redis顯示庫的index:
127.0.0.1:6379> set dbnumber 0
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> get dbnumber
“0”
select index 這個命令用來切換庫;
127.0.0.1:6379> keys *
- “set1”
- “set3”
- “str”
- “user1_2”
- “java”
- “set2”
- “user1”
- “list2”
- “user2”
- “str1”
- “list”
- “zset1”
- “set”
- “str2”
- “set4”
- “dbnumber”
127.0.0.1:6379> move set 15
(integer) 1
127.0.0.1:6379> keys * - “set1”
- “set3”
- “str”
- “user1_2”
- “java”
- “set2”
- “user1”
- “list2”
- “user2”
- “str1”
- “list”
- “zset1”
- “str2”
- “set4”
- “dbnumber”
127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> keys * - “set”
(2)【dump+restore】:
命令:
dump key 這個在源redis上
restore key ttl value [replace] 跟上replace表示如果目標redis上有同名key就覆寫掉
dump key 和restore key ttl value 用于多個redis之間進行資料遷移;
分2步:1.在源redis上,dump key 來使key序列化備份,格式rdb
2. 在目標redis上,restore key ttl value(這個value就是序列化后的值),ttl是過期時間,
ttl=0的時候表示永遠不過期;
127.0.0.1:6379[15]> set str1 abcdefg
OK
127.0.0.1:6379[15]> dump str1
“\x00\aabcdefg\b\x00\x7f\x13\xfc\x0f\x194yf”
127.0.0.1:6380[15]> restore str1 0 “\x00\aabcdefg\b\x00\x7f\x13\xfc\x0f\x194yf”
OK
127.0.0.1:6380[15]> keys *
- “str1”
127.0.0.1:6380[15]> get str1
“abcdefg”
(3)【migrate】 多個redis之間的key遷移, redis 3.0.6版本后才有的,
migrate相當于dump+restore+del
migrate host port key|"" destination-db timeout [copy|replace] [keys key]
host: 這里輸入目標redis的IP
port:輸入目標redis的埠
key|"" :指我們要遷移的鍵,如果要遷移的鍵多于1個時,我們這個位置寫"",然后把這些鍵放在
后面的引數keys后面;
destination-db :目標redis的庫的索引下標;
timeout:超時時間,單位是毫秒;
copy:表示移動key但不洗掉源redis上的這個key
replace:跟上replace表示如果目標redis上有同名key就覆寫掉
keys : 當我們要遷移多個鍵的時候,把這些鍵的其他鍵寫在keys后邊
127.0.0.1:6379[15]> migrate 127.0.0.1 6380 str1 1 10000
OK
127.0.0.1:6380[15]> select 1
OK
127.0.0.1:6380[1]> keys *
- “str1”
127.0.0.1:6380[1]> get str1
“abcdefg”
127.0.0.1:6379> migrate 127.0.0.1 6380 “” 1 10000 keys list2 user1
OK
127.0.0.1:6380[1]> keys *
- “str1”
- “list2”
- “user1”
127.0.0.1:6380[1]> keys *
- “str1”
- “list2”
- “user1”
127.0.0.1:6380[1]> migrate 127.0.0.1 6379 list2 1 10000 copy
OK
127.0.0.1:6380[1]> keys * - “str1”
- “list2”
- “user1”
歷鍵遍
1.keys pattern
pattern:* 匹配任意字符;? 匹配1個字符;[]匹配方括號當中任意字符,比如[1,3]代表1,3 [1-9]匹配1到9任意數字;\x用來轉義特殊字符; st\x*1
有3種情況用到keys:
1.不對外提供服務的redis節點;
2.確認鍵值總數數量較少,可以用keys;
用scan可以防止阻塞:
scan:漸進式的遍歷,從2.8版本才有,相當于1個keys*=多個scan
scan cursor [match pattern] [count number]
cursor:游標,第一次遍歷一般從0開始,每次scan遍歷完了都會回傳當前的游標的值,然后我們再從這個游標開始遍歷,知道游標值為在為0,就遍歷了所有的鍵;
[match pattern]:可選項,作用是做模式的匹配;
[count number]:作用是表名每次要變遍歷的個數;
scan的缺點:不能保證完整的遍歷所有鍵;
關于資料庫的操作:
1.select dbindex 切換庫
2.dbsize:查看庫里面有多少個鍵
3.flushdb|fludhall:這個命令是清除當前庫里的所有鍵,flushall這個是清楚所有庫里的鍵
1.慢查詢分析:
所謂慢查詢日志就是系統在命令執行前后計算每條命令的執行時間,當超過預設的閾值,就將這條命令的相關資訊(例如:發生時間,耗時,命令的詳細資訊)記錄下來;
redis的慢查詢,在組態檔當中有兩個配置引數:
slowlog-log-slower-then:這個預設的閾值(單位:微妙,1秒=1000毫秒=1000000微秒)
閾值=0,記錄所有命令;閾值<0,什么都不記錄;
slowlog-max-len:慢查詢日志最多存盤多少條;
若慢查詢日志存滿了,在有日志記錄時,則洗掉最早一條,一次按此執行;
慢查詢命令:
(1)slowlog get [N] N是可選項,表示我們要獲取慢查詢日志的條數;
如果不為空,回傳的內容應該包含以下內容:
1)慢查詢命令的時間戳;
2)
3)
4)
5)
3.4 Redis Shell
【Redis-cli詳解】
【-r】:代表將命令執行多次
[root@localhost redis-4.0.2]# redis-cli -r 3 ping
PONG
PONG
PONG
【-i】:代表每隔幾秒執行一次命令,但是-i 必須和-r 一起使用
[root@localhost redis-4.0.2]# redis-cli -r 5 -i 1 ping
PONG
PONG
PONG
PONG
PONG
【-x】:從標準輸入(stdin)讀取資料作為redis-cli的最后引數
將world作為鍵hello的值
[root@localhost redis-4.0.2]# echo “world” | redis-cli -x set hello
OK
【-c】:該選項是連接redis cluster節點時需要使用的,-c選項可以防止moved和ask例外
【-a】:不需要手動輸入auth命令
【–scan】用于掃描指定模式的鍵
【–slave】把當前的客戶端模擬當成redis節點的從節點,來獲取redis節點的更新
【–pipe】用于執行流水線,將命令封裝成redis通信協議定義的資料格式,批量發送給redis執行
【–rdb】用于拍快照(aof把快照保存在磁盤),備份,請求redis實體生成并發送RDB持久化檔案,保存在本地
【–eval】執行指定的lua腳本(與魔獸世界腳本相同)
【–latency】查詢延遲,包含以下3點
【–latency】 該選項可以測驗客戶端到目標redis的網路延遲,結果只有一條
【–latency-history】分時段的形式了解延遲資訊
【–latency-dist】 使用統計圖形式從控制臺輸出延遲統計資訊
【–stat】選項可以實時獲取redis的重要統計資訊(info不是實時的)
[root@localhost redis-4.0.2]# redis-cli --stat
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
11 829.17K 2 0 136 (+0) 6
11 829.17K 2 0 137 (+1) 6
11 829.17K 2 0 138 (+1) 6
11 829.17K 2 0 139 (+1) 6
杜興宇 15:08:31
【redis-server詳解】
【–test-memory 1024】是否有記憶體問題造成的記憶體崩潰,可以用來檢測當前作業系統是否穩定的分配指定容量的記憶體給redis
[root@localhost src]# redis-server --test-memory 1024
【redis-benchmark】可以為redis做基準性能測驗,為開發和運維提供方便,做測驗使
【-c】代表客戶端的并發量(默認50)
【-n 】-n后面跟數量,代表客戶端請求總量(默認為100 000)
【-q】僅僅顯示requests per second(請求數量,秒,等資訊)資訊
【-r】在一個空的redis上執行redis-benhmark,并向redis里面插入更多隨機鍵
【-p】每個請求pipe流水線的資料量(默認為1)
【-k】代表客戶端是否使用keepalive,1為使用,0為沒使用,默認是1
事務:為了保證多條命令組合的原子性,redis提供了簡單的事務功能以及集成腳本來解決這個問題,
簡單的說,事務表示一組動作,要么全部不執行,比如在社交網站上用戶A關注用戶B,那么需要在用戶A的關注表中加入用戶B,并且在用戶B的粉絲中加入用戶A,這兩個行為要么全部執行,要么全部不執行,否則會出現資料不一致的情況,
redis事務:將一組需要一起執行的命令放到multi和exec這兩個命令之間,multi命令代表事務開始exec代表事務結束;
第四章 redis的持久化
redis支持RDB和AOF兩種持久化,持久化功能有效的避免了因為行程退出造成的資料丟失問題,
當下次重啟時利用之前持久化的檔案即可實作資料恢復,
理解持久化機制對于redis運維非常重要,
首先我們學習RDB、AFO的配置和運行流程,以及控制持久化的相關命令,如bgsave和bgrewriteaof;其次對于常見持久化問題進行分析和優化,
1.RDB
RDB持久化是把當前行程資料生成快照保存到硬碟的程序,觸發RDB持久化程序分為:手動觸發和自動觸發,
1.1 RDB觸發機制:
手動觸發分別對應save和bgsave命令:
手動:save和bgsave
save:阻塞當前redis服務器,直到RDB程序完成(線上不建議使用,阻塞時間長);
bgsave:redis行程執行fork操作創建子行程,RDB持久化程序由子行程負責,完成后自動退出;
(阻塞只發生在fork間段)
自動:save m n
1.表示m秒內的資料集存在n次修改時會自動觸發bgsave;
2.如果從節點執行全量復制操作,主節點自動執行bgsave,形成RDB的檔案發給其他節點;
3.執行debug reload命令重新加載redis時,也會自動觸發save操作;
4.執行shutdown時,如果AOF持久化沒有開啟,則自動執行bgsave,
save命令:阻塞當前redis服務器,知道RDB程序完成,對于記憶體比較大的實體會造成長時間阻塞
線上環境不建議使用,運行save命令對應的redis的日志如下:
*DB saved on disk
bgsave命令:redis行程執行fork操作創建子行程,RDB持久化程序由子行程負責,完成后自動結束,阻塞只發生在fork階段,一般時間很短,
運行bgsave命令對應的redis日志如下:
*background saving started by pid 3151
*DB saved on disk
*RDB:0MB of memory used by copy-on-write
*background saving terminated with success
1.2 流程說明:
1)執行bgsave命令,redis父行程判斷當前是否存在正在執行的子行程,如:RDB/AOF子行程,
如果存在bgsave命令直接 回傳,
2)父行程執行fork操作創建行程,fork操作程序中父行程會阻塞,通過info stats命令查看latest_fork_usec選項,可以獲取最近一個fork操作的耗時,單位為微秒,
3)父行程完成fork后,bgsave命令回傳’‘background saving started’’ 資訊并不在阻塞父行程可以繼續回應其他命令;
4)子行程創建RDB檔案,根據父行程記憶體生成臨時快照檔案,完成后對原有檔案及進行原子替換,
執行lastsave命令可以獲取最后一次生成RDB的時間,對應info統計的rdb_last_save_time選項,
5)行程發送信號給父行程表示完成,父行程更新系統資訊,具體在info persistence 下的rdb_*相關選項,
1.3 RDB檔案的處理
RDB檔案的保存:3種方式
1.組態檔默認的保存路徑
2.在redis命令列 config set dbfilename ;
3.修改組態檔redis.conf:
dbfilename
dir ./
壓縮:LZF默認開啟:我們可以通過修改組態檔里的rdbcompression yes/no
或者執行命令config set rdbcompression [yes/no] yes是開啟壓縮, no是禁用;
1.5校驗:redis-check-dump 工具對rdb可以進行檢測;/user/local/redis-4.06/src下
1.6 RDB的優缺點::
優點:
(1)RDB是一個緊湊壓縮的二進制檔案,代表redis在某個時間點上的資料快照,非常適用于備份
全量復制等場景,比如每6小時執行bgsave備份,并把RDB檔案拷貝到遠程機器或者檔案系統中(如hdfs),
用于災難恢復,
(2)redis加載RDB恢復資料遠遠快于AOF的方式,
缺點:
(1) RDB方式資料沒辦法做到實時持久化/秒級持久化,因為bgsave每次運行都要執行fork操作創建
子行程,屬于重量級操作,頻繁執行成本過高,
(2)RDB檔案使用特定二進制格式保存、redis版本演程序序中有多個格式的RDB版本,存在老版本redis服務無法
兼容新版redis格式的問題,
針對RDB不適合實時持久化的問題,redis提供了AOF持久化方式來解決,
2.AOF
開啟AOF功能需要設定配置:appendonly yes,默認不開啟,AOF檔案名appendfilenname
配置設定,默認檔案名是appendonly.aof,保存路徑和RDB持久化一直,通過dir配置指定,
AFO的過流程操作:命令寫入(append)、檔案同步(sync)、檔案重寫(rewrite)、重啟加載(load),
命令:
寫入:append 將執行的redis命令寫入aof快取
aof緩沖:sync 將所有寫入快取的命令同步到磁盤
重寫:rewrite 起到壓縮日志檔案的目的,整理磁盤空間;
重啟:load 重啟時執行AOF檔案對資料進行加載;
3.自動持久化策略:
redis提供了多種AOF緩沖同步策略,由引數appendfsync控制,不同值得含義;
always、everysec、no
always:命令寫入aof_buf快取區后面呼叫系統fsync操作同步到AOF檔案,fsync完成后執行緒回傳(一般線上不采用always),
everysec: 命令寫入aof_buf快取區呼叫write操作,write完成后執行緒回傳,fsync同步檔案操作由
專門的執行緒每秒呼叫一次(一般建議選擇這個策略,資料性能安全的平衡);
no:命令寫入aof_buf后呼叫write操作,不對AOF檔案做fsync同步,同步硬碟操作由系統負責,
同步通常周期最長30秒(對線上不采用)
注意:
fsync針對單個檔案操作,做硬碟同步,fsync將阻塞直到寫入硬碟完成后回傳,保證資料持久化,
write:觸發延遲寫機制,write操作在寫入系統快取區之后直接回傳,同步硬碟操作依賴于系統呼叫機制
,比如:快取區頁寫滿或達到特定時間周期,同步檔案之前,如果時間系統故障宕機,快取區內資料將丟失,
4.重寫機制(rewrite):
隨著命令不斷寫入AOF檔案,檔案會越來越大,為了解決這個問題,redis引入AOF重寫機制壓縮
檔案體積,AOF檔案重寫是把redis行程內的資料轉換為命令同步到新AOF檔案的程序,
重寫后的AOF檔案為什么可以變小?
(1)行程內已經超時的資料不再寫入檔案,
(2)舊的AOF檔案含由無效命令,如del key srem keys set a 111 set 222等,這些無效命令就不寫入AOF檔案里了,
(3)多條寫命令可以合并,如:lpush list a、lpush list b、lpush list c可以轉化為lpush list abc,
AOF重寫降低了檔案占用空間,除此之外,另一個目的是:更小的AOF檔案可以更快的被redis加載,
AOF重寫程序可以手動觸發,也可以自動觸發:
手動觸發:直接條用bgrewiteao命令,
自動觸發:根據auto-aof-rewrite-percentage 引數確定觸發器時機,auto-aof-rewrite-min-size
表示運行AOF重寫時檔案最小體積,默認64MB
auto-aof-rewrite-percentage:代表AOF檔案空間(aof_current_size)和上一次重寫后AOF檔案空間的比值;
問題的定位余2優化:
1.
1.fork操作:
當redis做RDB或AOF
重寫時,一個必不可少的操作就是fork子行程,對于大多數作業系統來說fork是個重量級操作,
雖然fork創建子行程不需要拷貝父行程的物理記憶體空間,但是需要父行程的空間存串列,例如對于10G的redis行程,
需要復制大約20MB的記憶體串列,因此fork操作耗時跟行程的記憶體量息息相關,如果使用虛擬化技術、特別是Xen虛擬機,fork操作更耗時,
fork耗時問題定位:對于高流量的redis實體OPS可達到5萬以上,如果fork操作耗時在秒級別將拖慢redis幾萬條命令執行,對線上應用延遲影響非常明顯,
正常情況下fork耗時應該是每GB消耗2毫秒左右
可以在info stats統計中查看latest_fork_user指定獲取最近一次forl操作耗時,單位毫秒,
如何改善fork操作耗時:
(1)優先使用物理機或者高效支持fork操作的虛擬技術,避免使用Xen,
(2)控制redis實力最大可用記憶體,fork耗時跟記憶體成正比,線上建議每個redis實體控制在10G以內,
(3)合理配置linux記憶體分配策略,避免物理記憶體不足導致fork失敗,
(4)降低fork操作的頻率,如濕度放寬AOF自動觸發時機,避免不必要的全量復制,
2.子行程開銷監控和優化:
子行程負責RDB或者AOF檔案的重寫,他的運行程序主要涉及到cpu、記憶體、硬碟三部分的消耗,
(1)cpu開銷分析,子行程負責把行程內的資料 分批寫入檔案,這個程序屬于cpu密集操作,
通常子行程對單核cpu利用率接近90%,
cpu消耗的優化:redis是cpu密集型服務,不要做系結單核cpu操作,
子行程會和父行程產生單核資源競爭,不要和其他cpu密集服務部署在一起,造成cpu過度競爭,
如果多個redis實體,盡量保證同一時刻只有一個子行程執行重寫作業,
2.記憶體消耗分析:
子行程通過fork產生,占用記憶體大小等同于父行程,理論上需要兩倍記憶體來完成持久化操作,
但是linux系統有寫時復制機制(copy-on-write),父子行程會共享相同的記憶體頁,當父行程處理寫請求時會把要修改的記憶體頁創建副本,而子行程fork操作程序中共享整個
父行程記憶體頁快照,
3.硬碟的開銷分析:
子行程主要職責就是把AOF或者RDB檔案寫入硬碟持久性,勢必造成硬碟寫入壓力,
根據redis重寫AOF/RDB的數量,結合系統工具如sar、iostat、iotop等,
可分析重重寫期間負載情況,
硬碟開銷優化:
(1)不要和其他高硬碟的服務部署到一起,
(2)AOF重寫時會消耗大量硬碟IO,可以開啟配置no-appendfsync-no-rewrite,默認關閉,表示在AOF重寫期間不做fsync操作/
(3)當開啟AOF功能的redis用于高流量寫入場景時,如果使用普通機械硬碟,寫入吐量一般在100MB/s左右,這是redis實體的瓶頸
主要在AOF同步硬碟上,
(4)對于單機配置多個redis實體情況,可以配置不同實體分盤寫入壓力,
第五章 redis的復制
為了解決redis單節點的問題,為了保證資料的安全性,通常會把資料復制多個副本部署到其他服務器上,滿足故障恢復和負載均衡的需求,
redis我們提供復制功能,它的復制方式主要有兩種:1,主從復制 2.從從復制,
1.建立配置:
參與復制的redis實體劃分主節點(master)和從節點(slave),默認情況下,redis都是主節點,每一個從節點他只能有一個主節點,
而主節點可以同時具有多個從節點,復制的資料流是單向的,
配置復制的方式有以下三種:
(1)在從節點的組態檔中加入:slaveof(master) (masterport)隨著redis啟動生效
(2)在redis-server啟動命令后加上–slaveof (master) (masterport)生效;
(3)在redis命令列直接執行命令:slaveof (master) (masterport)生效;
我們可以通過命令:info replication 可以在主節點或者從節點上查看主從資訊
2.斷開主從復制:
slaveof命令不但可以建立復制,還可以在從節點上執行saveof no one斷開與主節點復制關系,
斷開復制主要流程:
(1)斷開主節點復制關系;
(2)從節點晉升為主節點;
從節點斷開復制后并不會拋棄原有資料,只是無法在獲取
主節點上的資料變化,
通過slaveof命令還可以切主,切主就是把當前從節點的復制,切換到另一臺主節點上的復制,命令:
slaveof 新主節點的ip 新節點的port 即可完成切主,
3設定.主從復制的安全配置:
對于資料比較重要的節點,主節點會通過requirepass引數進行密碼驗證,這時所有的客戶端訪問
必須用auth命令實行校驗,從節點與主節點的復制鏈接是通過一個特殊標識的客戶端來完成的,
因此需要配置從節點的requirepass引數與主節點密碼一致,這從節點才可以正確的
4.只讀
默認情況下,從節點使用siave-read-only=yes配置為只讀,由于復制只能從主節點到從節點,對于從節點
的任何修改主節點無法感知,修改從節點會造成主從資料不一致,因此建議線上不要修改從節點
的只讀模式,
5.傳輸延遲:
主從節點一般部署在不同機器上,復制時的網路延遲就成為需要考慮的問題,redis為我們提供了repl-disable-tcp-nodelay引數用于控制是否
關閉TCP_NODELAY,默認
關閉,說明如下:
(1)當關閉時,主節點產生 的命令資料無論大小都會及時地發送給從節點,這樣主從節點之間延遲會變小,但增加了網路帶寬的消耗,適用于主從之間的網路環境良好的場景,比如在同一個機房內的服務器,
(2)當開啟時,主節點會合并較小的TCP資料包從而節省帶寬,默認發送時間間隔取決于linux的內核,一般默認40毫秒,這種配置節省了帶寬增大了主從之間的延遲,適合于主從網路環境復雜或帶寬警長的場景,如機房部署,
6.主從拓撲:
1.主從,2.樹狀主從結構;
7.復制程序的原理:
(1)slave向master發送sync命令
(2)master開啟了行程來將dataset寫入rdb檔案,同時將子行程完成之前接收到的命令快取起來,
(3)子行程寫完,父行程得知,開始將RDB檔案發送給slave,
(4)master發送完RDB檔案,將快取的命令也發給slave,
(5)master增量的把命令發送給slave,
值得注意的是,當slave跟master的鏈接斷開時,slave可以自動的重新連接master,在redis2.8版本之前,每當slave行程掛掉重新連接master
7.心跳
朱從幾點在建立復制后,他們之間維護者連接并彼此發送心跳命令,主從心跳判斷機制:
(1)主從點彼此都有心跳檢測機制,各自模擬成對方的客戶端通信,通過client list命令查看復制相關的哭護資訊,主節點的連接狀態為flags:M,從節點的連接狀態為flags:S
(2)主節點默認每隔10秒發送給從節點ping命令,判斷從節點的存活和連接狀態,可以通過repl-ping-slave-period 10 設定多少秒發送ping命令;
(3)從節點在主執行緒中每個1秒發送replconf ack {offset}給主節點上報自身當前的復制偏移量,
replconf作用
(1)實時檢測主節點網路狀態;
(2)上報自身復制偏移量,檢測復制資料是否丟失,如果從節點資料丟失,在從主節點的積壓復制快取區里拉取丟失的資料;
(3)時間保證從節點的數量和延遲性功能,通過min-slaves-to-write、min-salves-max-lag引數定義,主節點根據repconf命令判斷從節點超時時間,體現在info replication統計中的lag資訊中lag表示與從節點最后一次通信延遲的秒數,正常延遲應該在0-1之間,如果超過了repl-timeout配置值(默認60秒),則判定從節點下線并且斷開復制客戶端連接,即使主節點判定從節點下線后如果從節點重新恢復,心跳檢測會繼續進行,
8.異步復制
主節點不斷負責資料的讀寫,還負責把命令同步給從節點,寫命令的發送程序時異步的,也就是說主節點自身處理完命令后直接回傳給客戶端,并不等從節點復制完成,
主節點復制的流程:
(1)主節點接受寫命令‘
(2)命令執行完之后回傳給客戶端執行結果;
(3)異步寫命令發送給從節點;
由于主從復制是異步的,就會造成從節點的資料相對于主節點在延遲,具體延遲多少位元組,我們可以在主節點上執行info replication命令相關指標:offset和master_repl_offset之間的差值就是延遲的位元組;
在統計資訊中可以看到從節點slave0資訊,分別記錄了從節點的ip、port、狀態、offset表示當前從節點的復制偏移量,master_repl_offset表示當前主節點復制偏移量,兩者的差值就是延遲量,
redis的復制速度取決于主從之間的網路環境,repo-disable-tcp-nodelay,命令處理速度等,正常情況下,延遲在1秒以內,
9.開發與運維中的問題
理解了復制原理之后,我們來看一些容易出現問題的應用場景:
1.讀寫分離的問題:
master負責寫,slave負責遇到的問題:
(1)復制資料延遲;(2)讀到過期的資料;(3)從節點故障
1.復制資料延遲:
redis復制資料的延遲由于異步復制特性是無法避免的,延遲取決于網路帶寬和命令阻塞 情況,比如剛在主節點寫入資料后立刻在從節點上讀取可能獲取不到,需要業務場景允許短時間內的資料延遲對于無法容忍大量延遲的場景,可以撰寫外部監控程式監聽主從節點的復制偏移量,
當延遲較大時,觸發報警或者通知客戶端避免讀取過高的從節點,
監控程式:定期檢查主從節點的偏移量,主從節點偏移量的差值叫做主從節點延遲的位元組,當延遲過高時,監控程式觸發報警,并通知客戶端從節點延遲過高,客戶端接收到具體的從節點讀命令請求,
2.讀到過期資料的問題:
當主節點存盤大量設定超時間資料時,如快取資料,redis內部需要維護過期資料洗掉策略,
洗掉策略主要有兩種:
一種叫惰性洗掉,另一種叫做定時洗掉
惰性洗掉,主節點每次處理讀取命令時,都會檢查鍵是否超時,如果超時,則執行del洗掉鍵,del命令異步發送給從節點,從節點永遠不會主動洗掉超時的資料;
定時洗掉,redis主節點在內部時任務會回圈采樣一定數量的鍵,當發現采樣的鍵過期時執行del命令之后在同步給從節點,
如果此時資料大量超時,主節點采樣速度跟不上過期且主節點沒有讀取過期鍵的操作,那么從節點將無法收到del命令,這時在從節點上可以讀取到已經超時的資料,redis在3.2版本解決了這個問題,從節點讀取資料之前會鍵的過期時間決定是否回傳資料,可以升級到3.2版本來規避這個問題,
3.從節點故障問題:
對于從節點的故障問題,需要在哭護端維護,維護可用的節點串列,當從節點故障時,會立刻切換到其他的從節點或主節點上,由監控程式完成,
2.主從配置不一致:
主從配置不一致是一個容易忽視的問題,對于有些配置主從之間是可以不一致的,比如:主節點關閉AOF但是從節點開啟,但對于記憶體相關的配置必須一致,比如:maxmemory,
hash-max-ziplist-entries等引數,
當配置的maxmeory-policy策略進行記憶體溢位控制,此時從節點資料已經丟失,但主從復制流程依然正常進行,復制偏移量也正常,當增大了從節點的記憶體,要修復這類問題也只能手動進行全量復制,當壓縮串列相關引數不一致時,雖然主從節點存盤的資料一致,但是時間占用情況差異會比較大,
4.規避全量復制:
第一次建立連接的復制:由于是第一次建立復制,從節點不包含任何主節點資料,因此必須進行全量復制才能完成資料同步,對于這種情況全量制無法避免,當對資料量較大卻流量較高的主節點添加從節點時,建議在低峰進行操作,或者盡量規避使用大量的redis節點,
節點運行id不匹配:當主從復制關系建立后,從節點會保存主節點的運行id,如果此時主節點因故障重啟,那么他的運行id會變,從節點發現主節點的運行id不匹配時,會認為自己復制的是一個新主節點,從而進行全量復制,對于這種情況應該從架構上規避,比如提供故障轉移功能,當主節點發生故障后,手動提升一個從節點為主節點或采用支持自動故障轉移的哨兵或集群方案,
(3)復制積壓快取區不足:當主從節點連接中斷后,從節點在次連接上主節點時會發送psync(runid)(offset),命令請求增量復制,但是請求的offset不在主節點的積壓快取區內,則無法提供給從位元組點資料,因此增量復制會退化為全量復制,針對這種情況需要根據網路中斷時長,調整復制積壓快取的大小,
入資料量,調整復制積壓快取區的大小,
網路中斷一般有閃斷、機房割接、網路磁區等情況,這時網路中斷的時長一般在分鐘級,寫命令可以查看的差值來計算出網路中斷大約產生多少新寫入的資料來修改快取區大小,因而可以避免由于復制積壓快取區不足造成的全量復制,
5.單節點復制風暴:
單節點復制風暴一般發生在主節點掛載多個從節點的場景,當主節點重啟恢復后,從節點會發起全量復制流程,這時主節點創建RDB快照,如果在快照創建完畢之前,有多個從節點都嘗試與主節點進行全量同步,那么其他從節點將共享這份RDB快照,這點redis做了優化,有效避免了創建多個RDB快照,但是,,同時向多個從節點發送RDB快照,可能使主節點的網路帶寬消耗嚴重,造成主節點的延遲變大,極端情況會發生主從節點連接斷開,導致復制失敗,
解決方案:首先可以也減少主節點掛載從節點的數量,或者采用樹狀復制結構,加入中間層從節點用來保護主節點,從節點采用樹狀復制非常有用,網路開銷交給位于中間層的從節點,而不必消耗主節點的網路帶寬,但是這種樹狀結構帶來了運維的復雜性增加了手動和自動處理故障轉移的難度,
單機復制風暴
由于redis的單執行緒架構,通常單帶機器會部署多個redis實體,但一臺機器同時部署多個主節點,如果這臺機器出項故障或者網路長時間中斷
,當他重啟恢復后,會有大量從節點針對這臺機器的主節點進行全量復制,會造成當前機器網路帶寬耗盡,
如何避免?方法如下:
(1)應該盡量避免多臺主節點部署在同一臺服務器上,盡量分散部署,
(2)當主節點所在機器
redis的哨兵(sentinel):
redis的主從復制模式下,一旦主節點由于故障不能提供服務,需要人工將從節點晉升為主節點,
同時要通知應用方更新新節點地址,對于很多場景故障處理的方式是無法接受的,可服務,喜的是2.8版本開始提供了redis sentinel(哨兵)架構來解決這個問題,
1.redis主從復制問題:
redis主從復制模式可以將主節點的資料改變同步給從節點,這樣呢從節點就可以起到2個作用:
第一,作為主節點的一個備份,一旦主節點出了故障從節點 可以作為后備’‘頂上來’'提供服務,并且保證了資料的安全性;第二,從節點可以擴展主節點讀的能力,一旦主節點不能支撐大并發量的讀操作,從節點可以在一定程度上幫助主節點分擔讀的壓力,
但是主從復制也帶了以下問題:
(1)一旦主節點出現故障,需要手動將一個從節點晉升為主節點,同時需要修改應用方的主節點地址,還需要 命令其他從節點去復制新的主節點,整個程序需要人為操作,同時耗時較長,
(2)主節點的寫能力受到單機的限制,
(3)主節點的存盤能力受到單機的限制,
哨兵主要解決第一個問題,
高可用
redis主從復制模式下,一旦主出現故障,需要人工故障轉移,無論對redis的應用還是運維方都帶來很大的不便,對于應用方來說無法及時感知到主節點的變化,必然會造成一定的寫資料丟失和讀資料的錯誤,甚至可能造成應用方服務不可用,對于redis的運維來說,整個故障轉移的程序是需要人工來介入的,故障轉移實時性和準確性都無法得到保障,
一個1主2從的redis主從復制模式下的主節點故障了,是如何進行故障轉移的?
(1)主節點發生故障后,客戶端連接到主節點失敗,兩個從節點與主節點的連接失敗造成復制中斷,
(2)如果主節點無法正常啟動,需要選出一個從節點(slave1),對其執行slave no one命令使其成為新的主節點,
(3)原來的從節點(slave1)成為新的主節點后,更新應用方的主節點資訊,從新啟動應用方,
(4)客戶端命令另外一個從節點(slave2)去復制新的主節點,
(5)待原來的主節點恢復后,讓他去復制新的主節點,
哨兵部署安裝:
在安裝目錄下有sentinel.conf這個哨兵的組態檔,我們修改這個組態檔部署sentinel:
sentinel monitor mastername masterip masterport quorum(這里填數字)
sentinel monitor mymaster 192.168.1.1 6379
這個選項指定了我們哨兵要監控的主節點,一個哨兵可以同時監控多個主節點(多個redis集群);
我我們只需要增加以上配置就可以了,
2.sentinel down-after-milliseconds mastername 30000(默認值)
這一項配置是指定主節點多少毫秒沒有回應就認為主節點下線了;
3.sentinel parallel-syncs mastername 1(默認值)
這一項是設定故障轉移后,同時可以有幾個從節點對主節點資料進行復制;
4.sentinel failover-timeout mastername 180000(默認)
這一項是故障轉移的超過了設定故障轉移失敗,下一次故障轉移的超時間會變成這個設定時間的兩倍;
failover-time 這個超時間主要體現現在4個階段:
(1)如果redis sentinel對一個主節點故障轉移失敗,那么下次在對該主節點做故障轉移的超時時間就會是failover-timeout的2倍;
(2)如果sentinel節點選出的從節點執行slaveof no one一直失敗(例如該從節點此時出現故障)當程序超過了failover-timeout,則故障轉移失敗;
(3)從節點晉升為主節點之后,sentinel節點還會發送info命令來確認主節點故障轉移成功,如果此程序執行時間超過了failover-timeout,則故障轉移失敗,
(4)從節點連接新的主節點超時,故障轉移失敗 ;這個failover-timeout不包含主從復制的程序;
4.sentinel auth-pass
如果我么要監控的主節點設定了密碼,那么我們就通過這一項來填寫主節點的名稱和密碼,以確保能夠監控到主節點;
5.sentinel notification-script
在故障轉移期間,當一些警告級的sentine時間發生(指重要事件,例如:-sdown:客觀下線、-odown:主管下線)時,會觸發對路徑的腳本,并向腳本發送相應的事件引數,
6.sentinel client-reconfig-script
他的作用是在故障轉移結束后,會觸發對應路徑的腳本,并向腳本發送故障結果的相關引數,
啟動sentinel節點的方法:
第一種:redis-server redis-sentinel.conf
第二種:redis-server redis-sentinel.conf -sentinel
登錄sentinel節點客戶端命令:redis-cli -p 26379(默認)
sentinel節點不是資料點,所以它支持的命令不多,主要有以下常用:
1.sentinel master 展示所有被監視的主節點狀態以及相關的資訊;
2.sentinel slaves
展示所有指定的master的從節點的狀態及相關的統計資訊:
3.sentinel master
展示指定的主節點的詳細資訊;
4.sentinel sentinel
展示指定的主節點的哨兵的相關資訊;
5.sentinel get-master-addr-by-name
回傳指定master的ip地址和埠;
6.sentinel reset
當前sentinel節點對符合(通配符風格)的主節點的配置進行重置,包括清除主節點的相關狀態(例如故障轉移),從新發現從節點和sentinel節點,
對指定的master強制故障轉移(沒有和其他sentinel節點協商),當故障轉移完成后,其他的sentinel節點按照故障的結果更新自身配置;
8.sentinel ckquorum
檢測當前主節點的哨兵是否到達quorum的個數,ckquorum填的數和quorum對比;
9.將sentinel節點的配置資訊強制寫到磁盤上;
10.sentinel remove
取消當前sentinel節點對于指定主節點的控制;
11.sentinel monitor
指定監控的主節點name、ip、port、quorum
12.sentinel set
動態修改sentinel節點配置選項
13.sentinel is-master-down-by-addr
sentinel節點之間用來交換對主節點是否下線的判斷,根據引數不同,還可以作為sentinellingdaozhe選舉的通信方式;
部署技巧
到現在有關Redis Sentinel的配置和部署方法相信你們已經基本掌握了,但在實際生產環境中都有哪些部署的技巧?本節將總結一下,
- Sentinel節點不應該部署在一臺物理“機器”上,
這里特意強調物理機是因為一臺物理機做成了若干虛擬機或者現今比較流行的容器,它們雖然有不同的IP地址,但實際上它們都是同一臺物理視,同一臺物理機意味著如果過臺機器有什么硬體故障,所有的虛擬機都會受到影響,為了實作Sentinel節點集合真正的高可用,請勿將Sentinel節點部署在同一臺物理機器上,
2)部署至少三個且奇數個的sentinel點,
3個以上是通過增加Sentinel節點的個數提高對于故障判定的準確性,因為領導者選舉需要至少一半加1個節點,奇數個節點可以在滿足該條件的基礎上節省一個節點,
3)只有一套Sentinel,還是每個主節點配置一套Sentinel?
Sentinel節點集合可以只監控一個主節點,也可以監控多個主節點那么在實際生產環境中更偏向于哪一種部署方式呢,下面分別分析兩種方案的優缺點,
方案一:一套Sentinel,很明顯這種方案在一定程度上降低了維護成本,因為只需要維護固定個數的Sentinel節點,集中對多個Redis資料節點進行管理就可以了,但是這同時也是它的缺點,如果這套Sentinel節點集合出現例外,可能會對多個Redis資料節點造成影響,還有如果監控的Redis資料節點較多,會造成Sentinel節點產生過多的網路連接,也會有一定的影響,
方案二:多套Sentinel,顯然這種方案的優點和缺點和上面是相反的,每個Redis主節點都有自己的Sentinel節點集合,會造成資源浪費,但是優點也很明顯,每套Redis Sentinel都是彼此隔離的,
6.4 實作原理
本節將介紹Redis Sentinel的基本實作原理,具體包含以下幾個方面: Redis Sentinel的三個定時任務、主觀下線和客觀下線、Sentinel領導者選舉、故障轉移,相信通過本節的學習同學們能對Redis Sentinel的高可用特性有更加深人的理解和認識,
6.4.1 三個定時監控任務
一套合理的監控機制是Sentinel節點判定節點不可達的重要保證, Redis Sentinel通過三時監控任務完成對各個節點發現和監控:
1)每隔10秒,每個Sentinel節點會向主節點和從節點發送info命令獲取最新的拓撲結構,
這個定時任務的作用具體可以表現在三個方面:
(1)通過向主節點執行info命令,獲取從節點的資訊,這也是為什么Sentinel節點不需要顯式配置監控從節點,
(2)當有新的從節點加入時都可以立刻感知出來,
(3)節點不可達或者故障轉移后,可以通過into命令實時更新節點拓撲資訊,
2)每隔2秒,每個Sentinel節點會向Redis資料節點的_sentinel :hello頻道上發送該Sentinel節點對于主節點的判斷以及當前Sentinel節點的資訊,同時每個Sentinel節點也會訂閱該頻道,來了解其他Sentinel節點以及它們對主節點的判斷,所以這個定時任務可以完成以下兩個作業:
(1)發現新的Sentinel節點:通過訂閱主節點的_sentinel :hello了解其他的Sentinel節點資訊,如果是新加人的Sentinel節點,將該Sentinel節點資訊保存起來,并與該Sentinel節點創建連接,
(2)Sentinel節點之間交換主節點的狀態,作為后面客觀下線以及領導者選舉的依據,
Sentinel節點publish的訊息格式如下:
<Sentinel 節點IP> <Sentinel 節點埠> <Sentinel 節點runId > <Sentinel 節點配置版本> <主節點名字> <主節點IP> <主節點埠> <主節點配置版本>
- 每隔1秒,每個Sentinel節點會向主節點、從節點、其余Sentinel節點發送一條ping命令做一次心跳檢測,來確認這些節點當前是否可達,通過上面的定時任務, Sentinel節點對主節點、從節點、其余Sentinel節點都建立起連接,實作了對每個節點的監控,這個定時任務是節點失敗判定的重要依據,
6.4.2 主觀下線和客觀下線
1、主觀下線
剛才介紹的第三個定時任務,每個Sentinel節點會每隔1秒對主節點、從節點、其他Sentinel節點發送ping命令做心跳檢測,當這些節點超過down-after-milliseconds沒有進行有效回復, Sentinel節點就會對該節點做失敗判定,這個行為叫做主觀下線,從字面意思也可以很容易看出來主觀下線是當前sentinel節點的一家之言,存在誤判的可能,
2、客觀下線
當Sentinel主觀下線的節點是主節點時,該Sentinel節點會通過sentinel is-master-down-by-addr命令向其他Sentinel節點詢問對主節點的判斷,當超過個數,
Sentinel節點認為主節點確實有問題,這時該Sentinel節點會做出客觀下線的決定,這樣客觀下
線的含義是比較明顯了,也就是大部分Sentinel節點都對主節點的下線做了同意的判定,那么
這個判定就是客觀的,
Sentinel is-master-down-by-addr <current_epoch>
Ip:主節點IP
Port:主節點埠
Current_epoch:當前配置時間
Runid:不同型別決定了次API作用的不同
當runid等于“*”時,作用是Sentinel節點直接交換對主節點下線的判定,
當runid等于當前Sentinel節點的runid時,作用是當前Sentinel節點希望目標Sentinel節點同意自己成為領導者的請求,
6.4.3 領導者sentinel節點選舉
假如Sentinel節點對于主節點已經做了客觀下線,那么是不是就可以立即進行故障轉移了?當然不是,實際上故障轉移的作業只需要一個Sentinel節點來完成即可,所以Sentinel節點之間會做一個領導者選舉的作業,選出一個Sentinel節點作為領導者進行故障轉移的作業,Redis使用了Raft演算法實作領導者選舉,因為Raft演算法相對比較抽象和復雜,以及篇幅所限,所以這里給出一個Redis Sentinel進行領導者選舉的大致思路:
1)每個在線的Sentinel節點都有資格成為領導者,當它確認主節點主觀下線時候,會向其他Sentinel節點發送sentinel is-master-down-by-addr命令,要求將自己設定為領導者,
2)收到命令的Sentinel節點,如果沒有同意過其他Sentinel節點的sentinel is-master-down-by-addr命令,將同意該請求,否則拒絕,
3)如果該Sentinel節點發現自己的票數已經大于等于max (quorum, num (sentinels)/2+1),那么它將成為領導,
4)如果此程序沒有選舉出領導者,將進入下一次選舉,
實際上Redis Sentinel實作會更簡單一些,因為一旦有一個Sentinel節點獲得了max (quorum,num (sentinels)/2 + 1)的票數,其他Sentinel節點再去確認已經沒有意義了,因為每個sentinel節點只有一票,
6.4.4 故障轉移
領導者選舉出的Sentinel節點負責故障轉移,具體步驟如下:
1)在從節點串列中選出一個節點作為新的主節點,選擇方法如下:
a)過濾: “不健康”(主觀下線、斷線)、5秒內沒有回復過Sentinel節點ping回應、與主節點失聯超過down-after-milliseconds*10秒,
b)選擇slave-priority (從節點優先級)最高的從節點串列,如果存在則回傳,不存在則繼續,
c)選擇復制偏移量最大的從節點(復制的最完整),如果存在則回傳,不存在則繼續,
d)選擇runid最小的從節點,
- Sentinel領導者節點會對第一步選出來的從節點執行slaveof no one命令讓其成為主節點,
- Sentinel領導者節點會向剩余的從節點發送命令,讓它們成為新主節點的從節點,復制規則和parallel-syncs引數有關,
4)sentinel節點集合會將原來的主節點更新為從節點,并保持著對其關注,當其恢復后命令它去復制新的主節點,
6.5 節點運維
1.節點下線
在介紹如何進行節點下線之前,首先需要明白兩個概念:臨時下線和永久下線,
臨時下線:暫時將節點關掉,之后還會重新啟動,繼續提供服務,
永久下線:將節點關掉后不再使用,需要做一些清理作業,如洗掉組態檔、持久化檔案、日志檔案,
所以你需要并清楚本次下線操作是臨時下線還是永久下線,通常來看,無論是主節點、從節點還是Sentinel節點,下線原因無外乎以下幾種:
1、節點所在的機器出現了不穩定或者即將過保被識訓
2、節點所在的機器性能比較差或者記憶體比較小,無法支撐應用方的需求
3、節點自身出現服務不正常情況,需要快速處理
(1)主節點
如果需要對主節點進行下線,比較合理的做法是選出一個“合適"(例如性能更高的機器)
的從節點,使用sentinel failover功能將從節點晉升主節點, sentinel failover
(2)從節點和sentinel
如果需要對從節點或者Sentinel節點進行下線,只需要確定好是臨時還是永久下線后執
行相應操作即可,如果使用了讀寫分離,下線從節點需要保證應用方可以感知從節點的下線變化,從而把讀取請求路由到其他節點,
需要注意的是, Sentinel節點依然會對這些下線節點進行定期監控,這是由Redis sentinel的設計思路所決定,
2、節點上線
(1)添加從節點
添加從節點的場景大致有如下幾種:
- 使用了讀寫分離,但現有的從節點無法支撐應用方的流量,
- 主節點沒有可用的從節點,無法支持故障轉移,
- 添加一個更強悍的從節點利用手動failover替換主節點,
添加方法:添加slaveof (masterIp) (masterPort)的配置,使用redis-server啟動即可,它將被Sentinel節點自動發現,
(2)添加sentinel節點
添加Sentinel節點的場景可以分為以下幾種:
1)當前Sentinel節點數量不夠,無法達到Redis Sentinel健壯性要求或者無法達到票數,
2)原Sentinel節點所在機器需要下線,
添加方法:添加sentinel monitor主節點的配置,使用redis-sentinel啟動即可,它將被其余Sentinel節點自動發現,
(3)添加主節點
因為Redis Sentinel中只能有一個主節點,所以不需要添加主節點,如果需要替換主節點,可以使用Sentinel failover手動故障轉移,
3、節點配置
有關Redis資料節點和Sentinel節點配置修改以及優化的方法,前面的章節已經介紹過
了,這里給出Sentinel節點配置時要注意的地方:
(1)Sentinel節點配置盡可能一致,這樣在判斷節點故障時會更加準確,
(2)Sentinel節點支持的命令非常有限,例如config命令是不支持的,而Sentinel節點也需要dir、loglevel之類的配置,所以盡量在一開始規劃好,不過所幸Sentinel節點不存盤資料,如果需要修改配置,重新啟動即可,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/245742.html
標籤:其他
上一篇:資料庫遷移遇到的問題和解決方案
