2014年5月4日 星期日

MongoDB 學習筆記之二 - MongoDB 簡介

一、什麼是 MongoDB?

MongoDB 是一套 open source 的 NoSQL DB。MongoDB 本身是用 C++ 開發的,它提供了高效能 (high performace)、高可用度 (high availability) 以及自動擴充 (automatic scaling) 等特色。

如下圖所示,在 MongoDB 中,一筆資料就是一個「document」(文件),所謂的 document 是由多個 field-value pairs 所組成的,其結構類似於 JSON 物件。一個 field (欄位) 裡的 value (值)可以是其他的文件、陣列或者由文件組成的陣列。


圖一、MongoDB 中每一筆紀錄都是 JSON 格式的 document

MongoDB 以 document 作為基本的資料儲存單位,有下列幾項好處
  1. JSON document 可對應於許多物件導向程式語言的原生資料類型 (如:物件),這也是近年來 JSONORM (Object-Relational Mapping) 日漸風行的原因 。
  2. RDBMS 的 JOIN 操作其實是成本高昂的,但如果採用 嵌入式文件 (embedded document) 或陣列的方式,可減少 JOIN 操作的使用。
  3. 動態的 schema 支援流暢的多型 (ploymorphism)。
本文寫作時的 MongoDB 社群正式版(production release)為 2.6.0 (2014/04/08 發行)。目前支援的 OS 如下表所示:

WindowsLinuxMac OS XSolaris
32-bit
64-bit

您可以在 MognoDB 官網的「Downloads」網頁下載。不過要注意的是,32 位元的版本有一個限制,即最多只能儲存 2 GB 的資料。所以,一般說來,你應該使用 64 位元版本。32 位元版本僅適用在 replica set 的「arbiter」(裁決者) 角色,或者用做 sharding 的 mongos (但請不要用於正式環境),相關資訊請參考這個網頁

MongoDB 的授權許可(license):
  • Database Server 和 Tools:AGPL
  • Drivers:Apache License
  • MongoDB Enterprise (企業版):MongoDB Inc. 提供商用的 licenses

MongoDB 的 key features(摘錄自官網):
  • High Performance
    • Support for embedded data models reduces I/O activity on database system.
    • Indexes support faster queries and can include keys from embedded documents and arrays.
  • High Availability (replica set)
    A replica set is a group of MongoDB servers that maintain the same data set, providing redundancy and increasing data availability.
    • automatic failover.
    • data redundancy.
  • Automatic Scaling (sharding)
    • Automatic sharding distributes data across a cluster of machines.
    • Replica sets can provide eventually-consistent reads for low-latency high throughput deployments.

二、關於 MongoDB Inc.

www.mongodb.org」是 MongoDB 社群版的官方網站,「www.mongodb.com」則是 MongoDB 企業版的官方網站,這兩個網站基本上都是由 Mongo Inc. 這家公司在維護。2013 年 8 月 27 日以前,MongoDB Inc. 其實叫做「10gen Inc.」的,為了避免造成大家的困惑,所以直接以產品名稱作為公司的名稱,詳情請參考 Tech Crunch 網站上這篇報導:《10gen Is Now MongoDB To Reflect Focus On NoSQL Database》。

2007 年,10gen Inc. 成立於紐約。由 Dwight Merriman (前 DoubleClick 創辦人兼 CTO )、Kevin P. Ryan (前 DoubleClick CEO、Gilt Groupe 創辦人)、 Eliot Horowitz (前 DoubleClck 工程師、 ShopWiki 創辦人兼 CTO ) 三人,接受了來自 Flybridge Capital Partners、In-Q-Tel、Intel、New Enterprise Associates (NEA)、Red Hat、紅杉資本 (Sequoia Capital) 以及 Union Square Ventures 共約 8,100 萬美金的投資。

10gen 最初的目標是希望能建立一個完全基於 open source 元件的 PaaS 架構,但因為該公司始終找不到一套既有的 DB 平台,可以符合他們建造此雲端架構的「原則」。因此,這家公司開始發展一套文件導向的資料庫系統 —— MongoDB

在發現這套系統的潛力之後,10gen 決定放棄原來的雲端平台計畫,全力投入 MongoDB 的開發與維護。2009 年,10gen 將 MongoDB 公開釋出為 open source 專案。2010 年 8 月,10gen 設立了位於美國西岸加州 Palo Alto 的辦公室。2011 年,陸續在維吉尼亞州的 Reston、英國倫敦、愛爾蘭都柏林、西班牙巴塞隆納、澳洲雪梨等地設立據點。

2012 年 9 月,在 華爾街日報 一篇《The Next Big Thing 2012》的報導裡,10gen 評為頂尖軟體公司排行榜的第 9 名

2013 年 4 月,10gen 搬進了舊紐約時報大樓。並於同年 8 月 27 日 10gen 宣佈將更名為 MongoDB Inc.,讓大家能由公司名稱直接就聯想到其代表性產品。

2013 年 10 月,MongoDB Inc. 在新一輪融資中獲得了1.5 億美元的風險創投資金,其估值達到 12 億美元,成為紐約估值最高的新創公司!(詳情請參考 Bloomberg 的這篇報導:《MongoDB Now King of NYC Startups With $1.2 Billion Valuation》和 TechOrange 的這篇報導:《NoSQL 資料庫的春天:MongoDB 獲得 1.5 億美元融資,它背後的故事是什麼?》)

三、MongoDB vs. RDBMS

以下這張 MongoDB 與 RDBMS 的對照表摘錄自官網的《SQL to MongoDB Mapping Chart》:

RDBMSMongoDB
databasedatabase
tablecollection
rowdocument or BSON document
columnfield
indexindex
table joinsembedded documents and linking
primary key
Specify any unique column or column combination as primary key.
primary key
In MongoDB, the primary key is automatically set to the _id field.
aggregation (e.g. group by)aggregation pipeline
See the SQL to Aggregation Mapping Chart.

下圖是在「users」這個 collection 裡新增一筆 document 的範例,也說明了 MongoDB 中的 Collection 與 Document 之間的關係:

圖二、Collection 與 Document 之間的關係

下表則是 MongoDB 與 RDBMS 在 DDL 與 DML 的比較表:

DML / DDLRDBMSMongoDB
DDLCREATE TABLEdb.collection.insert()
db.createCollection()
ALTER TABLEdb.collection.update()
DROP TABLEdb.collection.drop()
CREATE INDEXdb.collection.ensureIndex()
DROP INDEXdb.collection.dropIndex()
db.collection.dropIndexes()
DMLINSERTdb.collection.insert()
db.collection.save()
UPDATEdb.collection.update()
db.collection.save()
DELETEdb.collection.remove()
SELECTdb.collection.find()
db.collection.findOne()

※ 關於「db.collection.save()」,請參考官方文件
  •  如果未指定 _id,則等同執行「db.collection.insert()」。
  •  如果有指定 _id,則等同執行 upsert(即 db.collection.update({ _id: "XXXX"}, {document}, { upsert : true}))。若該 _id 已存在,則更新該筆 document;若該 _id 不存在,則新增一筆 document。

四、MongoDB 的安裝

MongoDB 的安裝非常簡單,官網已經提供了各種作業系統的安裝說明(如下),所以這裡就不再贅述囉。
五、結論

MongoDB 因為獲得相當龐大的資金挹注,所以銀彈充足,目前改版速度相當快。以最近兩次改版僅間隔三個月(2014/01/10 才出 2.4.9 版、2014/04/08 便跳到 2.6.0 版),以及 2.6.0 版的 release notes 所揭露的新功能與改版幅度來看,現在 MongoDB 應該處於急速成長的階段。

雖然如此,但我仍覺得 MongoDB 是相當值得一試的產品!

2014年5月2日 星期五

MongoDB 學習筆記之一 - 從 NoSQL 談起


近年來,資訊業界最夯的話題莫過於 Cloud Computing 和 Big Data 了,而「NoSQL」便是伴隨著這兩個主題所產生的技術主題。

MongoDB 也算是一種 NoSQL DB,所以我們會先從 NoSQL 說起,以利讀者們對於 NoSQL DB 有個基本認識以後,之後才來介紹 MongoDB。

一、NoSQL 的定義

一般人第一次看到「NoSQL」,直覺地都會以為是「不使用 SQL」的意思,其實不然,所以目前業界比較傾向使用「Not Only SQL」來解釋 NoSQL 一詞,也就是說通常是透過類似 SQL 的 API 來存取這類 DB。

以下則是摘錄《nosql-database.org》網站對「NoSQL」的定義:

「Next Generation Databases mostly addressing some of the points: being non-relationaldistributedopen-source and horizontally scalable. 」

圖一、《nosql-database.org》網站上對「NoSQL」的定義與特徵說明
二、NoSQL DB 的特徵

以下特徵採用的是《Toad World》網站「Survey distributed databases」一文的說法。
  1. Schema-less
    有類似「Table」的資料結構,但不需預先定義 schema。每一筆記錄的欄位數量與結構也可以不一樣。紀錄的內容與限制條件主要由應用程式來控管。
  2. Shared nothing architecture
    通常採用本地儲存、而非共同儲存設備(如 SAN 或 NAS)。本地磁碟的存取速度較透過網路傳輸快,也能透過增加節點的方式來擴充容量。使用一般規格的硬體即可(commodity hardware),故成本也隨之下降。
  3. Elasticity
    只需增加更多主機,便能立即擴充儲存容量與負載能力,所以不需要有停機時間(downtime)。當新節點加入後,資料庫便會開始分配任務給它。
  4. Sharding
    不將儲存視為龐大的空間,取而代之的是以「分片」(shard)方式來分割資料集。分片可在主機間進行複製(replication),但一個分片至少會由一部主機來管理。分片過大時,可採用自動分割方式,或者以程式為每一筆記錄指派所屬的分片ID。
  5. Asynchronous replication
    相較於 RAID (mirroring / stripping)或同步複製機制,NoSQL DB採用的是非同步的複製。這種方式較不會受到額外網路流量影響,所以能使寫入動作更快完成。又因為資料不會立即複製,所以某些時候可能發生資料遺失的狀況。此外,也沒有 lock 機制以保護某些特定資料。
  6. BASE instead of ACID
    由於 NoSQL DB 強調的是效能與可用度,所以「CAP Theorem」會比 RDBMS 的「ACID」更為重要。

三、NoSQL DB 的類型

世界頂尖的大師級人物  Martin Fowler、堪稱為「架構師中的架構師」。他在 2013 年的「goto; Conference」有一場主題為「Introduction to NoSQL」的演講,其中便對 NoSQL DB 做了一個分類:DocumentBig TableGraph 以及 Key-Value

而下面這張圖就是我仿效該場演講其中一張投影片所重製的:

圖二、NoSQL DB 的四大類型
以下則是放在 Youtube 上面的錄影,請大家一睹大師風采。


四、Non-Relational vs. Relational

2012 年 TechCrunch 網站上有一篇介紹 Big Data 五大開放源碼技術趨勢的文章 —— 「Big Data Right Now: Five Trendy Open Source Technologies」。該文作者 Tim Gasper 是 InfoChimps 的產品總監,InfoChimps 則是一家專門提供 Big Data 服務、平台的公司。

下圖也是我重製文中的一張照片,原圖是一張不是很清晰的照片。

圖三、Non-Relational vs. Relational

由上圖,我們可以知道:MongoDB 應該是一種 Non-RelationalNoSQLDocument based 的 DB:
  1. Non-Relational:代表了「無法或不使用 JOIN」。
  2. NoSQL:代表了「不使用標準 SQL 語言」。
  3. Document based:代表了「每筆紀錄都是一個 document」(相對於 RDBMS 的 row 而言)。
五、NoSQL DB 的理論基礎 - CAP & BASE

在 2000 年 的 PODC(Principles of Distributed Computing)會議上,柏克萊加州大學的 Eric Brewer 提出了著名的 「CAP Theorem」(CAP 定理)。2002 年,Seth Gilbert 和 Nancy Lynch 證明了這一理論:

  • Consistency(一致性)
    一致性是說資料的原子性,這種原子性在傳統 RDBMS 中是透過 Transaction 來保證的,當 Transaction 完成時,無論其是成功還是回滾,資料都會處於一致的狀態。在分散式環境中,一致性是說多個節點的資料是否一致。
  • Availability(可用性)
    可用性是說服務能一直保證是可用的狀態,當使用者發出一個請求,服務能在有限時間內返回結果。
  • Partition Tolerance(分區容錯性)
    Partition 是指網路的分區。可以這樣理解,一般來說,關鍵的資料和服務都會位於不同的 IDC 機房。
下圖擷取自 Eric Brewer 的「Towards Robust Distributed Systems」簡報:

圖四、CAP Theorem

CAP 定理告訴我們:「一個分散式系統不可能同時滿足上述這三個需求,三個要素中最多只能同時滿足兩點」。因此,架構設計師不要把精力浪費在設計如何能同時滿足三者的完美分散式系統上,而是應該進行權衡取捨。

但是對於分散式資料系統而言,「分區容錯性」(P) 是基本要求,否則就不能稱為「分散式系統」了。因此,一般我們所說的 NoSQL DB 都是在「一致性」(C) 和「可用性」(A) 之間尋求平衡(即上圖中以紅色虛線框所標示的交集處)。

BASE 是 Basically Available、Soft state、Eventually consistent 三個片語的簡寫,是對 CAP 中 CA 的延伸:
  • Basically Available:基本可用;
  • Soft-state:軟狀態/柔性交易,即狀態可以有一段時間的不同步;
  • Eventual consistency:最終一致性;
BASE 是基於 CAP 理論逐步演化而來,核心思想是:即便不能達到「強一致性」(Strong consistency),但可以根據應用特點採用適當的方式來達到「最終一致性」(Eventual consistency)的效果。

BASE 是反 ACID 的,它完全不同於 ACID 模型,犧牲強一致性,獲得基本可用性和柔性可靠性,並要求達到最終一致性。

CAP 和 BASE 理論是 NoSQL 的理論基礎。

六、NoSQL DB 的缺點

個人以為 NoSQL DB 有以下三個缺點:

  1. 不易轉換
    不像 RDBMS 有共通的標準語言 —— SQL,各種 NoSQL 都有自己的 API。所以一旦選定某種 NoSQL 產品,便不易再轉換至其他產品,比方說由 MongoDB 轉換為 Couchbase
  2. 不支援 ACID
    ACID 可說是「Transaction」的構成要件,也是所有 RDBMS 的主要特性。但大部分的 NoSQL DB 都不保證 ACID,必須使用一些變通技巧來實現(MongoDB 可使用 2 Phase Commits)。
  3. 不支援 JOIN
    因為 NoSQL DB 是 Non-relational 的,所以不支援 JOIN 操作。以 MongoDB 而言,除了一開始就要妥善規劃 Data Model 之外(如使用 embedded document 或 reference),也可搭配 Index 和  Aggregation(含 MapReduce)等技巧來提高查詢效能。

本文對於 NoSQL 就暫時介紹到這裡囉,下面「延伸閱讀」還有許多不錯的資訊,各位也可以參考一下喔!

※ 延伸閱讀:

  1. [酷壳] 分布式系统的事务处理:
    http://coolshell.cn/articles/10910.html
  2. [Toad World] Survey distributed databases
    http://www.toadworld.com/products/toad-for-cloud-databases/w/wiki/308.survey-distributed-databases.aspx
  3. [Martin Fowloer] NoSQL
    http://martinfowler.com/nosql.html
  4. [myNoSQL] NoSQL Databases and Polyglot Persistence: A Curated Guide
    http://nosql.mypopescu.com/

2014年2月8日 星期六

VMI 與 Design Patterns

在 GoF 的《Design Patterns》一書中共提到 23 種設計模式,有 18 種模式都使用了 VMI。所以 VMI 是瞭解 Design Patterns 的重要關鍵!

本文先從繼承、覆寫、重載、多型等基本概念談起,然後說明什麼是 VMI,最後再說明有哪些 Design Patterns 使用了 VMI。

一、繼承(Inheritance)
  1. 這是物件導向語言的基本特性與威力強大之處。類別之間如果有繼承關係,只需在父類別定義好 欄位(屬性)與 方法(行為),繼承該父類別的子類別就擁有同樣的欄位與方法。
  2. 此特性可大幅減少重複程式碼。但若使用不當,繼承亦會造成擴充困難與維護不易的問題。
二、覆寫(Overriding)與重載(Overloading)
  1. 繼承同一父類別之各項子類別,在部分欄位或方法難免有些許差異,透過這兩項技巧,既可保有繼承的優點,亦能增加子類別的擴充彈性。
  2. 覆寫與重載 (Overloading) 不同,覆寫是改變方法的內容,而重載是改變方法的回傳值與參數。但兩者均不會改變方法的名稱。(「方法名稱 + 參數」即所謂的「Signature」)
以下舉例說明:

鳥類(Bird):
public class Bird {
   String name;
   public Bird() {
      this.name = "Bird";
   }
   public void eat() {
      System.out.println(this.name + " can eat.");
   }
   public void fly() {
      System.out.println(this.name + " can fly.");
   }
}
烏鴉(Crow)
public class Crow extends Bird {
   public Crow() {
      this.name = "Crow";
   }
}
鴕鳥(Ostrich):
public class Ostrich extends Bird {
   public Ostrich() {
      this.name = "Ostrich";
   }
   Public void fly() {
      system.Out.Println(this.Name + " can't fly.");
   }
}
類別圖如下:


  • 繼承(Inheritance): 鳥類(Bird)是烏鴉(Crow)和鴕鳥(Ostrich)的父類別,是「繼承」的關係。
  • 覆寫(Overriding):但因為鴕鳥不會飛,所以我們「覆寫」其 fly() 的行為。

三、多型(Polymorphism)

對不同型別的物件提供單一介面。多型提供一些適用於多種型別的操作。多型又可細分為三種:
  • Ad hoc:又稱為「重載」,有 function overloading 或 operator overloading 兩種。
  • Parametric:又稱為「泛型」(generics 或 generic programming)。
  • Subtyping:即「子類別多型」,一個父類別參考可以指向不同子類別的物件。
以父類別類型 (Bird) 宣告的參考可以指向其下所有子類別物件 ( Crow, Ostrich… ) ,這種多型稱為「Subtyping Polymorphism」,又稱為「向上轉型」 (Upcasting)。

未使用多型使用多型
Crow myCrow = new Crow();
Ostrich myOstrich = new Ostrich();
Bird myCrow = new Crow();
Bird myOstrich = new Ostrich();
  • My crow "IS A" Crow.
  • My ostrich "IS AN" Ostrich.
  • My crow "IS A" Bird.
  • My ostrich "IS A" Bird.

有了多型,我們就可以使用同一個父類別參考來走訪所有子類別物件的實例欄位(instance field)。
Bird myBird = new Crow();
System.out.println(myBird.name);
myBird = new Ostrich();
System.out.println(myBird.name);
Crow
Ostrich
四、Virtual Method Invocation
  1. Virtual Method 又稱「Virtual Function」,當從父類別中繼承的時候,虛擬函式和被繼承的函式具有相同的簽名。但是在執行時期,執行系統將根據物件的型別,自動地選擇適當的具體實作執行。VMI 也適用於介面與實作。
  2. 虛擬函式是 OOP 實作多型的基本手段,更在 Design Patterns 之中扮演相當重要的角色。
  3. 在 Java 語言中,所有的方法預設都是虛擬函式。只有以關鍵字 final 標記的方法才是非虛擬函式。
  4. C++, Java 和 C# 都支援 VMI。 
VMI 是基於「多型」與「動態分派」(Dynamic Dispatch)的。所以,當您執行以下程式碼時,實際上將會呼叫到 Orstrich 類別的 fly()方法:

Bird myOstrich = new Ostrich();
myOstrich.fly();
 
Ostrich can’t fly.
如果 Java 不支援 VMI,則在編譯時期便會將 myOstrich.fly() 連結到  Bird  類別的 fly()方法,這是靜態分派。
Bird myOstrich = new Ostrich();
myOstrich.fly();
 Bird can fly.
有了 VMI,我們也可以這樣執行所有鳥類物件的 fly() 或 eat() 方法:

List Birds = new ArrayList();
Birds.add(new Bird());
Birds.add(new Ostrich());
Birds.add(new Crow());

for (Bird b : Birds) {
   b.fly();
}
其執行結果為:
Bird can fly.
Ostrich can't fly.
Crow can fly.
五、VMI 與 Design Patterns

在 GoF 的《Design Patterns》一書中共提到 23 種設計模式,有 18 種模式都使用了 VMI。所以 VMI 是瞭解 Design Patterns 的重要關鍵!

CreationalStructuralBehavioral
  1. Factory Method
  2. Abstract Factory
  3. Builder
  4. Prototype
  5. Singleton
  1. Adapter
  2. Bridge
  3. Composite
  4. Decorator
  5. Façade
  6. Flyweight
  7. Proxy
  1. Chain of Responsibility
  2. Command
  3. Interpreter
  4. Iterator
  5. Mediator
  6. Momento
  7. Observer
  8. State
  9. Strategy
  10. Template
  11. Visitor
s






參考資料:
  1. http://stackoverflow.com/questions/11431185/what-is-the-use-of-java-virtual-method-invocation
  2. http://en.wikipedia.org/wiki/Dynamic_dispatch
  3. http://zh.wikipedia.org/wiki/虚函数_(程序语言)
  4. http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokevirtual
  5. http://msdn.microsoft.com/en-us/library/aa645767(v=vs.71).aspx
  6. https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html

2014年1月4日 星期六

IDE v.s. 程式語言

如果你問 C# 開發者:「你使用哪一套 IDE?」,我想答案應該都是 Visual Studio;如果你問 Objective-C 的開發者同樣的問題,答案應該都是 Xcode。

可是,如果你問 Java 的開發者,那得到的答案有可能是 Eclipse、NetBeans、IntelliJ IDEA,甚至是 JBuilder...等等。

IDE 對程式語言的發展與社群具有決定性的影響。我甚至覺得像 .Net 或 Objective-C 這樣只有一種 IDE 可以選擇反而是比較好的,對於該程式語言的發展、普及、社群也比較會有正面幫助。 為什麼?我的答案是「一致」。

試想在一個 Java 開發團隊裡,如果沒有強制規定大家只能使用某種 IDE,不僅開發者之間無法共享許多使用 IDE 的知識、經驗、技巧之外, 開發工具的安裝設定組態以及 plugins 也都不能通用,如果成員要進行 pair programming 更是痛苦,導致整個團隊裡的每個人浪費了過多時間在熟悉、適應、比較甚至爭論各種 IDE 的好壞。

所以,有時候選擇太多也不一定是件好事....