像MongoDB, Cassandra, HBase, DynamoDB, 和
目前创新互联公司已为1000多家的企业提供了网站建设、域名、虚拟空间、成都网站托管、企业网站设计、温江网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
Riak这些NoSQL缺乏传统的原子事务机制,所谓原子事务机制是可以保证一系列写操作要么全部完成,要么全部不会完成,不会发生只完成一系列中一两个
写操作;因为数据库不提供这种事务机制支持,开发者需要自己编写代码来确保一系列写操作的事务机制,比较复杂和测试。
这些NoSQL数据库不提供事务机制原因在于其分布式特点,一系列写操作中访问的数据可能位于不同的分区服务器,这样的事务就变成分布式事务,在分
布式事务中实现原子性需要彼此协调,而协调是耗费时间的,每台机器在一个大事务过程中必须依次确认,这就需要一种协议确保一个事务中没有任何一台机器写操
作失败。
这种协调是昂贵的,会增加延迟时间,关键问题是,当协调没有完成时,其他操作是不能读取事务中写操作结果的,这是因为事务的all-or-
nothing原理导致,万一协调过程发现某个写操作不能完成,那么需要将其他写操作成功的进行回滚。针对分布式事务的分布式协调对整体数据库性能有严重
影响,不只是吞吐量还包括延迟时间,这样大部分NoSQL数据库因为性能问题就选择不提供分布式事务。
MongoDB, Riak, HBase, 和 Cassandra提供基于单一键的事务,这是因为所有信息都和一个键key有关,这个键是存储在单个服务器上,这样基于单键的事务不会带来复杂的分布式协调。
那么看来扩展性性能和分布式事务是一对矛盾,总要有取舍?实际上是不完全是,现在完全有可能提供高扩展的性能同时提供分布式原子事务。
FIT是这样一个在分布式系统提供原子事务的策略,在fairness公平性, isolation隔离性, 和throughput吞吐量(简称FIT)可以权衡。
一个支持分布式事务的可伸缩分布式系统能够完成这三个属性中两个,公平是事务之间不会相互影响造成延迟;隔离性提供一种幻觉好像整个数据库只有它自
己一个事务,隔离性保证当任何同时发生的事务发生冲突时,能够保证彼此能看到彼此的写操作结果,因此减轻了程序员为避免事务读写冲突的强逻辑推理要求;吞
吐量是指每单元时间数据库能够并发处理多少事务。
FIT是如下进行权衡:
保证公平性fairness 和隔离性isolation, 但是牺牲吞吐量
保证公平性fairness和吞吐量, 牺牲隔离性isolation
保证隔离性isolation和吞吐量throughput, 但是牺牲公平性fairness.
牺牲公平性:放弃公平性,数据库能有更多机会降低分布式事务的成本,主要成本是分布式协调带来的,也就是说,不需要在每个事务过程内对每个机器都依
次确认事务完成,这样排队式的确认commit事务是很浪费时间的,放弃公平性,意味着可以在事务外面进行协调,这样就只是增加了协调时间,不会增加互相
冲突事务因为彼此冲突而不能运行所耽搁的时间,当系统不需要公平性时,需要根据事务的优先级或延迟等标准进行指定先后执行顺序,这样就能够获得很好的吞吐
量。
G-Store是一种放弃公平性的 Isolation-Throughput
的分布式key-value存储,支持多键事务(multi-key transactions),MongoDB 和
HBase在键key在同样分区上也支持多键事务,但是不支持跨分区的事务。
总之:传统分布式事务性能不佳的原因是确保原子性(分布式协调)和隔离性同时重叠,创建一个高吞吐量分布式事务的关键是分离这两种关注,这种分离原
子性和隔离性的视角将导致两种类型的系统,第一种选择是弱隔离性能让冲突事务并行执行和确认提交;第二个选择重新排序原子性和隔离性机制保证它们不会某个
时间重叠,这是一种放弃公平的事务执行,所谓放弃公平就是不再同时照顾原子性和隔离性了,有所倾斜,放弃高标准道德要求就会带来高自由高效率。
NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
虽然NoSQL流行语火起来才短短一年的时间,但是不可否认,现在已经开始了第二代运动。尽管早期的堆栈代码只能算是一种实验,然而现在的系统已经更加的成熟、稳定。不过现在也面临着一个严酷的事实:技术越来越成熟——以至于原来很好的NoSQL数据存储不得不进行重写,也有少数人认为这就是所谓的2.0版本。这里列出一些比较知名的工具,可以为大数据建立快速、可扩展的存储库。
NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。
对于NoSQL并没有一个明确的范围和定义,但是他们都普遍存在下面一些共同特征:
不需要预定义模式:不需要事先定义数据模式,预定义表结构。数据中的每条记录都可能有不同的属性和格式。当插入数据时,并不需要预先定义它们的模式。
无共享架构:相对于将所有数据存储的存储区域网络中的全共享架构。NoSQL往往将数据划分后存储在各个本地服务器上。因为从本地磁盘读取数据的性能往往好于通过网络传输读取数据的性能,从而提高了系统的性能。
弹性可扩展:可以在系统运行的时候,动态增加或者删除结点。不需要停机维护,数据可以自动迁移。
分区:相对于将数据存放于同一个节点,NoSQL数据库需要将数据进行分区,将记录分散在多个节点上面。并且通常分区的同时还要做复制。这样既提高了并行性能,又能保证没有单点失效的问题。
异步复制:和RAID存储系统不同的是,NoSQL中的复制,往往是基于日志的异步复制。这样,数据就可以尽快地写入一个节点,而不会被网络传输引起迟延。缺点是并不总是能保证一致性,这样的方式在出现故障的时候,可能会丢失少量的数据。
BASE:相对于事务严格的ACID特性,NoSQL数据库保证的是BASE特性。BASE是最终一致性和软事务。
NoSQL数据库并没有一个统一的架构,两种NoSQL数据库之间的不同,甚至远远超过两种关系型数据库的不同。可以说,NoSQL各有所长,成功的NoSQL必然特别适用于某些场合或者某些应用,在这些场合中会远远胜过关系型数据库和其他的NoSQL。
select ID=Dept_ID,Name=Dept_Name
from (
select *,flag=0 from d_dept
union all
select *,1 from d_unit) k
order by left(Dept_ID,3) asc,flag asc,Dept_ID asc
首先通过
select *,flag=0 from d_dept
union all
select *,1 from d_unit
将所有内容合并在一起 这样合一起是乱序的
然后将它作为临时表
from (
select *,flag=0 from d_dept
union all
select *,1 from d_unit) k
注意这里我加个了个FLAG字段 是为了标志0为部门 1为单位 为之后排序做准备
然后利用这个临时表 我进行排序 看下面
select ID=Dept_ID,Name=Dept_Name
这句的意思 理解的吧 选取临时结果集的2个字段,注意这里的Dept_ID和Dept_Name分别语句包含了unit_ID 和unit_Name(这个自己执行下临时结果集就知道了)
我们重点来说排序
order by left(Dept_ID,3) asc,flag asc,Dept_ID asc
先看第一个left(Dept_ID,3) 首先要进行部门排序的 我们是以左边三个符号位排序信息的 排出来就是
001
001001
..
002
..
003
003...
上面的排序不保证每个部门里面的排序时按照部门号先 然后再改部门的单位的顺序 所以加上flag asc
在每组里面 要让部门号先 通过FLAG=0 将部门号放在了前面
所以这里出来:
001
001001
..
002
..
003
003...
请看 在001号部门里面 001 肯定在 001XXX前面了
但是这排序不能保证 001XXX 001XXY这样的单位号排序 就是加上
Dept_ID asc 明白了吧
文档数据库
源起:受Lotus Notes启发。
数据模型:包含了key-value的文档集合
例子:CouchDB, MongoDB
优点:数据模型自然,编程友好,快速开发,web友好,CRUD。
图数据库
源起: 欧拉和图理论。
数据模型:节点和关系,也可处理键值对。
例子:AllegroGraph, InfoGrid, Neo4j
优点:解决复杂的图问题。
关系数据库
源起: E. F. Codd 在A Relational Model of Data for Large Shared Data Banks提出的
数据模型:各种关系
例子:VoltDB, Clustrix, MySQL
优点:高性能、可扩展的OLTP,支持SQL,物化视图,支持事务,编程友好。
对象数据库
源起:图数据库研究
数据模型:对象
例子:Objectivity, Gemstone
优点:复杂对象模型,快速键值访问,键功能访问,以及图数据库的优点。
Key-Value数据库
源起:Amazon的论文 Dynamo 和 Distributed HashTables。
数据模型:键值对
例子:Membase, Riak
优点:处理大量数据,快速处理大量读写请求。编程友好。
BigTable类型数据库
源起:Google的论文 BigTable。
数据模型:列簇,每一行在理论上都是不同的
例子:HBase, Hypertable, Cassandra
优点:处理大量数据,应对极高写负载,高可用,支持跨数据中心, MapReduce。
数据结构服务
源起: ?
数据模型:字典操作,lists, sets和字符串值
例子:Redis
优点:不同于以前的任何数据库
网格数据库
源起:数据网格和元组空间研究。
数据模型:基于空间的架构
例子:GigaSpaces, Coherence
优点:适于事务处理的高性能和高扩展性
下文例子中演示了如何插入、获取、删除一条记录
LevelDB 简介
一、LevelDB入门
LevelDB是Google开源的持久化KV单机数据库,具有很高的随机写,顺序读/写性能,但是随机读的性能很一般,也就是说,LevelDB很适合应用在查询较少,而写很多的场景。LevelDB应用了LSM (Log Structured Merge) 策略,lsm_tree对索引变更进行延迟及批量处理,并通过一种类似于归并排序的方式高效地将更新迁移到磁盘,降低索引插入开销,关于LSM,本文在后面也会简单提及。
根据LevelDB官方网站的描述,LevelDB的特点和限制如下:
特点:
1、key和value都是任意长度的字节数组;
2、entry(即一条K-V记录)默认是按照key的字典顺序存储的,当然开发者也可以重载这个排序函数;
3、提供的基本操作接口:Put()、Delete()、Get()、Batch();
4、支持批量操作以原子操作进行;
5、可以创建数据全景的snapshot(快照),并允许在快照中查找数据;
6、可以通过前向(或后向)迭代器遍历数据(迭代器会隐含的创建一个snapshot);
7、自动使用Snappy压缩数据;
8、可移植性;
限制:
1、非关系型数据模型(NoSQL),不支持sql语句,也不支持索引;
2、一次只允许一个进程访问一个特定的数据库;
3、没有内置的C/S架构,但开发者可以使用LevelDB库自己封装一个server;
LevelDB本身只是一个lib库,在源码目录make编译即可,然后在我们的应用程序里面可以直接include leveldb/include/db.h头文件,该头文件有几个基本的数据库操作接口,下面是一个测试例子:
#include iostream
#include string
#include assert.h
#include "leveldb/db.h"
using namespace std;
int main(void)
{
leveldb::DB *db;
leveldb::Options options;
options.create_if_missing = true;
// open
leveldb::Status status = leveldb::DB::Open(options,"/tmp/testdb", db);
assert(status.ok());
string key = "name";
string value = "chenqi";
// write
status = db-Put(leveldb::WriteOptions(), key, value);
assert(status.ok());
// read
status = db-Get(leveldb::ReadOptions(), key, value);
assert(status.ok());
coutvalueendl;
// delete
status = db-Delete(leveldb::WriteOptions(), key);
assert(status.ok());
status = db-Get(leveldb::ReadOptions(),key, value);
if(!status.ok()) {
cerrkey" "status.ToString()endl;
} else {
coutkey"==="valueendl;
}
// close
delete db;
return 0;
}
上面的例子演示了如何插入、获取、删除一条记录,编译代码:
g++ -o test test.cpp libleveldb.a -lpthread -Iinclude
执行./test后,会在/tmp下面生成一个目录testdb,里面包含若干文件:
------------------------------------------------------------
LevelDB是google开源的一个key-value存储引擎库,类似于开源的Lucene索引库一样。其他的软件开发者可以利用该库做二次开发,来满足定制需求。LevelDB采用日志式的写方式来提高写性能,但是牺牲了部分读性能。为了弥补牺牲了的读性能,一些人提议使用SSD作为存储介质。
对于本地化的Key-value存储引擎来说,简单的使用一般都分成三个基本的步骤:(1)打开一个数据库实例;(2)对这个数据库实例进行插入,修改和查询操作;(3)最后在使用完成之后,关闭该数据库。下面将详细讨论该三个步骤:
一、打开一个数据库实例
一个leveldb数据库有一个对应一个文件系统目录的名字。该数据库的所有内容都存储在这个目录下。下面的代码描述了怎样打开一个数据库或者建立一个新的数据库。
#include assert.h
#include "leveldb/db.h"
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options,"/tmp/testdb", db);
assert(status.ok());
如果打开已存在数据库的时候,需要抛出错误。将以下代码插在leveldb::DB::Open方法前面:
options.error_if_exists = true;
二、对数据库的简单读、写操作
LevelDB提供了Put,Delete和Get三个方法对数据库进行修改和查询。例如,下面的代码片段描述了怎样将key1对应的value值,移到key2对应的值。
std::string value;
leveldb::Status s = db-Get(leveldb::ReadOptions(), key1, value);
if(s.ok()) s = db-Put(leveldb::WriteOptions(), key2, value);
if(s.ok()) s = db-Delete(leveldb::WriteOptions(), key1);
三、关闭数据库
在对数据库进行了一系列的操作之后,需要对数据库进行关闭。该操作比较简单:
... open the db as described above...
... do something with db ...
delete db;
上面对levelDB的简单使用做了基本的介绍,接下来就是如何自己写一个完成并且能运行的例子。
1、下载源码 git clone
2、编译源码 cd leveldb make all
3、编写test.cpp
#include assert.h
#include string.h
#include leveldb/db.h
#include iostream
int main(){
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options,"/tmp/testdb", db);
assert(status.ok());
//write key1,value1
std::string key="key";
std::string value = "value";
status = db-Put(leveldb::WriteOptions(), key,value);
assert(status.ok());
status = db-Get(leveldb::ReadOptions(), key, value);
assert(status.ok());
std::coutvaluestd::endl;
std::string key2 = "key2";
//move the value under key to key2
status = db-Put(leveldb::WriteOptions(),key2,value);
assert(status.ok());
status = db-Delete(leveldb::WriteOptions(), key);
assert(status.ok());
status = db-Get(leveldb::ReadOptions(),key2, value);
assert(status.ok());
std::coutkey2"==="valuestd::endl;
status = db-Get(leveldb::ReadOptions(),key, value);
if(!status.ok()) std::cerrkey" "status.ToString()std::endl;
else std::coutkey"==="valuestd::endl;
delete db;
return 0;
}
4、编译链接 g++ -o test test.cpp ../leveldb/libleveldb.a -lpthread -I../leveldb/include
注意libleveldb.a 和leveldb include的路径。
5、运行结果./test:
value
key2===value
key NotFound: