# 存儲
* `[Point]` Sql
* `[Point]` NoSql
* `[Point]` 緩存
* `[Point]` 數據一致性
## 簡介
科班的同學可以了解一下[數據庫范式](http://www.cnblogs.com/CareySon/archive/2010/02/16/1668803.html), 在 ElemeFe 面試不會問, 但是其他地方可能會問 (比如阿里).
## Mysql
SQL (Structured Query Language) 是[關系式數據庫管理系統](https://en.wikipedia.org/wiki/Relational_database)的標準語言, 關于關系型數據庫這里主要帶大家看一下 Mysql 的幾個問題
### 存儲引擎
|attr|MyISAM|InnoDB|
|----|----|----|
|Locking|Table-level|Row-level|
|designed for|need of speed|high volume of data|
|foreign keys | × (DBMS) | ? (RDBMS)|
|transaction | × | ? |
|fulltext search | ? | × |
|scene| lots of select | lots of insert/update |
|count rows| fast | slow |
|auto_increment | fast | slow |
* 你的數據庫有外鍵嗎?
* 你需要事務支持嗎?
* 你需要全文索引嗎?
* 你經常使用什么樣的查詢模式?
* 你的數據有多大?
參見 [MYSQL: INNODB 還是 MYISAM?](http://coolshell.cn/articles/652.html)
### 索引
索引是用空間換時間的一種優化策略. 推薦閱讀: [mysql索引類型](http://www.cnblogs.com/cq-home/p/3482101.html) 以及 [主鍵與唯一索引的區別](http://blog.mimvp.com/2015/03/the-difference-between-primary-key-and-unique-index/)
## Mongodb
> Monogdb 連接問題(超時/斷開等)有可能是什么問題導致的?
* 網絡問題
* 任務跑不完, 超過了 driver 的默認鏈接超時時間 (如 30s)
* Monogdb 宕機了
* 超過了連接空閑時間 (connection idle time) 被斷開
* fd 不夠用 (ulimit 設置)
* mongodb 最大連接數不夠用 (可能是連接未復用導致)
* etc...
### other
populate
aggregate
pipeline
Cursor
整理中
## Replication
> 備份數據庫與 M/S, M/M 等部署方式的區別?
關于數據庫基于各種模式的特點全部可以通過以下圖片分清:

圖片出處:Google App Engine 的 co-founder Ryan Barrett 在 2009 年的 google i/o 上的演講 [《Transaction Across DataCenter》](http://snarfed.org/transactions_across_datacenters_io.html)(視頻: http://www.youtube.com/watch?v=srOgpXECblk)
根據上圖, 我們可以知道 Master/Slave 與 Master/Master 的關系.
<table>
<tr><th>attr</th><th>Master/Slave</th><th>Master/Master</th></tr>
<tr><td>一致性</td><td colspan="2">Eventually:當你寫入一個新值后,有可能讀不出來,但在某個時間窗口之后保證最終能讀出來。比如:DNS,電子郵件、Amazon S3,Google搜索引擎這樣的系統。</td></tr>
<tr><td>事務</td><td align="center">完整</td><td align="center">本地</td></tr>
<tr><td>延遲</td><td colspan="2" align="center">低延遲</td></tr>
<tr><td>吞吐</td><td colspan="2" align="center">高吞吐</td></tr>
<tr><td>數據丟失</td><td colspan="2" align="center">部分丟失</td></tr>
<tr><td>熔斷</td><td align="center">只讀</td><td align="center">讀/寫</td></tr>
</table>
### 讀寫分離
讀寫分離是在 query 量大的情況下減輕單個 DB 節點壓力, 優化數據庫讀/寫速度的一種策略. 不論是 MySQL 還是 MongoDB 都可以進行讀寫分離.
讀寫分離的配置方式直接搜索一下 `數據庫名 + 讀寫分離` 即可找到. 通常是 M/S 的情況, 使用 Master 專門寫, 用 Slave 節點專門讀. 使用讀寫分離時, 請確認讀的請求對一致性要求不高, 因為從寫庫同步讀庫是有延遲的.
## 數據一致性
關于數據一致性推薦看陳皓的[分布式系統的事務處理](http://www.infoq.com/cn/articles/distributed-system-transaction-processing)
> 什么情況下數據會出現臟數據? 如何避免?
* 從 A 帳號中把余額讀出來
* 對 A 帳號做減法操作
* 把結果寫回 A 帳號中
* 從 B 帳號中把余額讀出來
* 對 B 帳號做加法操作
* 把結果寫回 B 帳號中
為了數據的一致性, 這6件事, 要么都成功做完, 要么都不成功, 而且這個操作的過程中, 對A、B帳號的其它訪問必需鎖死, 所謂鎖死就是要排除其它的讀寫操作, 否則就會出現臟數據 ---- 即數據一致性的問題.
這個問題并不僅僅出現在數據庫操作中, 普通的并發以及并行操作都可能導致出現臟數據. 避免出現臟數據通常是從架構上避免或者采用事務的思想處理.
### 矛盾
* 1)要想讓數據有高可用性,就得寫多份數據
* 2)寫多份的問題會導致數據一致性的問題
* 3)數據一致性的問題又會引發性能問題
強一致性必然導致性能短板, 而弱一致性則有很好的性能但是存在數據安全(災備數據丟失)/一致性(臟讀/臟寫等)的問題.
目前 Node.js 業內流行的主要是與 Mongodb 配合, 在數據一致性方面屬于短板.
### 事務
事務并不僅僅是 sql 數據庫中的一個功能, 也是分布式系統開發中的一個思想, 事務在分布式的問題中可以稱為 "兩階段提交" (以下引用陳皓原文)
第一階段:
* 協調者會問所有的參與者結點,是否可以執行提交操作。
* 各個參與者開始事務執行的準備工作:如:為資源上鎖,預留資源,寫undo/redo log……
* 參與者響應協調者,如果事務的準備工作成功,則回應“可以提交”,否則回應“拒絕提交”。
第二階段:
* 如果所有的參與者都回應“可以提交”,那么,協調者向所有的參與者發送“正式提交”的命令。參與者完成正式提交,并釋放所有資源,然后回應“完成”,協調者收集各結點的“完成”回應后結束這個Global Transaction。
* 如果有一個參與者回應“拒絕提交”,那么,協調者向所有的參與者發送“回滾操作”,并釋放所有資源,然后回應“回滾完成”,協調者收集各結點的“回滾”回應后,取消這個Global Transaction。
異常:
* 如果第一階段中,參與者沒有收到詢問請求,或是參與者的回應沒有到達協調者。那么,需要協調者做超時處理,一旦超時,可以當作失敗,也可以重試。
* 如果第二階段中,正式提交發出后,如果有的參與者沒有收到,或是參與者提交/回滾后的確認信息沒有返回,一旦參與者的回應超時,要么重試,要么把那個參與者標記為問題結點剔除整個集群,這樣可以保證服務結點都是數據一致性的。
* 第二階段中,如果參與者收不到協調者的commit/fallback指令,參與者將處于“狀態未知”階段,參與者完全不知道要怎么辦。
## 緩存
> redis 與 memcached 的區別?
|attr|memcached|redis|
|----|----|----|
|struct|key/value|key/value + list, set, hash etc. |
|backup | × | ? |
|Persistence | × | ? |
|transcations | × | ? |
|consistency | strong (by cas) | weak |
|thread | multi | signle |
|memory | physical | physical & swap |
## 其他
* zookeeper
* kafka
* storm
* hadoop
* spark