2016年6月5日 星期日

資料庫研究

性能测试:SequoiaDB vs. MongoDB vs. Cassandra vs. HBase

摘要:NoSQL通过弱化一部分关系型数据库特性(如一致性和关系模型)来提升其可扩展性及高可用性,弥补了关系型数据库在很多互联网类应用中的不足。因此,不同的NoSQL有着不同的杀手级应用,这里我们通过基准测试摸索。
【编者按】在《先锋》系列的 事务、高性能,王涛谈打造超越MongoDB的NoSQL一 文中,我们与王涛浅谈了高性能,拥有事务的SequoiaDB打造经验。应读者需求,从数据上解读各个NoSQL的优势,我们同时邀请了国内外相关专家对 MongoDB、SequoiaDB、Cassandra、HBase四个NoSQL进行基准测试,并公布测试用例、相关数据及测试规则。本次我们将给大 家放出国内专家的测评,仅供参考。PS:为了方便传阅,特别为大家准备了PDF版本,点击下载
下为测试资料
在本篇测试报告中,我们使用Yahoo!发布的标准YCSB测试规则,对 MongoDB、SequoiaDB、Cassandra、HBase进行对比,并尝试给出每种不同产品所适用的应用场景。在测试配置中,我们尽可能对全 部产品做到高可用配置,而在一致性级别上则使用最终一致性。
在测试中我们会对两种类型的NoSQL数据库做横向对比,包括Document-Oriented文档类数据库、以及Big-Table宽表类数据 库。由于每种类型的数据库具有很多自己独特的特性,我们不能将每种特性一一表现在该测评结果中。本测试主要针对数据库在不同任务类型下的性能指标进行,且 仅依赖YCSB所提供的标准测试流程。
本测试将详细列出测试的物理环境以及配置信息,以便于读者能够使用自己的环境独立验证结果。

测试概要

1. 测试产品
本测试主要对比两种类型的NoSQL数据库,包括四款不同的产品:


  • MongoDB(文档类,V2.6.1)
  • SequoiaDB(文档类,V1.8)
  • HBase(宽表类,V0.94.6-CDH 4.5.0)
  • Cassandra(宽表类,V1.1.12)

其中MongoDB作为当前市场占有率最高的数据库,可能是众多读者所关心的产品,提供丰富的数据库功能,号称是最接近关系型数据库的NoSQL产品;而SequoiaDB由前IBM DB2团队的研发人员创建,据称在性能和功能上能够与MongoDB做正面抗衡,同样提供很多MongoDB所提供的功能(例如分片、多索引等特性)。
HBase则是Hadoop框架的一员,也已经被广大企业和互联网用户所接受,我们使用的版本0.94.6是跟随CDH 4.5.0安装包的版本;而Cassandra则是与HBase类似的产品,由Facebook研发并进行开源,同样拥有广大的用户市场。
我们的测试使用由Yahoo!研究院发布的Yahoo Cloud Serving Benchmark (YCSB)基准测试,并将接口对各自产品的最新版进行了修改和适配。我们在正文后的附录中也提供了SequoiaDB的YCSB测试接口。
需要重新强调的是,每种不同的产品都有各自的应用场景。YCSB测试尽管是Yahoo!研究院提供的测试框架,但是在很多场景下并不能 完全发挥出每个产品各自的特点。在本测试中,我们尝试使用YCSB框架给出最为客观的评估结果。如果对于该测试结果或配置存在疑问,我们欢迎广大读者根据 自身需要重新调整,并将结果开放以供参考。
2. 测试场景
YCSB测试框架提供了丰富的场景配置机制,允许用户根据需要选择需要导入的数据量和增删改查之间相应的比例。在本测试中,我们导入一亿条数据,并对如下场景进行对比。
场景编号 场景分类 描述
1 单条记录导入 单条记录导入
2 批量记录导入 批量记录导入
3 单纯查询 100%查询
4 查询导入平衡 50%导入,50%查询
5 更新为主 95%更新,5%查询
6 查询为主 95%查询,5%更新
7 查询最新 95%查询,5%导入

对于数据导入的场景,我们对单条记录插入和批量插入两个场景进行了区分。对于一些数据库来说,默认配置会在客户端将一批记录打包并统一发送给服务器,对于这类产品,尽管其接口为单条记录操作,我们依然将其归类为批量记录导入模式。
写入和查询的数据模拟典型日志记录的长度,具有以下特性:

特性 描述
字段数 10字段
字段名长度 6字节
记录总大小 100Bytes
全部字段类型 字符串
主键长度 23字节
总记录数 1亿条
总裸数据量 大约100GB
数据副本份数 3
其中,SequoiaDB与MongoDB的分片均配置为一主两从;HBase所在的HDFS设置复制份数为3;Cassandra建表时使用参数replication_factor=2。
一致性级别上,我们使用最弱的最终一致性,读写的write concern均设置为1。
3. 测试环境
本测试中,测试环境总共包含4台Dell R520物理机作为数据存储。生成数据的YCSB程序与数据库运行在同一物理环境。
注:如使用独立服务器进行YCSB的数据生成,会导致千兆网瓶颈。
整个集群的拓扑结构如图1所示:
图1:测试集群拓扑
服务器环境。本测试数据库服务器使用4台Dell R520物理机环境,每台物理机配置如下:

类型 参数
CPU Intel(R) Xeon® CPU E5-2420 1.9GHZ (6 core)
内存 DDR3 48GB
磁盘 6块内置SATA硬盘,2TB/块
网络 千兆以太网
操作系统 Red Hat Enterprise Linux Server release 6.4
kernel-release:2.6.32-358.e16.x86_64
JDK Oracle JDK 1.6
4. 测试方法
本测试使用YCSB标准,基于四台物理机执行。对于每种不同产品的测试流程如下:

  • 安装软件
  • 基于四节点部署集群,配置时尽可能基于以下准则:

  • 高可用配置
  • 最终一致性
  • 功能与单节点环境保持一致
  • 充分利用硬件资源

  • 在四台物理机中部署YCSB集群,向本地集群写入读取数据
  • 进行数据操作时通过YCSB产生记录的统计数量
  • 根据结果生成Excel文件
  • 针对其他场景重复以上步骤

并发性方面则基于以下规则:

  • 单条记录插入每服务器24条线程
  • 批量记录插入每服务器8条线程
  • 其他所有操作每服务器36条线程

测试结果

一、 场景1:单条记录导入
图2:单条记录导入场景
在单条记录导入场景中,SequoiaDB与MongoDB使用insert方法,writeConcern设置为 Normal;HBase则设置客户端缓冲区为2KB。而在错误检验方式上,由于是单条记录插入,所以MongoDB必须在每次操作后检测返回值是否成 功,因此不可以使用异步插入方式。
在图2的结果中可以看到,单条记录导入操作SequoiaDB最高,总吞吐量可以达到每秒钟近7万。而HBase与Cassandra则比较接近,在5-6万之间。MongoDB在该场景中表现较差,总吞吐量不到每秒1万。
在该场景中,YCSB在4台服务器上各启动24条线程,总共并发量为96线程。
二、 场景2:批量记录导入
图3:批量记录导入场景
批量记录导入场景的结果见图3。在该场景中,SequoiaDB与MongoDB使用各自提供的bulk insert方法;HBase则设置client buffer为4MB;Cassandra不提供批量数据导入方式。
在该测试中,批量导入数据为每批次3000条记录,每节点启动8条线程,总数32线程。
测试结果显示,SequoiaDB可以达到每秒钟近19万的导入速度,而MongoDB则与单线程导入的性能接近(1万左右),HBase也没有本质提升。
三、 场景3:单纯查询

图4:单纯查询场景
图4显示单纯随机查询的场景。在该场景中MongoDB表现最为突出,整体吞吐量达到每秒钟8万以上。SequoiaDB和Cassandra类似,大约为MongoDB的一半,在4万至5万之间徘徊。而HBase表现最差,未达到每秒1万的指标。
该场景每台物理服务器使用36条客户端线程,总数144条线程。
四、 场景4:查询导入平衡
图5:查询导入平衡场景
该场景主要模拟50%的插入和50%的查询业务(图5)。其中插入业务使用单条记录插入。
最终的结果显示,SequoiaDB的整体表现最优,平均达到每秒钟超过14000TPS,而MongoDB/HBase/Cassandra则比较接近,各自不到10000TPS。
五、 场景5:更新为主
图6:更新为主场景
如图6所示,更新为主场景模拟95%更新与5%查询的场景。该场景中,SequoiaDB表现最优,结果介于5万到6万之间每秒。
而MongoDB表现相对较弱,大约在5千每秒左右的数量级。
六、 场景6:查询为主
图7:查询为主场景
在查询为主的场景中,模拟95%查询+5%更新。在该测试中,SequoiaDB与Cassandra的性能接近单纯查询的场景,而更新操作对MongoDB的损耗相对较大,使其性能仅不到3万每秒。
HBase在随机读为主的场景下相对较慢。
七、 场景7:查询最新
图8:查询最新场景
查询最新场景为95%读+5%插入,并且读取的数据尽可能是刚刚写入的数据。
从图8中可以看出,SequoiaDB对于刚刚写入至内存中便读取的场景性能最佳,达到近4万每秒。
而MongoDB和Cassandra则相比场景6有明显下降,HBase依然性能较低。

结论

从第三部分的各个场景对比中可以看出,SequoiaDB数据库在数据插入场景中表现最为突出,甚至超过本身以插入性能著称的Cassandra,混合读写场景下性能也可圈可点。而业界普及率最高的MongoDB则在单纯读取性能上最为抢眼,远超其他。
HBase与Cassandra虽然在写入性能上远高于MongoDB,但是和SequoiaDB相比仍然逊色一筹;而在主键随机 读操作方面,Cassandra的新版本和之前的版本比起来性能大幅度上升,基本做到和MongoDB处于同一水平线,而HBase则远不能和其他产品相 比。
当然,这些比较也仅仅局限于YCSB所做的测试,而文档类数据库能够提供的二级索引等机制并非是YCSB所测试的。因此,文档类数据库能够提供比宽表类数据库更多的应用场景。
如此看来,对于宽表类数据库来说,如果在其最有优势的主场都败给了文档类数据库,这是否意味着,HBase和Cassandra最大的优势已经不再,文档类数据库会在各个领域的性能表现超越宽表呢?

資料庫使用量排名
http://db-engines.com/en/ranking
2000萬筆壓力測試
http://www.our-program.com.tw/taka/demo/sql_2000_test.php

Javascript程式碼重新排版








若是遇到很長很複雜的JS文件可以先用程式碼重新排版
推薦兩個網站
http://jsbeautifier.org/

http://unminify.com/

若是習慣使用chrome瀏覽器也可以使用以下方法
chrome >F12>sources>選擇一個JS文件>{}










何謂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 中 C和 A 的延伸:
  • 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/

getUserMedia with the Web Audio API

Introduction

Audio/Video capture has been the "Holy Grail" of web development for a long time. For many years we've had to rely on browser plugins (Flash or Silverlight) to get the job done. Come on!
HTML5 to the rescue. It might not be apparent, but the rise of HTML5 has brought a surge of access to device hardware. Geolocation (GPS), the Orientation API(accelerometer), WebGL (GPU), and the Web Audio API (audio hardware) are perfect examples. These features are ridiculously powerful, exposing high level JavaScript APIs that sit on top of the system's underlying hardware capabilities.
This tutorial introduces a new API, navigator.getUserMedia(), which allows web apps to access a user's camera and microphone.

The road to getUserMedia()

If you're not aware of its history, the way we arrived at the getUserMedia() API is an interesting tale.
Several variants of "Media Capture APIs" have evolved over the past few years. Many folks recognized the need to be able to access native devices on the web, but that led everyone and their mom to put together a new spec. Things got so messy that the W3C finally decided to form a working group. Their sole purpose? Make sense of the madness! The Device APIs Policy (DAP) Working Group has been tasked to consolidate + standardize the plethora of proposals.
I'll try to summarize what happened in 2011...

Round 1: HTML Media Capture

HTML Media Capture was the DAP's first go at standardizing media capture on the web. It works by overloading the <input type="file"> and adding new values for the accept parameter.
If you wanted to let users take a snapshot of themselves with the webcam, that's possible with capture=camera:
<input type="file" accept="image/*;capture=camera">
Recording a video or audio is similar:
<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">
Kinda nice right? I particularly like that it reuses a file input. Semantically, it makes a lot of sense. Where this particular "API" falls short is the ability to do realtime effects (e.g. render live webcam data to a <canvas> and apply WebGL filters). HTML Media Capture only allows you to record a media file or take a snapshot in time.
Support:
  • Android 3.0 browser - one of the first implementations. Check out this video to see it in action.
  • Chrome for Android (0.16)
  • Firefox Mobile 10.0
  • iOS6 Safari and Chrome (partial support)

Round 2: device element

Many thought HTML Media Capture was too limiting, so a new spec emerged that supported any type of (future) device. Not surprisingly, the design called for a new element, the <device> element, which became the predecessor togetUserMedia().
Opera was among the first browsers to create initial implementations of video capture based on the <device> element. Soon after (the same day to be precise), the WhatWG decided to scrap the <device> tag in favor of another up and comer, this time a JavaScript API called navigator.getUserMedia(). A week later, Opera put out new builds that included support for the updated getUserMedia()spec. Later that year, Microsoft joined the party by releasing a Lab for IE9supporting the new spec.
Here's what <device> would have looked like:
<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>
  function update(stream) {
    document.querySelector('video').src = stream.url;
  }
</script>
Support:
Unfortunately, no released browser ever included <device>. One less API to worry about I guess :) <device> did have two great things going for it though: 1.) it was semantic, and 2.) it was easily extendible to support more than just audio/video devices.
Take a breath. This stuff moves fast!

Round 3: WebRTC

The <device> element eventually went the way of the Dodo.
The pace to find a suitable capture API accelerated thanks to the larger WebRTC(Web Real Time Communications) effort. That spec is overseen by the W3C WebRTC Working Group. Google, Opera, Mozilla, and a few others have implementations.
getUserMedia() is related to WebRTC because it's the gateway into that set of APIs. It provides the means to access the user's local camera/microphone stream.
Support:
getUserMedia() has been supported since Chrome 21, Opera 18, and Firefox 17.

Getting started

With navigator.getUserMedia(), we can finally tap into webcam and microphone input without a plugin. Camera access is now a call away, not an install away. It's baked directly into the browser. Excited yet?

Feature detection

Feature detecting is a simple check for the existence ofnavigator.getUserMedia:
function hasGetUserMedia() {
  return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia || navigator.msGetUserMedia);
}

if (hasGetUserMedia()) {
  // Good to go!
} else {
  alert('getUserMedia() is not supported in your browser');
}
You can also use Modernizr to detect getUserMedia to avoid the vendor prefix dance yourself:
if (Modernizr.getusermedia){
  var gUM = Modernizr.prefixed('getUserMedia', navigator);
  gUM({video: true}, function( //...
  //...
}

Gaining access to an input device

To use the webcam or microphone, we need to request permission. The first parameter to getUserMedia() is an object specifying the details and requirements for each type of media you want to access. For example, if you want to access the webcam, the first parameter should be {video: true}. To use both the microphone and camera, pass {video: true, audio: true}:
<video autoplay></video>

<script>
  var errorCallback = function(e) {
    console.log('Reeeejected!', e);
  };

  // Not showing vendor prefixes.
  navigator.getUserMedia({video: true, audio: true}, function(localMediaStream) {
    var video = document.querySelector('video');
    video.src = window.URL.createObjectURL(localMediaStream);

    // Note: onloadedmetadata doesn't fire in Chrome when using it with getUserMedia.
    // See crbug.com/110938.
    video.onloadedmetadata = function(e) {
      // Ready to go. Do some stuff.
    };
  }, errorCallback);
</script>
OK. So what's going on here? Media capture is a perfect example of new HTML5 APIs working together. It works in conjunction with our other HTML5 buddies,<audio> and <video>. Notice that we're not setting a src attribute or including<source> elements on the <video> element. Instead of feeding the video a URL to a media file, we're feeding it a Blob URL obtained from a LocalMediaStreamobject representing the webcam.
I'm also telling the <video> to autoplay, otherwise it would be frozen on the first frame. Adding controls also works as you'd expected.
If you want something that works cross-browser, try this:
navigator.getUserMedia  = navigator.getUserMedia ||
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia ||
                          navigator.msGetUserMedia;

var video = document.querySelector('video');

if (navigator.getUserMedia) {
  navigator.getUserMedia({audio: true, video: true}, function(stream) {
    video.src = window.URL.createObjectURL(stream);
  }, errorCallback);
} else {
  video.src = 'somevideo.webm'; // fallback.
}

Setting media constraints (resolution, height, width)

The first parameter to getUserMedia() can also be used to specify more requirements (or constraints) on the returned media stream. For example, instead of just indicating you want basic access to video (e.g. {vide: true}), you can additionally require the stream to be HD:
var hdConstraints = {
  video: {
    mandatory: {
      minWidth: 1280,
      minHeight: 720
    }
  }
};

navigator.getUserMedia(hdConstraints, successCallback, errorCallback);

...

var vgaConstraints = {
  video: {
    mandatory: {
      maxWidth: 640,
      maxHeight: 360
    }
  }
};

navigator.getUserMedia(vgaConstraints, successCallback, errorCallback);
For more configurations, see the constraints API

Selecting a media source

In Chrome 30 or later, getUserMedia() also supports selecting the the video/audio source using the MediaStreamTrack.getSources() API.
In this example, the last microphone and camera that's found is selected as the media stream source:
MediaStreamTrack.getSources(function(sourceInfos) {
  var audioSource = null;
  var videoSource = null;

  for (var i = 0; i != sourceInfos.length; ++i) {
    var sourceInfo = sourceInfos[i];
    if (sourceInfo.kind === 'audio') {
      console.log(sourceInfo.id, sourceInfo.label || 'microphone');

      audioSource = sourceInfo.id;
    } else if (sourceInfo.kind === 'video') {
      console.log(sourceInfo.id, sourceInfo.label || 'camera');

      videoSource = sourceInfo.id;
    } else {
      console.log('Some other kind of source: ', sourceInfo);
    }
  }

  sourceSelected(audioSource, videoSource);
});

function sourceSelected(audioSource, videoSource) {
  var constraints = {
    audio: {
      optional: [{sourceId: audioSource}]
    },
    video: {
      optional: [{sourceId: videoSource}]
    }
  };

  navigator.getUserMedia(constraints, successCallback, errorCallback);
}
Check out Sam Dutton's great demo of how to let users select the media source.

Security

Some browsers throw up an infobar upon calling getUserMedia(), which gives users the option to grant or deny access to their camera/mic. The spec unfortunately is very quiet when it comes to security. For example, here is Chrome's permission dialog:
Permission dialog in Chrome
Permission dialog in Chrome
If your app is running from SSL (https://), this permission will be persistent. That is, users won't have to grant/deny access every time.

Providing fallback

For users that don't have support for getUserMedia(), one option is to fallback to an existing video file if the API isn't supported and/or the call fails for some reason:
// Not showing vendor prefixes or code that works cross-browser:

function fallback(e) {
  video.src = 'fallbackvideo.webm';
}

function success(stream) {
  video.src = window.URL.createObjectURL(stream);
}

if (!navigator.getUserMedia) {
  fallback();
} else {
  navigator.getUserMedia({video: true}, success, fallback);
}

Basic demo

 

Taking screenshots

The <canvas> API's ctx.drawImage(video, 0, 0) method makes it trivial to draw <video> frames to <canvas>. Of course, now that we have video input viagetUserMedia(), it's just as easy to create a photo booth application with realtime video:
<video autoplay></video>
<img src="">
<canvas style="display:none;"></canvas>

<script>
  var video = document.querySelector('video');
  var canvas = document.querySelector('canvas');
  var ctx = canvas.getContext('2d');
  var localMediaStream = null;

  function snapshot() {
    if (localMediaStream) {
      ctx.drawImage(video, 0, 0);
      // "image/webp" works in Chrome.
      // Other browsers will fall back to image/png.
      document.querySelector('img').src = canvas.toDataURL('image/webp');
    }
  }

  video.addEventListener('click', snapshot, false);

  // Not showing vendor prefixes or code that works cross-browser.
  navigator.getUserMedia({video: true}, function(stream) {
    video.src = window.URL.createObjectURL(stream);
    localMediaStream = stream;
  }, errorCallback);
</script>
 
 

Applying Effects

CSS Filters

Using CSS Filters, we can apply some gnarly effects to the <video> as it is captured:
<style>
video {
  width: 307px;
  height: 250px;
  background: rgba(255,255,255,0.5);
  border: 1px solid #ccc;
}
.grayscale {
  +filter: grayscale(1);
}
.sepia {
  +filter: sepia(1);
}
.blur {
  +filter: blur(3px);
}
...
</style>

<video autoplay></video>

<script>
var idx = 0;
var filters = ['grayscale', 'sepia', 'blur', 'brightness',
               'contrast', 'hue-rotate', 'hue-rotate2',
               'hue-rotate3', 'saturate', 'invert', ''];

function changeFilter(e) {
  var el = e.target;
  el.className = '';
  var effect = filters[idx++ % filters.length]; // loop through filters.
  if (effect) {
    el.classList.add(effect);
  }
}

document.querySelector('video').addEventListener(
    'click', changeFilter, false);
</script>
Click the video to cycle through CSS filters
 

WebGL Textures

One amazing use case for video capture is to render live input as a WebGL texture. Since I know absolutely nothing about WebGL (other than it's sweet), I'm going to suggest you give Jerome Etienne's tutorial and demo a look. It talks about how to use getUserMedia() and Three.js to render live video into WebGL.

Using getUserMedia with the Web Audio API

One of my dreams is to build AutoTune in the browser with nothing more than open web technology!
Chrome supports live microphone input from getUserMedia() to the Web Audio API for real-time effects. Piping microphone input to the Web Audio API looks like this:
window.AudioContext = window.AudioContext ||
                      window.webkitAudioContext;

var context = new AudioContext();

navigator.getUserMedia({audio: true}, function(stream) {
  var microphone = context.createMediaStreamSource(stream);
  var filter = context.createBiquadFilter();

  // microphone -> filter -> destination.
  microphone.connect(filter);
  filter.connect(context.destination);
}, errorCallback);
Demos:
For more information, see Chris Wilson's post.

Conclusion

In general, device access on the web has been a tough cookie to crack. Manypeople have tried, few have succeeded. Most of the early ideas have never taken hold outside of a proprietary environment nor have they gained widespread adoption.
The real problem is that the web's security model is very different from the native world. For example, I probably don't want every Joe Shmoe web site to have random access to my video camera. It's a tough problem to get right.
Bridging frameworks like PhoneGap have helped push the boundary, but they're only a start and a temporary solution to an underlying problem. To make web apps competitive to their desktop counterparts, we need access to native devices.
getUserMedia() is but the first wave of access to new types of devices. I hope we'll continue to see more in the very near future!

Additional resources

Demos