數據庫(DB)
RDBMS -- MySQL
nosql -- mongodb
redis 典型nosql數據庫
========================================================================
redis ? 安裝:
Linux:
????????redis-stable.tar.gz (源代碼包):
????????tar -zxvf
????????make
????????cd src
????????make install
????????sudo apt-get/apt install redis-server(不推薦)
window:
????????exe:
????????????????????下一步
????????zip:
????????????????1、解壓zip包
????????????????2、將主目錄配置到path
????????????????3、cmd redis-server
????????????????4、cmd redis-cli
?將redis-server注冊為window的服務或者Linux的守護進程
window:
????????redis-server 配置文件的絕對路徑 --service-install
????????net start redis? # 啟動redis服務
????????redis-cli
linux:
????????修改配置文件:137行 daemonize yes 表示以守護進程運行redis
????????redis-service 配置文件的絕對路徑
????????redis-cli
????????redis的配置文件:
redis有五種數據類型:
????????String:
????????hash:
????????list
????????set
????????sorted set? zset
==String類型的操作==
set key value # 表示將key對應的字符串存儲起來
eg:set ? ?name ? ?zhangsan
get key # 獲取key對應的值
eg:get ? ?name
mset key1 v1 key1 v2 key3 v3 # 多個鍵值對保存
eg:mset ? ?age ? ?18 ? ?gender ? ?nan ? ?nickname ? ?xiaozhang ??
mget key1 key2 key3 # 獲取多個key對應的值
eg:mset ? ?name ? ?age ? ?gender ? ?nickname ?
setex key seconds value # 設置一個key,seconds秒后失效
eg:setex ? ?address ? ?10 ? ?zz
incr key # 將key對應的值加一,注意:只能是數字字符串
eg:incr ? ?age
incrby key number # 將key對應的值加number
eg:incrby ? ?age ? ?10
decr key # 將key對應的值減一
eg:decr ? ?age
decrby key number # 將key對應的值減number
eg:decrby ? ?age ? ?5
strlen key # 求key對應的長度
eg:strlen ????name/age/gender/nickname
append key value # 對key的值末尾進行追加
eg:append ? ?nickname ? ?laozhang
setrange key offset value # 將key對應的值的offset位置開始替換為value
eg:setrange ? ?nickname ? ?3 ? ? today
getrange key start end # 獲取key對應的值的區間值
eg:getrange ? ?nickname ? ?0 ? ?-1
getrange ? ?nickname ? ?3 ? ?6
setnx key value # 判斷是否存在key,如果不存在,則增加
eg: ?setnx ? ?name ? ?zhangsan
? ? ? ? ? setnx ? ?name ? ?lisi ?
==key的操作==
keys * # 查詢當前數據庫下的所有key
exists key # 判斷key是否存在
eg:exists ? ?name ? ?
exists ? ?valuex
type key # 判斷key對應的值的類型
eg: ?type ? ? name/age/gender/nickname
del key # 刪除key
eg:del ? ?address
expire key seconds # 為一個存在的key設置失效時間
eg:expire ? ?nickname ? ?50
# set + expire? <====> setex
ttl key(Time To Live) # 查看某個key的失效時間 -1 永久有效 -2 失效 正數表示正在失效的時間秒數
eg: ttl ? ?name
????? ? ttl ? ? address
????????ttl ? ?nickname
persist key # 取消key的失效,讓它永久有效
eg:persist ? ?nickname
select index # 切換數據庫
eg:select ? ?1
move key index # 將當前數據庫的key移動到對應數據庫下
eg:move ? ? nickname ????1
dbsize # 返回當前數據庫下key的數量
Info # 查詢當前數據的信息
flushdb # 清空當前數據庫? (慎用)
flushall # 清空所有的數據庫(慎用)
==hash的操作==
hset key field value # 保存一個對象的屬性和值
eg:hset ? ?u1 ? ?name ? ?zhangsan
hget key field # 通過對象的屬性獲取值
eg:hget ? ?u1 ? ?name
hmset key f1 v1 f2 v2…… # 保存一個對象的多個屬性和值
eg:hmset ? ?u1 ? ?age ? ?18 ? ?gender ? ?nan ? ?nickname ? ?xiaozhang
hmget key f1 f2 # 通過對象的多個屬性獲取值
eg:hmget ? ?u1 ? ?name ? ?age ? ?gender ? ?nickname
hgetall key # 獲取對象的所有屬性和值
eg:hgetall ? ?u1
hkeys key # 獲取對象的所有屬性名稱
eg:hkeys ? ?u1
hvals key # 獲取對象的所有屬性的值
eg:hvals ? ?u1
hlen key # 獲取對象的屬性個數
eg:hlen ? ?u1
hexists key field # 查詢對象是否存在某個屬性
eg:hexists ? ?u1 ? ?name/address
hdel key field # 刪除對象的某個屬性
eg:hdel ? ?u1 ? ?nickname
hstrlen key field # 查詢對象的屬性的值的長度
eg:hstrlen ? ?u1 ? ?age/name.....
==list的操作==
redis的list是一個隊列和棧 字符串 的實現
lpush key value1 value2…… # 從左側壓入數據到list中
eg: ?lpush ? ?list1 ? ?zhangsan
? ? ? ? ? lpush ? ?today ? ? is ? ?good
rpush key value1 value2…… # 從右側壓入數據到list中
eg: ? ?rpush ? ?list1 ? ?lisi ? ?wangwu ? ?zhaoliu
lrange key start end # 從左側start位置開始循環展示數據,到end結束
eg:lrange ? ? list1 ? ?0 ? ? -1
linsert key before|after pivot value: # 在一個元素前/后插入數據
eg: ?linsert ? ?list1 ? ?before ? ?zhangsan ? ? xiaozhang????
? ? ? ? ?linsert ? ?list1 ? ?after ? ?wangwu ? ?xiaowang
lpop key # 移除第一個元素
eg:lpop ? ?list1
rpop key # 移除最后一個元素
eg:rpop ? ?list1
llen key # 獲取list的元素個數
eg:llen ? ? list1
lindex key index # 獲取索引對應的值
eg:lindex ? ? list1 ? ? 3
ltrim key start end # 截取list,從start位置開始,到end結束(組成新的列表,代替原來的)
eg:ltrim ? ?list1 ? ?0 ? ?-1
lrem key count value # 刪除value元素,count個(有重復或者刪一個或0)
eg:lrem ? ?list1 ? ?2 ? ?is
==set的操作==
sadd key value1 value2…… # 將v1,v2……添加到set中
eg:sadd ? ? set1 ? ?today ? ?is ? ?good
????????sadd ? ?set2 ? ?happy ? ?new ? ?year ? ?very ? ?good
smembers key # 展示set中所有元素
eg:smembers ? ?set1
sismember key value # 判斷value在不在key中
eg:sismember ? ?set1 ? ?very
scard key # 返回set的元素個數
eg:scard ? ?set1
sinter key [key]: # 獲取多個集合 交集
eg: ?sinter ? ?set1 ? ?set2
sdiff key [key]: # 獲取多個集合的差集
eg:sdiff ? ?set1 ? ?set2
????????sdiff ? ?set2 ? ?set1
sunion key [key]: # 獲取多個集合的并集
eg:sunion ? ?set1 ? ?set2
srem key member # 移除元素
eg:srem ? ?set1 ? ?good
spop key [count] # 隨機移除元素
eg:spop ? ?set1 ? ?[2]
sdiffstore newkey key1 key2 # 將差集保存成一個新的set
eg:sdiffstore ? ?set3 ? ?set1????set2
srandmember key # 隨機獲取一個元素
eg:srandmember ? ?set1
==zset的操作==
zadd key score value2 [score value2] # 將值添加到zset中
eg:zadd ? ? z1 ? ?13 ? ? liuzhijuan
zrange key start end # 遍歷展示數據
eg:zrange ? ? z1 ? ?0 ? ?-1
zcard key???? # 返回set的元素個數
eg:zcard ? ?z1
zcount ? ?key ? ? min ? ?max????返回score值在min和max之間的數據個數
eg:zcount ? ?z1 ? ?3 ? ?20
zscore ? ?key ? ?value????返回集合中元素的score(權重值)
eg:zscore ? ?z1 ? ?juan
面試題:
緩存:
????緩存的英文是cache,一般是用于RAM存儲器,用于存儲臨時數據,斷電后存儲的內容會消失。緩存是臨時文件交換區,電腦把最常用的文件從存儲器里提出來臨時放在緩存里,就像把工具和材料搬上工作臺一樣,這樣會比用時現去倉庫取更方便。因為緩存往往使用的是RAM(斷電即掉的非永久儲存),所以在忙完后還是會把文件送到硬盤等存儲器里永久存儲。電腦里最大的緩存就是內存條了,最快的是CPU上鑲的L1和L2緩存,顯卡的顯存是給GPU用的緩存,硬盤上也有16M或者32M的緩存。千萬不能把緩存理解成一個東西,它是一種處理方式的統稱。
什么是redis、什么是memcache,兩者有什么區別?
>>Memcached
Memcached的優點:
Memcached可以利用多核優勢,單實例吞吐量極高,可以達到幾十萬QPS(取決于key、value的字節大小以及服務器硬件性能,日常環境中QPS高峰大約在4-6w左右)。適用于最大程度扛量。
支持直接配置為session handle。
Memcached的局限性:
只支持簡單的key/value數據結構,不像Redis可以支持豐富的數據類型。
無法進行持久化,數據不能備份,只能用于緩存使用,且重啟后數據全部丟失。
無法進行數據同步,不能將MC中的數據遷移到其他MC實例中。
Memcached內存分配采用Slab Allocation機制管理內存,value大小分布差異較大時會造成內存利用率降低,并引發低利用率時依然出現踢出等問題。需要用戶注重value設計。
>>Redis
Redis的優點:
支持多種數據結構,如 string(字符串)、 list(雙向鏈表)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基數估算)
支持持久化操作,可以進行aof及rdb數據持久化到磁盤,從而進行數據備份或數據恢復等操作,較好的防止數據丟失的手段。
支持通過Replication進行數據復制,通過master-slave機制,可以實時進行數據的同步復制,支持多級復制和增量復制,master-slave機制是Redis進行HA的重要手段。
單線程請求,所有命令串行執行,并發情況下不需要考慮數據一致性問題。
支持pub/sub消息訂閱機制,可以用來進行消息訂閱與通知。
支持簡單的事務需求,但業界使用場景很少,并不成熟。
Redis的局限性:
Redis只能使用單線程,性能受限于CPU性能,故單實例CPU最高才可能達到5-6wQPS每秒(取決于數據結構,數據大小以及服務器硬件性能,日常環境中QPS高峰大約在1-2w左右)。
支持簡單的事務需求,但業界使用場景很少,并不成熟,既是優點也是缺點。
Redis在string類型上會消耗較多內存,可以使用dict(hash表)壓縮存儲以降低內存耗用。
Mc和Redis都是Key-Value類型,不適合在不同數據集之間建立關系,也不適合進行查詢搜索。比如redis的keys pattern這種匹配操作,對redis的性能是災難。
>>mongoDB?
mongoDB?是一種文檔性的數據庫。先解釋一下文檔的數據庫,即可以存放xml、json、bson類型系那個的數據。
這些數據具備自述性(self-describing),呈現分層的樹狀數據結構。redis可以用hash存放簡單關系型數據。
mongoDB?存放json格式數據。
適合場景:事件記錄、內容管理或者博客平臺,比如評論系統。
1.mongodb持久化原理
mongodb與mysql不同,mysql的每一次更新操作都會直接寫入硬盤,但是mongo不會,做為內存型數據庫,數據操作會先寫入內存,然后再會持久化到硬盤中去,那么mongo是如何持久化的呢
mongodb在啟動時,專門初始化一個線程不斷循環(除非應用crash掉),用于在一定時間周期內來從defer隊列中獲取要持久化的數據并寫入到磁盤的journal(日志)和mongofile(數據)處,當然因為它不是在用戶添加記錄時就寫到磁盤上,所以按mongodb開發者說,它不會造成性能上的損耗,因為看過代碼發現,當進行CUD操作時,記錄(Record類型)都被放入到defer隊列中以供延時批量(groupcommit)提交寫入,但相信其中時間周期參數是個要認真考量的參數,系統為90毫秒,如果該值更低的話,可能會造成頻繁磁盤操作,過高又會造成系統宕機時數據丟失過。
2.什么是NoSQL數據庫?NoSQL和RDBMS有什么區別?在哪些情況下使用和不使用NoSQL數據庫?
NoSQL是非關系型數據庫,NoSQL = Not Only SQL。
關系型數據庫采用的結構化的數據,NoSQL采用的是鍵值對的方式存儲數據。
在處理非結構化/半結構化的大數據時;在水平方向上進行擴展時;隨時應對動態增加的數據項時可以優先考慮使用NoSQL數據庫。
在考慮數據庫的成熟度;支持;分析和商業智能;管理及專業性等問題時,應優先考慮關系型數據庫。
3.MySQL和MongoDB之間最基本的區別是什么?
關系型數據庫與非關系型數據庫的區別,即數據存儲結構的不同。
4.MongoDB的特點是什么?
(1)面向文檔(2)高性能(3)高可用(4)易擴展(5)豐富的查詢語言
5.MongoDB支持存儲過程嗎?如果支持的話,怎么用?
MongoDB支持存儲過程,它是javascript寫的,保存在db.system.js表中。
6.如何理解MongoDB中的GridFS機制,MongoDB為何使用GridFS來存儲文件?
GridFS是一種將大型文件存儲在MongoDB中的文件規范。使用GridFS可以將大文件分隔成多個小文檔存放,這樣我們能夠有效的保存大文檔,而且解決了BSON對象有限制的問題。
7.為什么MongoDB的數據文件很大?
MongoDB采用的預分配空間的方式來防止文件碎片。
8.當更新一個正在被遷移的塊(Chunk)上的文檔時會發生什么?
更新操作會立即發生在舊的塊(Chunk)上,然后更改才會在所有權轉移前復制到新的分片上。
9.MongoDB在A:{B,C}上建立索引,查詢A:{B,C}和A:{C,B}都會使用索引嗎?
不會,只會在A:{B,C}上使用索引。
10.如果一個分片(Shard)停止或很慢的時候,發起一個查詢會怎樣?
如果一個分片停止了,除非查詢設置了“Partial”選項,否則查詢會返回一個錯誤。如果一個分片響應很慢,MongoDB會等待它的響應。
>>Redis、Memcache和MongoDB的區別
從以下幾個維度,對redis、memcache、mongoDB 做了對比,
1、性能
都比較高,性能對我們來說應該都不是瓶頸
總體來講,TPS方面redis和memcache差不多,要大于mongodb
2、操作的便利性
memcache數據結構單一
redis豐富一些,數據操作方面,redis更好一些,較少的網絡IO次數
mongodb支持豐富的數據表達,索引,最類似關系型數據庫,支持的查詢語言非常豐富
3、內存空間的大小和數據量的大小
redis在2.0版本后增加了自己的VM特性,突破物理內存的限制;可以對key value設置過期時間(類似memcache)
memcache可以修改最大可用內存,采用LRU算法
mongoDB適合大數據量的存儲,依賴操作系統VM做內存管理,吃內存也比較厲害,服務不要和別的服務在一起
4、可用性(單點問題)
對于單點問題,
redis,依賴客戶端來實現分布式讀寫;主從復制時,每次從節點重新連接主節點都要依賴整個快照,無增量復制,因性能和效率問題,
所以單點問題比較復雜;不支持自動sharding,需要依賴程序設定一致hash 機制。
一種替代方案是,不用redis本身的復制機制,采用自己做主動復制(多份存儲),或者改成增量復制的方式(需要自己實現),一致性問題和性能的權衡
Memcache本身沒有數據冗余機制,也沒必要;對于故障預防,采用依賴成熟的hash或者環狀的算法,解決單點故障引起的抖動問題。
mongoDB支持master-slave,replicaset(內部采用paxos選舉算法,自動故障恢復),auto sharding機制,對客戶端屏蔽了故障轉移和切分機制。
5、可靠性(持久化)
對于數據持久化和數據恢復,
redis支持(快照、AOF):依賴快照進行持久化,aof增強了可靠性的同時,對性能有所影響
memcache不支持,通常用在做緩存,提升性能;
MongoDB從1.8版本開始采用binlog方式支持持久化的可靠性
6、數據一致性(事務支持)
Memcache 在并發場景下,用cas保證一致性
redis事務支持比較弱,只能保證事務中的每個操作連續執行
mongoDB不支持事務
7、數據分析
mongoDB內置了數據分析的功能(mapreduce),其他不支持
8、應用場景
redis:數據量較小的更性能操作和運算上
memcache:用于在動態系統中減少數據庫負載,提升性能;做緩存,提高性能(適合讀多寫少,對于數據量比較大,可以采用sharding)
MongoDB:主要解決海量數據的訪問效率問題
redis有哪些持久化方案?
redis支持(快照、AOF):依賴快照進行持久化,aof增強了可靠性的同時,對性能有所影響
什么是緩存擊穿、什么緩存穿透
緩存雪崩
緩存雪崩是指在我們設置緩存時采用了相同的過期時間,導致緩存在某一時刻同時失效,請求全部轉發到DB,DB瞬時壓力過重雪崩。
解決方案
緩存失效時的雪崩效應對底層系統的沖擊非常可怕。大多數系統設計者考慮用加鎖或者隊列的方式保證緩存的單線 程(進程)寫,從而避免失效時大量的并發請求落到底層存儲系統上。這里分享一個簡單方案就時講緩存失效時間分散開,比如我們可以在原有的失效時間基礎上增加一個隨機值,比如1-5分鐘隨機,這樣每一個緩存的過期時間的重復率就會降低,就很難引發集體失效的事件。
緩存穿透
緩存穿透是指查詢一個一定不存在的數據,由于緩存是不命中時被動寫的,并且出于容錯考慮,如果從存儲層查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到存儲層去查詢,失去了緩存的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應用,這就是漏洞。
有很多種方法可以有效地解決緩存穿透問題,最常見的則是采用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被 這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。另外也有一個更為簡單粗暴的方法(我們采用的就是這種),如果一個查詢返回的數據為空(不管是數 據不存在,還是系統故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鐘。
對于一些設置了過期時間的key,如果這些key可能會在某些時間點被超高并發地訪問,是一種非常“熱點”的數據。這個時候,需要考慮一個問題:緩存被“擊穿”的問題,這個和緩存雪崩的區別在于這里針對某一key緩存,前者則是很多key。
緩存在某個時間點過期的時候,恰好在這個時間點對這個Key有大量的并發請求過來,這些請求發現緩存過期一般都會從后端DB加載數據并回設到緩存,這個時候大并發的請求可能會瞬間把后端DB壓垮。
業界比較常用的做法,是使用mutex。簡單地來說,就是在緩存失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作返回成功時,再進行load db的操作并回設緩存;否則,就重試整個get緩存的方法。?
SETNX,是「SET if Not eXists」的縮寫,也就是只有不存在的時候才設置,可以利用它來實現鎖的效果。在redis2.6.1之前版本未實現setnx的過期時間,