1. 答:
關系型數據庫:Mysql,Oracel,Microsoft SQL Server
非關系型數據庫:MongoDB,memcache,Redis。
2. 答:
MyISAM:默認的MySQL插件式存儲引擎,它是在Web、數據倉儲和其他應用環境下最常使用的存儲引擎之一。注意,通過更改STORAGE_ENGINE配置變量,能夠方便地更改MySQL服務器的默認存儲引擎。
InnoDB:用於事務處理應用程序,具有眾多特性,包括ACID事務支持。(提供行級鎖)
BDB:可替代InnoDB的事務引擎,支持COMMIT、ROLLBACK和其他事務特性。
Memory:將所有數據保存在RAM中,在需要快速查找引用和其他類似數據的環境下,可提供極快的訪問。
Merge:允許MySQL DBA或開發人員將一系列等同的MyISAM表以邏輯方式組合在一起,並作為1個對象引用它們。對於諸如數據倉儲等VLDB環境十分適合。
Archive:為大量很少引用的歷史、歸檔、或安全審計信息的存儲和檢索提供了完美的解決方案。
Federated:能夠將多個分離的MySQL服務器鏈接起來,從多個物理服務器創建一個邏輯數據庫。十分適合於分布式環境或數據集市環境。
Cluster/NDB:MySQL的簇式數據庫引擎,尤其適合於具有高性能查找要求的應用程序,這類查找需求還要求具有最高的正常工作時間和可用性。
Other:其他存儲引擎包括CSV(引用由逗號隔開的用作數據庫表的文件),Blackhole(用於臨時禁止對數據庫的應用程序輸入),以及Example引擎(可為快速創建定制的插件式存儲引擎提供幫助)。
3. 答:
第一范式:確保每列的原子性.
如果每列(或者每個屬性)都是不可再分的最小數據單元(也稱為最小的原子單元),則滿足第一范式.
例如:顧客表(姓名、編號、地址、……)其中"地址"列還可以細分為國家、省、市、區等。
第二范式:在第一范式的基礎上更進一層,目標是確保表中的每列都和主鍵相關.
如果一個關系滿足第一范式,並且除了主鍵以外的其它列,都依賴於該主鍵,則滿足第二范式.
例如:訂單表(訂單編號、產品編號、定購日期、價格、……),"訂單編號"為主鍵,"產品編號"和主鍵列沒有直接的關系,即"產品編號"列不依賴於主鍵列,應刪除該列。
第三范式:在第二范式的基礎上更進一層,目標是確保每列都和主鍵列直接相關,而不是間接相關.
如果一個關系滿足第二范式,並且除了主鍵以外的其它列都不依賴於主鍵列,則滿足第三范式.
為了理解第三范式,需要根據Armstrong公里之一定義傳遞依賴。假設A、B和C是關系R的三個屬性,如果A-〉B且B-〉C,則從這些函數依賴中,可以得出A-〉C,如上所述,依賴A-〉C是傳遞依賴。
例如:訂單表(訂單編號,定購日期,顧客編號,顧客姓名,……),初看該表沒有問題,滿足第二范式,每列都和主鍵列"訂單編號"相關,再細看你會發現"顧客姓名"和"顧客編號"相關,"顧客編號"和"訂單編號"又相關,最后經過傳遞依賴,"顧客姓名"也和"訂單編號"相關。為了滿足第三范式,應去掉"顧客姓名"列,放入客戶表中。
4.答:
一般來說,事務是必須滿足4個條件(ACID)::原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。
原子性:一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性:在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及后續數據庫可以自發性地完成預定的工作。
隔離性:數據庫允許多個並發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務並發執行時由於交叉執行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。
持久性:事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。
MYSQL 事務處理主要有兩種方法:
1、用 BEGIN, ROLLBACK, COMMIT來實現
BEGIN 開始一個事務
ROLLBACK 事務回滾
COMMIT 事務確認
2、直接用 SET 來改變 MySQL 的自動提交模式:
SET AUTOCOMMIT=0 禁止自動提交
SET AUTOCOMMIT=1 開啟自動提交
5. 答:
作者模型:一個作者有姓名。
作者詳細模型:把作者的詳情放到詳情表,包含性別,email地址和出生日期,作者詳情模型和作者模型之間是一對一的關系(one-to-one)(類似於每個人和他的身份證之間的關系),在大多數情況下我們沒有必要將他們拆分成兩張表,這里只是引出一對一的概念。
出版商模型:出版商有名稱,地址,所在城市,省,國家和網站。
書籍模型:書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關系就是多對多的關聯關系(many-to-many),一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關系(one-to-many),也被稱作外鍵。
6. 答:
高並發之下使用內存數據庫Redis,正常則使用表來進行計數。
DROP TABLE access_counter;
CREATE TABLE access_counter(
cnt INT UNSIGNED NOT NULL
);
INSERT INTO access_counter VALUES(0);
UPDATE access_counter SET cnt=cnt+1;
SELECT * FROM access_counter;
7.略
8.答:
視圖:視圖是由查詢結果形成的一張虛擬表,是表通過某種運算得到的一個投影。
同一張表可以創建多個視圖
存儲過程:概念類似於函數,就是把一段代碼封裝起來,當要執行這一段代碼的時候,可以通過調用該存儲過程來實現。在封裝的語句體里面,
可以同if/else ,case,while等控制結構。
可以進行sql編程。
查看現有的存儲過程。
函數:需要先定義,然后調用(使用)。
只是規定,這個函數,必須要返回數據——要有返回值
觸發器:(1)觸發器是一個特殊的存儲過程,它是MySQL在insert、update、delete的時候自動執行的代碼塊。
(2)觸發器必須定義在特定的表上。
(3)自動執行,不能直接調用,
作用:監視某種情況並觸發某種操作。
9.答:
單列:B+樹/哈希索引 --> 查詢速度快更新速度慢
- 普通索引 :加速查找
- 唯一索引 :加速查詢 + 約束(不能重復)
- 主鍵索引 :加速查詢 + 約束(不能重復) + 不能為空
- 全文索引 :
多列:遵循最左前綴規則
- 聯合索引 :
- 聯合唯一索引 :
其他:
- 索引合並 :利用多個單例索引查詢
- 覆蓋索引 :在索引表中就能將想要的數據查詢到
- 組合索引遵循最左前綴規則
如果組合索引為:(name,email)
name and email -- 使用索引
name -- 使用索引
email -- 不使用索引
10. 答:
假設聯合索引是state/city/zipCode
那么state就是第一關,city是第二關,zipCode就是第三關
必須匹配了第一關,才能匹配第二關,匹配了第一關和第二關,才能匹配第三關
你不能直接到第二關的
索引的格式就是第一層是state,第二層才是city
多列索引是先按照第一列進行排序,然后在第一列排好序的基礎上再對第二列排序,如果沒有第一列的話,直接訪問第二列,那第二列肯定是無序的,直接訪問后面的列就用不到索引了
11. 答:主鍵是唯一標識一條記錄,不能有重復,不允許為空,表的外鍵就是另一表的逐漸,外鍵可以有重復,可以是空值。
主鍵用來保證數據完整性,外鍵用來和其它表建立聯系
主鍵只可以有一個,而一個表可以有多個外鍵。
12. 答:數學函數:ABS,BIN,MOD,PI
聚合函數,AVG,MIN,MAX
字符串函數,ASCII,CONCAT
日期和時間函數,DATE_ADD,DATE_SUB
加密函數
13. 答:
1、查詢謂詞沒有使用索引的主要邊界,換句話說就是select *,可能會導致不走索引。
比如,你查詢的是SELECT * FROM T WHERE Y=XXX;假如你的T表上有一個包含Y值的組合索引,但是優化器會認為需要一行行的掃描會更有效,這個時候,優化器可能會選擇TABLE ACCESS FULL,但是如果換成了SELECT Y FROM T WHERE Y = XXX,優化器會直接去索引中找到Y的值,因為從B樹中就可以找到相應的值。
2、單鍵值的b樹索引列上存在null值,導致COUNT(*)不能走索引。
如果在B樹索引中有一個空值,那么查詢諸如SELECT COUNT(*) FROM T 的時候,因為HASHSET中不能存儲空值的,所以優化器不會走索引,有兩種方式可以讓索引有效,一種是SELECT COUNT(*) FROM T WHERE XXX IS NOT NULL或者把這個列的屬性改為not null (不能為空)。
3、索引列上有函數運算,導致不走索引
如果在T表上有一個索引Y,但是你的查詢語句是這樣子SELECT * FROM T WHERE FUN(Y) = XXX。這個時候索引也不會被用到,因為你要查詢的列中所有的行都需要被計算一遍,因此,如果要讓這種sql語句的效率提高的話,在這個表上建立一個基於函數的索引,比如CREATE INDEX IDX FUNT ON T(FUN(Y));這種方式,等於Oracle會建立一個存儲所有函數計算結果的值,再進行查詢的時候就不需要進行計算了,因為很多函數存在不同返回值,因此必須標明這個函數是有固定返回值的。
4、隱式轉換導致不走索引。
索引不適用於隱式轉換的情況,比如你的SELECT * FROM T WHERE Y = 5 在Y上面有一個索引,但是Y列是VARCHAR2的,那么Oracle會將上面的5進行一個隱式的轉換,SELECT * FROM T WHERE TO_NUMBER(Y) = 5,這個時候也是有可能用不到索引的。
5、表的數據庫小或者需要選擇大部分數據,不走索引
在Oracle的初始化參數中,有一個參數是一次讀取的數據塊的數目,比如你的表只有幾個數據塊大小,而且可以被Oracle一次性抓取,那么就沒有使用索引的必要了,因為抓取索引還需要去根據rowid從數據塊中獲取相應的元素值,因此在表特別小的情況下,索引沒有用到是情理當中的事情。
6、cbo優化器下統計信息不准確,導致不走索引
很長時間沒有做表分析,或者重新收集表狀態信息了,在數據字典中,表的統計信息是不准確的,這個情況下,可能會使用錯誤的索引,這個效率可能也是比較低的。
7、!=或者<>(不等於),可能導致不走索引,也可能走 INDEX FAST FULL SCAN
例如select id from test where id<>100
8、表字段的屬性導致不走索引,字符型的索引列會導致優化器認為需要掃描索引大部分數據且聚簇因子很大,最終導致棄用索引掃描而改用全表掃描方式,
由於字符型和數值型的在insert的時候排序不同,字符類型導致了聚簇因子很大,原因是插入順序與排序順序不同。詳細點說,就是按照數字類型插入(1..3200000),按字符類型('1'...'32000000')t排序,在對字符類型使用大於運算符時,會導致優化器認為需要掃描索引大部分數據且聚簇因子很大,最終導致棄用索引掃描而改用全表掃描方式。
14.答:
slow_query_log = OFF # 是否開啟慢日志記錄
long_query_time = 2 # 時間限制,超過此時間,則記錄
slow_query_log_file = /usr/slow.log # 日志文件
log_queries_not_using_indexes = OFF # 為使用索引的搜索是否記錄
15. 答:
MySQL命令行導出數據庫
1,進入MySQL目錄下的bin文件夾:cd MySQL中到bin文件夾的目錄
如我輸入的命令行:cd C:\Program Files\MySQL\MySQL Server 4.1\bin
(或者直接將windows的環境變量path中添加該目錄)
2,導出數據庫:mysqldump -u 用戶名 -p 數據庫名 > 導出的文件名
如我輸入的命令行:mysqldump -u root -p news > news.sql (輸入后會讓你輸入進入MySQL的密碼)
(如果導出單張表的話在數據庫名后面輸入表名即可)
3、會看到文件news.sql自動生成到bin文件下
命令行導入數據庫
1,將要導入的.sql文件移至bin文件下,這樣的路徑比較方便
2,同上面導出的第1步
3,進入MySQL:mysql -u 用戶名 -p
如我輸入的命令行:mysql -u root -p (輸入同樣后會讓你輸入MySQL的密碼)
4,在MySQL-Front中新建你要建的數據庫,這時是空數據庫,如新建一個名為news的目標數據庫
5,輸入:mysql>use 目標數據庫名
如我輸入的命令行:mysql>use news;
6,導入文件:mysql>source 導入的文件名;
16. 答:
選取最適用的字段屬性。
使用連接(join)來代替子查詢(Sub-Queries)
使用聯合(UNION)來代替手動創建的臨時表
事務
鎖定表
使用外鍵
使用索引
優化的查詢語句
17. 答:char長度不可變,varchar長度是可變的。char的存取數度還是要比varchar要快得多,因為其長度固定,方便程序的存儲與查找;但是char也為此付出的是空間的代價,因為其長度固定,所以難免會有多余的空格占位符占據空間,可謂是以空間換取時間效率,而varchar是以空間效率為首位的。
再者,char的存儲方式是,對英文字符(ASCII)占用1個字節,對一個漢字占用兩個字節;而varchar的存儲方式是,對每個英文字符占用2個字節,漢字也占用2個字節。
18. 答:
弄明白了explain語法返回的每一項結果,我們就能知道查詢大致的運行時間了,如果查詢里沒有用到索引、或者需要掃描的行過多,那么可以感到明顯的延遲。因此需要改變查詢方式或者新建索引。mysql中的explain語法可以幫助我們改寫查詢,優化表的結構和索引的設置,從而最大地提高查詢效率。當然,在大規模數據量時,索引的建立和維護的代價也是很高的,往往需要較長的時間和較大的空間,如果在不同的列組合上建立索引,空間的開銷會更大。因此索引最好設置在需要經常查詢的字段中。
19. 答:兩個查詢語句的區別在於,下面那一句是從從第一行開始查詢。
20. 答:
如果使用子查詢去優化LIMIT的話,則子查詢必須是連續的,某種意義來講,子查詢不應該有where條件,where會過濾數據,使數據失去連續性。
如果你查詢的記錄比較大,並且數據傳輸量比較大,比如包含了text類型的field,則可以通過建立子查詢。
SELECT id,title,content FROM items WHERE id IN (SELECT id FROM items ORDER BY id limit 900000, 10);
如果limit語句的offset較大,你可以通過傳遞pk鍵值來減小offset = 0,這個主鍵最好是int類型並且auto_increment優化方法有子查詢優化法,倒排表優化法,反向查找優化法,limit限制優化法,只查優化法。
21. 答:
1、索引合並是把幾個索引的范圍掃描合並成一個索引。
2、索引合並的時候,會對索引進行並集,交集或者先交集再並集操作,以便合並成一個索引。
3、這些需要合並的索引只能是一個表的。不能對多表進行索引合並。
22. 答:
覆蓋索引只是特定於具體select語錄而言的聯合索引。也就是說一個聯合索引對於某個select語句,通過索引可以直接獲取查詢結果,而不再需要回表查詢啦,就稱該聯合索引覆蓋了這條select語句。
或者: MySQL可以利用索引返回SELECT 列表中的字段。而不必根據索引再次讀取數據文件。包含所有滿足查詢需要的數據的索引成為覆蓋索引(Covering Index)。也就是平時所說的不需要回表操作。
或者:就是select的數據列只用從索引中就能夠取得,不必從數據表中讀取,換句話說查詢列要被所使用的索引覆蓋。
23. 答:
通過設置主從數據庫實現讀寫分離,主數據庫負責“寫操作”,從數據庫負責“讀操作”,根據壓力情況,從數據庫可以部署多個提高“讀”的速度,借此來提高系統總體的性能。
要實現讀寫分離,就要解決主從數據庫數據同步的問題,在主數據庫寫入數據后要保證從數據庫的數據也要更新。
24.答:
垂直切分
把不同功能,不同模塊的數據分別放到不同的表中,但是如果同一個模塊的數據量太大就會存在性能瓶頸
水平切分
垂直切分解決不了大表的瓶頸,如果同一個功能中表的數據量過大,就要對該表進行切分,為水平切分
通俗理解:垂直切分---分不同的模塊表;水平切分---分同一個模塊下的多個表。
25. 答:
1、Redis和Memcache都是將數據存放在內存中,都是內存數據庫。不過memcache還可用於緩存其他東西,例如圖片、視頻等等;
2、Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲;
3、虛擬內存--Redis當物理內存用完時,可以將一些很久沒用到的value 交換到磁盤;
4、過期策略--memcache在set時就指定,例如set key1 0 0 8,即永不過期。Redis可以通過例如expire 設定,例如expire name 10;
5、分布式--設定memcache集群,利用magent做一主多從;redis可以做一主多從。都可以一主一從;
6、存儲數據安全--memcache掛掉后,數據沒了;redis可以定期保存到磁盤(持久化);
7、災難恢復--memcache掛掉后,數據不可恢復; redis數據丟失后可以通過aof恢復;
8、Redis支持數據的備份,即master-slave模式的數據備份;
26. 答:
默認情況下是十六個。
27. 答:安裝Redis, import redis
28. 答:
Redis實例需要裝載大量用戶在短時間內產生的數據,數以百萬計的keys需要被快速的創建。即大量數據插入(mass insertion)
使用Luke協議
使用正常模式的Redis客戶端執行大量數據插入是不明智的:因為一個個的插入會有大量的時間浪費在每一個命令往返時間上。
使用管道(pipelining)還比較靠譜,但是在大量插入數據的同時又需要執行其他新命令時,這時讀取數據的同時需要確保盡可能快的寫入數據。
只有一小部分的客戶端支持非阻塞/輸出(non-blocking I/O),並且並不是所有客戶端能以最大限度的提高吞吐量到高效的方式來分析答復。
同時,在分析回復的時候,我們會采用計數器的方法計數,以便在最后能夠告訴我們大量插入數據的數據量
29. 答:
Redis主從復制可以根據是否是全量分為全量同步和增量同步。
Redis全量復制一般發生在Slave初始化階段,這時Slave需要將Master上的所有數據都復制一份。具體步驟如下:
1)從服務器連接主服務器,發送SYNC命令;
2)主服務器接收到SYNC命名后,開始執行BGSAVE命令生成RDB文件並使用緩沖區記錄此后執行的所有寫命令;
3)主服務器BGSAVE執行完后,向所有從服務器發送快照文件,並在發送期間繼續記錄被執行的寫命令;
4)從服務器收到快照文件后丟棄所有舊數據,載入收到的快照;
5)主服務器快照發送完畢后開始向從服務器發送緩沖區中的寫命令;
6)從服務器完成對快照的載入,開始接收命令請求,並執行來自主服務器緩沖區的寫命令;
2 增量同步
Redis增量復制是指Slave初始化后開始正常工作時主服務器發生的寫操作同步到從服務器的過程。
增量復制的過程主要是主服務器每執行一個寫命令就會向從服務器發送相同的寫命令,從服務器接收並執行收到的寫命令。
Redis的正常部署中一般都是一個master用於寫操作,若干個slave用於讀操作,另外定期的數據備份操作也是單獨選址一個slave完成,這樣可以最大程度發揮出redis的性能。在部署完成,各master\slave程序啟動之后,首先進行第一階段初始化時的全同步操作,全同步操作完成之后,后續所有寫操作都是在master上進行,所有讀操作都是在slave上進行,因此用戶的寫操作需要及時擴散到所有的slave以便保持數據最大程度上的同步。
30. 答:
Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis做Master-slave的高可用方案時,假如master宕機了,Redis本身(包括它的很多客戶端)都沒有實現自動進行主備切換,而Redis-sentinel本身也是一個獨立運行的進程,它能監控多個master-slave集群,發現master宕機后能進行自動切換。
它的主要功能有以下幾點
不時地監控redis是否按照預期良好地運行;
如果發現某個redis節點運行出現狀況,能夠通知另外一個進程(例如它的客戶端);
能夠進行自動切換。當一個master節點不可用時,能夠選舉出master的多個slave(如果有超過一個slave的話)中的一個來作為新的master,其它的slave節點會將它所追隨的master的地址改為被提升為master的slave的新地址。
31.答:
1.客戶端分片
客戶端分片是把分片的邏輯放在Redis客戶端實現,通過Redis客戶端預先定義好的路由規則,把對Key的訪問轉發到不同的Redis實例中,最后把返回結果匯集。
2.Twemproxy
Twemproxy是由Twitter開源的Redis代理,其基本原理是:Redis客戶端把請求發送到Twemproxy,Twemproxy根據路由規則發送到正確的Redis實例,最后Twemproxy把結果匯集返回給客戶端。
Twemproxy通過引入一個代理層,將多個Redis實例進行統一管理,使Redis客戶端只需要在Twemproxy上進行操作,而不需要關心后面有多少個Redis實例,從而實現了Redis集群。
3.Codis
Twemproxy不能平滑增加Redis實例的問題帶來了很大的不便,於是豌豆莢自主研發了Codis,一個支持平滑增加Redis實例的Redis代理軟件,其基於Go和C語言開發,並於2014年11月在GitHub上開源。
Codis包含下面4個部分。
Codis Proxy:Redis客戶端連接到Redis實例的代理,實現了Redis的協議,Redis客戶端連接到Codis Proxy進行各種操作。Codis Proxy是無狀態的,可以用Keepalived等負載均衡軟件部署多個Codis Proxy實現高可用。
CodisRedis:Codis項目維護的Redis分支,添加了slot和原子的數據遷移命令。Codis上層的 Codis Proxy和Codisconfig只有與這個版本的Redis通信才能正常運行。
Codisconfig:Codis管理工具。可以執行添加刪除CodisRedis節點、添加刪除Codis Proxy、數據遷移等操作。另外,Codisconfig自帶了HTTP server,里面集成了一個管理界面,方便運維人員觀察Codis集群的狀態和進行相關的操作,極大提高了運維的方便性,彌補了Twemproxy的缺點。
ZooKeeper:分布式的、開源的應用程序協調服務,是Hadoop和Hbase的重要組件,其為分布式應用提供一致性服務,提供的功能包括:配置維護、名字服務、分布式同步、組服務等。Codis依賴於ZooKeeper存儲數據路由表的信息和Codis Proxy節點的元信息。另外,Codisconfig發起的命令都會通過ZooKeeper同步到CodisProxy的節點。
4.Redis 3.0集群
Redis 3.0集群采用了P2P的模式,完全去中心化。Redis把所有的Key分成了16384個slot,每個Redis實例負責其中一部分slot。集群中的所有信息(節點、端口、slot等),都通過節點之間定期的數據交換而更新。
Redis客戶端在任意一個Redis實例發出請求,如果所需數據不在該實例中,通過重定向命
5.雲服務器上的集群服務
國內的雲服務器提供商阿里雲、UCloud等均推出了基於Redis的雲存儲服務。
令引導客戶端訪問所需的實例。
32. 答:默認有16384個哈希槽
33. 答:
Redis的持久化策略:2種
---------rdb:快照形式是直接把內存中的數據保存到一個dump文件中,定時保存,保存策略
這種方式不能完全保證數據持久化,因為是定時保存,所以當redis服務down掉,就會丟失一部分數據,而且數據量大,寫操作多的情況下,會引起大量的磁盤IO操作,會影響性能。
---------aof:把所有的對redis的服務器進行修改的命令都存到一個文件里,命令的集合
使用aof做持久化,每一個寫命令都通過write函數追加到appendonly.aof中.
配置方式:啟動aof持久化的方式
34. 答:
定時刪除
含義:在設置key的過期時間的同時,為該key創建一個定時器,讓定時器在key的過期時間來臨時,對key進行刪除
優點:保證內存被盡快釋放
缺點:
若過期key很多,刪除這些key會占用很多的CPU時間,在CPU時間緊張的情況下,CPU不能把所有的時間用來做要緊的事兒,還需要去花時間刪除這些key
定時器的創建耗時,若為每一個設置過期時間的key創建一個定時器(將會有大量的定時器產生),性能影響嚴重
沒人用
惰性刪除
含義:key過期的時候不刪除,每次從數據庫獲取key的時候去檢查是否過期,若過期,則刪除,返回null。
優點:刪除操作只發生在從數據庫取出key的時候發生,而且只刪除當前key,所以對CPU時間的占用是比較少的,而且此時的刪除是已經到了非做不可的地步(如果此時還不刪除的話,我們就會獲取到了已經過期的key了)
缺點:若大量的key在超出超時時間后,很久一段時間內,都沒有被獲取過,那么可能發生內存泄露(無用的垃圾占用了大量的內存)
定期刪除
含義:每隔一段時間執行一次刪除過期key操作
優點:
通過限制刪除操作的時長和頻率,來減少刪除操作對CPU時間的占用--處理"定時刪除"的缺點
定期刪除過期key--處理"惰性刪除"的缺點
缺點
在內存友好方面,不如"定時刪除"
在CPU時間友好方面,不如"惰性刪除"
難點
合理設置刪除操作的執行時長(每次刪除執行多長時間)和執行頻率(每隔多長時間做一次刪除)(這個要根據服務器運行情況來定了)
35. 答:
redis 內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。redis 提供 6種數據淘汰策略:
volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
no-enviction(驅逐):禁止驅逐數據
36.略
37.答:
Redis提供了兩種方式來作消息隊列。
一個是使用生產者消費模式模式,
另一個就是發布訂閱者模式。
前者會讓一個或者多個客戶端監聽消息隊列,一旦消息到達,消費者馬上消費,誰先搶到算誰的,如果隊列里沒有消息,則消費者繼續監聽。
后者也是一個或多個客戶端訂閱消息頻道,只要發布者發布消息,所有訂閱者都能收到消息,訂閱者都是平等的。
38.答:
“發布/訂閱”模式包含兩種角色,分別是發布者和訂閱者。訂閱者可以訂閱一個或若干個頻道(channel),而發布者可以向指定的頻道發送消息,所有訂閱此頻道的訂閱者都會收到此消息。
發布者發送消息的命令是PUBLISH,用法是PUBLISH channel message,如向channel.1說一聲“hi”:
redis>PUBLISH channel.1 hi
(integer) 0
這樣消息就發出去了。返回值表示接收到這條消息的訂閱者數量。發出去的消息不會被持久化,也就是說當客戶端訂閱channel.1后只能收到后續發布到該頻道的消息,之前發送到就收不到了。
訂閱頻道的命令是SUBSCRIBE,可以同時訂閱多個頻道,用法是 SUBSCRIBE channel [channel ...]。
redis>SUBSCRIBE channel.1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel.1"
3) (integer) 1
執行SUBSCRIBE命令后進入訂閱狀態,處於此狀態下客戶端不能使用除SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCRIBE這四個屬於“發布/訂閱”模式之外的命令,否則會報錯。
進入訂閱模式后客戶端可能收到三種類型的回復。每種類型的回復都包含3個值,第一個值是消息的類型,根據消息類型的不同,第二第三個值的含義也不同。消息類型可能的取值有:
(1)Subscribe。表示訂閱成功的反饋信息。第二個值是訂閱成功的頻道名稱,第三個值是當前客戶端訂閱的頻道數。
(2)message。這個類型的回復表示收到的消息。第二個值表示產生消息的頻道名稱,第三個值是消息內容。
(3)unsubscribe。表示成功取消訂閱某個頻道。第二個值是對應的頻道名稱,第三個值是當前客戶端訂閱的頻道數量,當此值為0時客戶端會退出訂閱狀態。
39. 答:
Codis 是一個分布式 Redis 解決方案, 對於上層的應用來說, 連接到 Codis Proxy 和連接原生的 Redis Server 沒有明顯的區別 (不支持的命令列表), 上層應用可以像使用單機的 Redis 一樣使用, Codis 底層會處理請求的轉發, 不停機的數據遷移等工作, 所有后邊的一切事情, 對於前面的客戶端來說是透明的, 可以簡單的認為后邊連接的是一個內存無限大的 Redis 服務.
40. 答:
Twemproxy 也叫 nutcraker。是 Twtter 開源的一個 Redis 和 Memcache 代理服務器,主要用於管理 Redis 和 Memcached 集群,減少與Cache 服務器直接連接的數量。
Twemproxy特性:
輕量級、快速
保持長連接
減少了直接與緩存服務器連接的連接數量
使用 pipelining 處理請求和響應
支持代理到多台服務器上
同時支持多個服務器池
自動分片數據到多個服務器上
實現完整的 memcached 的 ASCII 和再分配協議
通過 yaml 文件配置服務器池
支持多個哈希模式,包括一致性哈希和分布
能夠配置刪除故障節點
可以通過端口監控狀態
支持 linux, *bsd,os x 和 solaris
41.答:
class CasNormal(object):
def __init__(self, host, key):
self.r = redis.Redis(host)
self.key = key
if not self.r.exists(self.key):
self.r.set(self.key, 0)
def inc(self):
with self.r.pipeline() as pipe:
while True:
try:
#監視一個key,如果在執行期間被修改了,會拋出WatchError
pipe.watch(self.key)
next_count = 30 + int(pipe.get(self.key))
pipe.multi()
if next_count < int(time.time()):
next_count = int(time.time())
pipe.set(self.key, next_count)
pipe.execute()
return next_count
except WatchError:
continue
finally:
pipe.reset()
42.答:Redis Watch 命令用於監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那么事務將被打斷
43.略
44.答:
分布式鎖應該具有的特性(Safety & Liveness)
我們將從三個特性的角度出發來設計RedLock模型:
安全性(Safety):在任意時刻,只有一個客戶端可以獲得鎖(排他性)。
避免死鎖:客戶端最終一定可以獲得鎖,即使鎖住某個資源的客戶端在釋放鎖之前崩潰或者網絡不可達。
容錯性:只要Redsi集群中的大部分節點存活,client就可以進行加鎖解鎖操作。
一個Client想要獲得一個鎖需要以下幾個操作:
得到本地時間
Client使用相同的key和隨機數,按照順序在每個Master實例中嘗試獲得鎖。在獲得鎖的過程中,為每一個鎖操作設置一個快速失敗時間(如果想要獲得一個10秒的鎖, 那么每一個鎖操作的失敗時間設為5-50ms)。
這樣可以避免客戶端與一個已經故障的Master通信占用太長時間,通過快速失敗的方式盡快的與集群中的其他節點完成鎖操作。
客戶端計算出與master獲得鎖操作過程中消耗的時間,當且僅當Client獲得鎖消耗的時間小於鎖的存活時間,並且在一半以上的master節點中獲得鎖。才認為client成功的獲得了鎖。
如果已經獲得了鎖,Client執行任務的時間窗口是鎖的存活時間減去獲得鎖消耗的時間。
如果Client獲得鎖的數量不足一半以上,或獲得鎖的時間超時,那么認為獲得鎖失敗。客戶端需要嘗試在所有的master節點中釋放鎖, 即使在第二步中沒有成功獲得該Master節點中的鎖,仍要進行釋放操作。
45.答:
一致性哈希要對緩存的key進行哈希,同時也需要服務器也提供一個key進行哈希,然后將其分布在一個閉圓上,在決定一個key的分布的時候,這里通過找到第一個大於這個key的哈希值的服務器就行了。。。
這樣在當一台服務器退出之后,或者有新的服務器加入進來之后,只會影響一部分的key的哈希分布,不至於導致所有的key的哈希分布都失效。
46. 答:獲取指定前綴的key:redis-cli KEYS “oldboy*”