【分享】面試官:說下Redis 主從同步原理!
1.MYISAM 和 Innodb 差別
1. InnoDB 支持事務(wù),MyISAM 不支持事務(wù)。這是 MySQL 將默認(rèn)存儲引擎從
MyISAM 變成 InnoDB 的重要原因之一;
2. InnoDB 支持外鍵,而 MyISAM 不支持。對一個包含外鍵的 InnoDB 表轉(zhuǎn)為
MYISAM 會失敗;
3. InnoDB 是聚集索引,MyISAM 是非聚集索引。聚簇索引的文件存放在主鍵索引的 葉子節(jié)點上,因此 InnoDB 必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要 兩次查詢,先查詢到主鍵,然后再通過主鍵查詢到數(shù)據(jù)。因此,主鍵不應(yīng)該過大,因為 主鍵太大,其他索引也都會很大。而 MyISAM 是非聚集索引,數(shù)據(jù)文件是分離的,索 引保存的是數(shù)據(jù)文件的指針。主鍵索引和輔助索引是獨立的。
4. InnoDB 不保存表的具體行數(shù),執(zhí)行 select count(*) from table 時需要全表掃描。而MyISAM 用一個變量保存了整個表的行數(shù),執(zhí)行上述語句時只需要讀出該變量即可,
速度很快;
5. InnoDB 最小的鎖粒度是行鎖,MyISAM 最小的鎖粒度是表鎖。一個更新語句會鎖
住整張表,導(dǎo)致其他查詢和更新都會被阻塞,因此并發(fā)訪問受限。這也是 MySQL 將默
認(rèn)存儲引擎從 MyISAM 變成 InnoDB 的重要原因之一;
6. 每個 MyISAM 在磁盤上存儲成三個文件。分別為:表定義文件、數(shù)據(jù)文件、索引文
件。InnoDB 是單文件,文件大小受操作系統(tǒng)的限制
7. MyISAM:不支持 fulltext 索引,innodb 支持
8. MyISAM 支持支持三種不同的存儲格式:靜態(tài)表(默認(rèn),但是注意數(shù)據(jù)末尾不能有空
格,會被去掉)、動態(tài)表、壓縮表。InnoDB 需要更多的內(nèi)存和存儲,它會在主內(nèi)存中建
立其專用的緩沖池用于高速緩沖數(shù)據(jù)和索引。
9. 可移植性,MyISAM 是存儲在文件中,遷移很方便,InnoDB 有各種日志,免費的方 案可以是拷貝數(shù)據(jù)文件、備份 binlog,或者用 mysqldump,在數(shù)據(jù)量達(dá)到幾十G的時 候就相對痛苦了。
2.Tcp 和 udp 的區(qū)別:
1. tcp是面向連接的,而udp是無連接就發(fā)送數(shù)據(jù)的,tcp 的三次握手,四次揮手,所以
tcp 面向鏈接,而udp就是一個數(shù)據(jù)報帶著目的ip和端口,直接發(fā)送。
2. tcp傳輸時是可靠的,udp傳輸時是不可靠的。tcp有個以字節(jié)為單位的滑動窗口,它
把要發(fā)送的數(shù)據(jù)都以字節(jié)形式存儲在這個滑動窗口當(dāng)中。每次發(fā)送完窗口的數(shù)據(jù)后,都
會先保留數(shù)據(jù),只有當(dāng)收到對方的數(shù)據(jù)確認(rèn)收到信號時再清除這些數(shù)據(jù),如果超時沒有
收到確認(rèn)信號的話就要重傳。這就是tcp的確認(rèn)重傳機(jī)制。
3. udp 適合快速傳輸不太重要但實時性要求比較高的大數(shù)據(jù),比如實時的視頻傳輸,而
tcp 適合傳輸可靠的內(nèi)容。
4. 基于tcp的應(yīng)用層協(xié)議:http,https,ftp,telnet 基于udp :dns,tftp
5. 一個TCP數(shù)據(jù)包報頭的大小是20字節(jié),UDP數(shù)據(jù)報報頭是8個字節(jié)。TCP報頭中包含
序列號,ACK號,數(shù)據(jù)偏移量,保留,控制位,窗口,緊急指針,可選項,填充項,校
驗位,源端口和目的端口。而UDP報頭只包含長度,源端口號,目的端口,和校驗和。6. TCP有流量控制。在任何用戶數(shù)據(jù)可以被發(fā)送之前,TCP需要三數(shù)據(jù)包來設(shè)置一個套
接字連接。TCP處理的可靠性和擁塞控制。另一方面,UDP不能進(jìn)行流量控制。

3.Http 和 https 的區(qū)別
1、https協(xié)議需要到ca申請證書,一般免費證書很少,需要交費。2、http是超文本傳輸協(xié)議,信息是明文傳輸,https 則是具有安全性的ssl加密 傳輸協(xié)議。3、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80, 后者是443。4、http的連接很簡單,是無狀態(tài)的;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行 加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,比http協(xié)議安全。
4.Include 和 require 區(qū)別
這兩者是語言結(jié)構(gòu),不是函數(shù),他們都可以直接引用參數(shù),而不是括號內(nèi)引用參數(shù)?
include在用時加載,一般放在代碼段中,出錯時繼續(xù)執(zhí)行下面的代碼
require一般放在腳本最前面,會一開始就讀取,出錯時停止運行代碼
_once 是已加載的不加載
5.Epoll select poll 區(qū)別
(1)select==>時間復(fù)雜度O(n) 它僅僅知道了,有I/O事件發(fā)生了,卻并不知道是哪那幾個流(可能有一個,多個,甚至 全部),我們只能無差別輪詢所有流,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流,對他們進(jìn) 行操作。所以select具有O(n)的無差別輪詢復(fù)雜度,同時處理的流越多,無差別輪詢時 間就越長。最多支持 1024 個fd。
(2)poll==>時間復(fù)雜度O(n)
poll本質(zhì)上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間,然后查詢每個fd對
應(yīng)的設(shè)備狀態(tài), 但是它沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲的. poll的
實現(xiàn)和select非常相似,只是描述fd集合的方式不同,poll 使用 pollfd 結(jié)構(gòu)而不是select 的 fd_set 結(jié)構(gòu),其他的都差不多。
(3)epoll==>時間復(fù)雜度O(1)
epoll可以理解為event poll,不同于忙輪詢和無差別輪詢,epoll會把哪個流發(fā)生了怎
樣的I/O事件通知我們。所以我們說epoll實際上是事件驅(qū)動(每個事件關(guān)聯(lián)上fd)的,
此時我們對這些流的操作都是有意義的。(復(fù)雜度降低到了O(1))select,poll,epoll都是IO多路復(fù)用的機(jī)制。I/O多路復(fù)用就通過一種機(jī)制,可以監(jiān)視多
個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進(jìn)行相應(yīng)
的讀寫操作。但select,poll,epoll本質(zhì)上都是同步I/O,因為他們都需要在讀寫事件
就緒后自己負(fù)責(zé)進(jìn)行讀寫,也就是說這個讀寫過程是阻塞的,而異步I/O則無需自己負(fù)
責(zé)進(jìn)行讀寫,異步I/O的實現(xiàn)會負(fù)責(zé)把數(shù)據(jù)從內(nèi)核拷貝到用戶空間。
總結(jié):
(1)select,poll實現(xiàn)需要自己不斷輪詢所有fd集合,直到設(shè)備就緒,期間可能要睡眠 和喚醒多次交替。而epoll其實也需要調(diào)用epoll_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設(shè)備就緒時,調(diào)用回調(diào)函數(shù),把就緒fd放入就緒鏈表中, 并喚醒在epoll_wait中進(jìn)入睡眠的進(jìn)程。雖然都要睡眠和交替,但是select和poll在“醒 著”的時候要遍歷整個fd集合,而epoll在“醒著”的時候只要判斷一下就緒鏈表是否為 空就行了,這節(jié)省了大量的CPU時間。這就是回調(diào)機(jī)制帶來的性能提升。
(2)select,poll每次調(diào)用都要把fd集合從用戶態(tài)往內(nèi)核態(tài)拷貝一次,并且要把current 往設(shè)備等待隊列中掛一次,而epoll只要一次拷貝,而且把current往等待隊列上掛也只 掛一次(在epoll_wait的開始,注意這里的等待隊列并不是設(shè)備等待隊列,只是一個 epoll內(nèi)部定義的等待隊列)。這也能節(jié)省不少的開銷。
Linux 系統(tǒng)中,把一切都看做是文件,當(dāng)進(jìn)程打開現(xiàn)有文件或創(chuàng)建新文件時,內(nèi)核向進(jìn) 程返回一個文件描述符,文件描述符就是內(nèi)核為了高效管理已被打開的文件所創(chuàng)建的索 引,用來指向被打開的文件,所有執(zhí)行I/O操作的系統(tǒng)調(diào)用都會通過文件描述符。
6.New self 和 new static 的區(qū)別:
new self()和new static()的區(qū)別只有在繼承中才能體現(xiàn)出來,如果沒有任何繼承, 那么這兩者是沒有區(qū)別的。
在繼承中,new self()返回的實例是萬年不變的,無論誰去調(diào)用,都返回同一個類 的實例,而new static()則是由調(diào)用者決定的。
7.Git reset 和 git revert 區(qū)別
git reset 會失去后面的提交,而 git revert 是通過反做的方式重新創(chuàng)建一個新的提交, 而保留原有的提交,git reset 之后需要 git push -f 強(qiáng)制提交,不建議使用
8.Do while while foreach for 區(qū)別
Do while 和while類似,do while 會不管條件真假先執(zhí)行一次,while 條件為真才執(zhí) 行,foreach 循環(huán)為先讀取整塊數(shù)據(jù),然后再循環(huán),而 for 主要用于限制循環(huán)次數(shù) 例如循環(huán)數(shù)組,while 是移動內(nèi)部指針,foreach 是對數(shù)組副本進(jìn)行操作,而 foreach 在讀操作比較快,在寫操作比較慢,因為 php 的 引用計數(shù)寫時復(fù)制 的特性
9.Mysql 事務(wù)中臟讀和幻讀的區(qū)別:
臟讀(Dirty Read): 臟讀是指一個事務(wù)讀到了另一個未提交事務(wù)修改過的數(shù)據(jù)。幻讀(Phantom Read): 所謂幻讀,指的是當(dāng)某個事務(wù)在讀取某個范圍內(nèi)的記錄
時,另外一個事務(wù)又在該范圍內(nèi)插入了新的記錄,當(dāng)之前的事務(wù)再次讀取該范圍的記錄
時,會讀取到之前沒有讀到的數(shù)據(jù)。
事務(wù)的四個隔離級別:Read Uncommitted(讀取未提交內(nèi)容),Read
Committed(讀取提交內(nèi)容),Repeatable Read(可重讀),Serializable(可串行
化),其中未提交讀會產(chǎn)生臟讀,未提交讀、提交讀、可重復(fù)讀會產(chǎn)生幻讀情況
10.Isset empty gettype is_null 區(qū)別

11.Redis 主從同步原理
Slave 初始化中是全量同步,
- 從服務(wù)器連接主服務(wù)器,發(fā)送SYNC命令;
- 主服務(wù)器接收到SYNC命名后,開始執(zhí)行BGSAVE命令生成RDB文件并使用緩沖區(qū)記
錄此后執(zhí)行的所有寫命令;
- 主服務(wù)器BGSAVE執(zhí)行完后,向所有從服務(wù)器發(fā)送快照文件,并在發(fā)送期間繼續(xù)記錄
被執(zhí)行的寫命令;
- 從服務(wù)器收到快照文件后丟棄所有舊數(shù)據(jù),載入收到的快照;
- 主服務(wù)器快照發(fā)送完畢后開始向從服務(wù)器發(fā)送緩沖區(qū)中的寫命令;
- 從服務(wù)器完成對快照的載入,開始接收命令請求,并執(zhí)行來自主服務(wù)器緩沖區(qū)的寫命
令;

全量之后是增量同步:指Slave初始化后開始正常工作時主服務(wù)器發(fā)生的寫操作同 步到從服務(wù)器的過程。
額外信息:
1)一個master可以有多個slave,slave也可以有多個slave,組成樹狀結(jié)構(gòu)2)主從同步不會阻塞master,但是會阻塞slave。也就是說當(dāng)一個或多個slave與master進(jìn)行初次同步數(shù)據(jù)時,master可以繼續(xù)處理client發(fā)來的請求。相反slave在初次同步數(shù)據(jù)時則會阻塞不能處理client的請求;3)主從同步可以用來提高系統(tǒng)的可伸縮性,我們可以用多個slave專門處理client的讀請求,也可以用來做簡單的數(shù)據(jù)冗余或者只在slave上進(jìn)行持久化從 而提升集群的整體性能。
12.redo undo 日志和事務(wù)執(zhí)行中崩潰的重放
redo log 包括兩部分:一個是內(nèi)存中的日志緩沖( redo log buffer ),另一個是磁盤上
的日志文件( redo logfile)。
mysql 每執(zhí)行一條 DML(增刪改) 語句,先將記錄寫入 redo log buffer,后續(xù)某個時 間點再一次性將多個操作記錄寫到 redo log file。這種 先寫日志,再寫磁盤 的技術(shù)就 是 MySQL wal(預(yù)寫式日志),在計算機(jī)操作系統(tǒng)中,用戶空間( user space )下的緩沖 區(qū)數(shù)據(jù)一般情況下是無法直接寫入磁盤的,中間必須經(jīng)過操作系統(tǒng)內(nèi)核空間( kernel space )緩沖區(qū)( OS Buffer )。
因此, redo log buffer 寫入 redo logfile 實際上是先寫入 OS Buffer ,然后再通過系 統(tǒng)調(diào)用 fsync() 將其刷到 redo log file中。
undo-log 保存了事務(wù)發(fā)生之前的數(shù)據(jù)的一個版本,可以用于回滾,同時可以提供多版 本并發(fā)控制下的讀(MVCC),也即非鎖定讀。在事務(wù)開始之前,將當(dāng)前事務(wù)的版本生 成undo-log,undo也會產(chǎn)生redo日志來保證undo-log的可靠性。
undo log和redo log記錄物理日志不一樣,它是邏輯日志。可以認(rèn)為當(dāng)delete一條記錄 時,undo log中會記錄一條對應(yīng)的insert記錄,反之亦然,當(dāng)update一條記錄時,它 記錄一條對應(yīng)相反的update記錄。
在恢復(fù)時,對于已經(jīng)COMMIT的事務(wù)使用redo log進(jìn)行重做,對于沒有 COMMIT的事務(wù),使用undo log進(jìn)行回滾.
13.Php 長網(wǎng)址轉(zhuǎn)成短網(wǎng)址
//短網(wǎng)址生成算法
class?ShortUrl
{
????//字符表
????public?static?$charset?=?"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
???//編碼
????public?static?function?encode($url)
????{
????????$key?=?'abc';?//加鹽
????????$urlhash?=?md5($key?.?$url);
????????$len?=?strlen($urlhash);
????????//將加密后的串分成4段,每段4字節(jié),對每段進(jìn)行計算,一共可以生成四組短連接?
????????for?($i?=?0;?$i?4;?$i++)?{
????????????$urlhash_piece?=?substr($urlhash,?$i?*?$len?/?4,?$len?/?4);
????????????//將分段的位與0x3fffffff做位與,0x3fffffff表示二進(jìn)制數(shù)的30個1,即30位?以后的加密串都?xì)w零
????????????//此處需要用到hexdec()將16進(jìn)制字符串轉(zhuǎn)為10進(jìn)制數(shù)值型,否則運算會不正常?
????????????$hex?=?hexdec($urlhash_piece)?&?0x3fffffff;
????????????//域名根據(jù)需求填寫
????????????$short_url?=?"http://t.cn/";
????????????//生成6位短網(wǎng)址
????????????for?($j?=?0;?$j?6;?$j++)?{
????????????//將得到的值與0x0000003d,3d為61,即charset的坐標(biāo)最大值?
????????????????$short_url?.=?self::$charset[$hex?&?0x0000003d];
????????????//循環(huán)完以后將hex右移5位?
????????????????$hex?=?$hex?>>?5;
????????????}
????????????$short_url_list[]?=?$short_url;
????????}
????????return?$short_url_list;
????}
}
//示例
$url?=?"http://www.sunbloger.com/";
$short?=?ShortUrl::encode($url);
print_r($short);
更好的長短網(wǎng)址轉(zhuǎn)換方案是長網(wǎng)址插入數(shù)據(jù)庫,得到id,十進(jìn)制的 id 轉(zhuǎn)成 62 進(jìn)制的值,保存起來對應(yīng)關(guān)系,可逆可查。
