1. NoSQL其實(shí)是關(guān)系型數(shù)據(jù)庫相對應(yīng)的,是no relational 即非關(guān)系型數(shù)據(jù)庫;web2.0特別是一些用戶訪問量比較大的網(wǎng)站如:www.taobao.com weibo.com baidu.com
每秒的訪問量可能是上萬次(10K);傳統(tǒng)的關(guān)系型數(shù)據(jù)庫 mysql oracle 每秒進(jìn)行10K次數(shù)據(jù)查詢還可以勉強(qiáng)應(yīng)付,但是如果是每秒10K次讀寫數(shù)據(jù)庫,因?yàn)閿?shù)據(jù)庫的數(shù)據(jù)都是卸載磁盤中,所以磁盤IO也是支撐不住每秒10K的讀寫。
在web的架構(gòu)中,數(shù)據(jù)庫是最難進(jìn)行橫向擴(kuò)展的(通過簡單的添加機(jī)器和硬件,也就是添加一些服務(wù)節(jié)點(diǎn)來提高負(fù)載均衡能力);對于7*24小時在線的網(wǎng)站來說,對關(guān)系型數(shù)據(jù)庫進(jìn)行升級和擴(kuò)展(分布式擴(kuò)展--分庫分表)是非常痛苦的事情,往往要進(jìn)行停機(jī)維護(hù);但這種對www.taobao.com 來說是非常丑陋的事情。[--可不可以添加幾臺服務(wù)器然后把復(fù)制,然后進(jìn)行負(fù)載均衡--]。
NoSQL 是采用key/value的結(jié)構(gòu)來存儲數(shù)據(jù),而且大多數(shù)的NoSQL采用內(nèi)存來存儲數(shù)據(jù),一段時間后把數(shù)據(jù)同步到磁盤中;由于使用內(nèi)存保存數(shù)據(jù)很好地解決了高并發(fā)讀寫的問題;其次NoSQL提供了根據(jù)key值進(jìn)行橫向分表(比如:用戶id,每2000w數(shù)據(jù)放到一臺數(shù)據(jù)庫服務(wù)器中的一張用戶表中);同時實(shí)現(xiàn)了主從數(shù)據(jù)庫互備,這樣可以讓數(shù)據(jù)庫的動態(tài)遷移變得簡單,讓數(shù)據(jù)庫服務(wù)器的橫向擴(kuò)展變得容易了。
2. 分布式數(shù)據(jù)庫的CAP理論
CAP理論是說Consistency(一致性), Availability(可用性), partition tolerance(分布)三部分系統(tǒng);而且任何系統(tǒng)只會滿足兩個,不會有任何的系統(tǒng)會同時滿足這三個條件;在傳統(tǒng)的關(guān)系型數(shù)據(jù)庫中是強(qiáng)調(diào)C 一致性,但是在滿足高可用性(高并發(fā)時效率不高),高擴(kuò)展性(分布式數(shù)據(jù)庫進(jìn)行橫向擴(kuò)展)存在一定的缺陷。但是NoSQL在進(jìn)行設(shè)計的時候就是針對并發(fā)海量數(shù)據(jù)存儲的情況下進(jìn)行設(shè)計的,在這種高并發(fā)海量數(shù)據(jù)下數(shù)據(jù)一致性并不像銀行那樣保持?jǐn)?shù)據(jù)的強(qiáng)一致性,所以NoSQL·放棄強(qiáng)一致性的追求,從而達(dá)到更高的可用性和擴(kuò)展性,通過“鴿巢原理”達(dá)到最終的一致性。
現(xiàn)在的數(shù)據(jù)庫系統(tǒng)肯定是同一個時刻有多個進(jìn)程對數(shù)據(jù)庫進(jìn)行讀寫操作,假設(shè)現(xiàn)在有3個進(jìn)程(A、B、C)對數(shù)據(jù)庫的某表進(jìn)行操作,
- 強(qiáng)一致性:A寫入的數(shù)據(jù)x,B、C可以讀到數(shù)據(jù)x
- 弱一致性:A寫入的數(shù)據(jù)x,B、C一段時間內(nèi)讀不到,最后會讀到
- 最終一致性:是一種特殊的一致性,保證在一段時間內(nèi)沒有數(shù)據(jù)的更新,但所有的返回都是把最新的數(shù)據(jù)返回;---緩存的概念,一段時間后把數(shù)據(jù)更新到數(shù)據(jù)庫,達(dá)到最終一致性。
3. 哈希算法
(1). 哈希算法的基本原理:
哈希算法的提出和應(yīng)用背景,對于一個龐大的字符串?dāng)?shù)組array,給你一個字符串讓你判斷它是否在這個字符串?dāng)?shù)組中并找到它,最好的辦法就是把這個龐大的字符串?dāng)?shù)組構(gòu)建成一個哈希表,然后在進(jìn)行查詢是否有這個字符串。
(2).構(gòu)建hash table的過程:一般是采用一個32的整數(shù)來代表一個字符串,首先這個array的字符串已經(jīng)存在內(nèi)存或者磁盤中,我們要做的只是按照一定的算法把每個字符串映射到一個32位的整數(shù),每個int占4個字節(jié),在字符串中每個字符都占一個字節(jié);這樣就建立了字符串與32位整數(shù)的映射,然后根據(jù)程序大小設(shè)定一個hash table的Size(這個Size確保所有的int % Size的值是唯一的--取最大值即可),這個把剛才得到的所有字符串對應(yīng)的32位整數(shù)對這個Size進(jìn)行取模,這個模值就是此整數(shù)在hash table的位置;這個位置與每一個字符串又建立了一個映射關(guān)系;這樣讓你查詢這個str是否在array中?
- 首先,是把這個str,用相同的哈希算法進(jìn)行編碼---->映射到一個32位的int型數(shù)據(jù) num
- 然后,把這個num % Size 獲取此字符串在hash table里面的位置;
- 然后,判斷hash table 此位置是否已經(jīng)有數(shù)據(jù)占用,如果已經(jīng)占用說明在array里面有一個字符串對應(yīng)的32位整數(shù)與str的32位整數(shù)相同,在一個字符串對應(yīng)唯一一個32位整數(shù)的前提條件下,就說明array里面存在字符串str。
- int GetHashTablePos(char *lpszString, SOMESTRUCTURE *lpTable, int nTableSize)
- { //lpszSring--要查詢的字符串;lpTable 哈希表;nTableSize是哈希表的Size
- int nHash = HashString(lpszString), nHashPos = nHash % nTableSize;
-
- if (lpTable[nHashPos].bExists && !strcmp(lpTable[nHashPos].pString, lpszString)) //時間復(fù)雜度是O(1)
- return nHashPos;
- else
- return -1; //Error value
- }
(3). 上面的處理方法是假設(shè)一個字符串通過一個哈希算法只得到唯一一個hashcode(32為int整數(shù));但是如果存在兩個整數(shù)在同一個哈希算法得到同一個hashcode,那這個查詢就不正確的,雖然這個可能性比較小,但確實(shí)存在這個風(fēng)險。
采用的解決辦法是用多個不同的哈希算法來校驗(yàn),兩個str 在三個不同的哈希算法得到的hashcode都相同的概率是:1/18889465931478580854784;可以認(rèn)為是OK的。
- int GetHashTablePos(char *lpszString, MPQHASHTABLE *lpTable, int nTableSize)
- {
- const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
- int nHash = HashString(lpszString, HASH_OFFSET);
- int nHashA = HashString(lpszString, HASH_A);
- int nHashB = HashString(lpszString, HASH_B);
- int nHashStart = nHash % nTableSize, nHashPos = nHashStart;
- while (lpTable[nHashPos].bExists)
- {
- if (lpTable[nHashPos].nHashA == nHashA && lpTable[nHashPos].nHashB == nHashB)
- return nHashPos;
- else
- nHashPos = (nHashPos + 1) % nTableSize;
- if (nHashPos == nHashStart)
- break;
- }
- return -1; //Error value
- }
這樣就可以保證萬無一失了!
(4). 常見的哈希算法:MD5 SHA SHA-1等都是常用的哈希算法,而且他們都屬于混合哈希算法,除了混合哈希算法還有加法、乘法、除法的哈希算法;
所以,在比較一個文件是否發(fā)生變化的方法出了可以用最后修改時間來判斷,也可以用其哈希code來比較,比如用MD5來比較,如果其MD5都變化了則文件一定被修改了。
4. Tair 緩存也是一種 基于key/value的NoSQL結(jié)構(gòu)開發(fā)的一種緩存機(jī)制,其實(shí)質(zhì)也是NoSQL數(shù)據(jù)庫,不過是key/value結(jié)構(gòu)而且是用內(nèi)存來存儲數(shù)據(jù),所以用把Tair叫做緩存。
5. 關(guān)系型數(shù)據(jù)庫的事務(wù)(ACID)
(1). 事務(wù)(Transaction):Transaction是訪問并可能更新數(shù)據(jù)庫中各種數(shù)據(jù)項(xiàng)的一個程序執(zhí)行單元(unit),事務(wù)一般由高級數(shù)據(jù)語言(C++ Java SQL)等寫的用戶程序引起的,并用begin transaction----end transaction 來界定一個完整的事務(wù)
- <begin transaction>
- ****
- ****
- ****
- </end transaction>
一個完整的事務(wù)由
begin transaction----end transaction 里面的所有操作組成;在關(guān)系型數(shù)據(jù)庫中一個事務(wù)可以是一條SQL語句或一組SQL語句或者是一個程序;事務(wù)是并發(fā)和回滾的基本單位。(2). 事務(wù)的ACID屬性:
- Atomicity(原子性):一個事務(wù)是一個不可分割的完整單元,一個transaction里面的所有操作要么都做完,要么都不做;當(dāng)中間一個操作失敗把所有已經(jīng)做的操作都回滾!
- Consistency(一致性):數(shù)據(jù)庫在一個事務(wù)開始前是一致性的,在這個事務(wù)執(zhí)行完畢后仍然是一致性的;只是從一個一致性狀態(tài)到另一個一致性狀態(tài);但都是一致性的
- Isolation(隔離性):一個事務(wù)的執(zhí)行不能被其他事務(wù)所打擾,即一個事務(wù)內(nèi)部操作及使用的數(shù)據(jù)對并發(fā)的事務(wù)是隔離的,并發(fā)執(zhí)行的事務(wù)之間互相不干擾(不理解)!!
- Durablity(持久性):也就永久性(Permanence),即一個事務(wù)一旦執(zhí)行完畢,則它對數(shù)據(jù)庫的更新是持久性的,即不受其他操作的影響;也就是事務(wù)修改了數(shù)據(jù)庫了
這個ACID的屬性是關(guān)系型數(shù)據(jù)庫(DBMS)非常重要的屬性,在執(zhí)行數(shù)據(jù)庫操作時必須滿足ACID屬性,其中AI是我們編程中要注意的地方。