“NOSQL” 杂谈

引言:

 nosql 的兴起和革命,在我看来已经开始逐渐影响到了传统的sql的地位,可是仅仅是影响而已,取代是不太可能的。javascript

 

 


 

正文:

两年前,一个偶然的机会开始接触到 nosql ( mongodb )。用来做数据挖掘的存储容器,第一次接触到nosql,真的被它惊艳到了。鄙人受到传统的SQL的思惟定势,甚至一时间难以接受。java

mongodb是一个非关系型文档数据库,很是适合文档类型的数据的存储,查询也十分方便,支持动态的横向和纵向的数据扩展。爱不释手。下个用几行shell来展现一下mongodb的魅力mysql

 

 

show dbs;

//无则会建立
use mydb;


show collections;


//新建集合,至关于mysql中的表
db.createCollection('mycollection');

//插入数据.
db.mycollection.insert({'username':'chenqimiao','age':23})

db.mycollection.insert({'username':'cqm','age':23,'sex':'男'})

//查询
db.mycollection.find({"age":23});

 

 

类比mysql的话,最大的区别可能在于表结构或者说集合结构的定义了,mysql的列是预约义的,而mongodb是在插入数据的时候才肯定这条数据的列。redis

 

因此mongodb能够支持动态扩展列,在mongo中可能不叫列,要叫做域(field)吧。算法

 

 


 

 

后来花了一点时间了解了一下 HBase , Habase   诞生于 Hadoop的子项目,受大数据的遗传。单表能够很是的大,一样Habase也是基于列的。sql

 

 

印象中HBase 中有一个很是特别的特性,HBase 的数据覆盖,并非实际的覆盖。HBase 有一个时间维度的概念,全部的数据都是基于这个维度进行存储的,mongodb

简单点说,一样的key  可能在HBase 中存在两个value。它是怎么作到的?由于它给每一条记录都偷偷记录了一个timestamp,每次你去覆盖键值对的时候,你觉得你已经删除了旧值,替换成了新shell

值,而实际上只是再添加了一条记录而已,两条记录共存在一个时间维度上。每次get(key)默认取最新的一个value,仅此而已。数据库

 

你还能够手动设置失效时间TTL,这样每个值就会有一个有效期,过了有效期都值是不能get出来了,可是值仍是存储在HBase中并未丢失。缓存

 

 

 

 


 

 

 

再后来接触到了 redis ,相信你们对这个都至关的熟悉,基于内存的缓存数据库,简单的set()  get()就能够了缓存一些常用到的值,以前我也专门介绍过 redis的安装,shell命令,多实例部署,读写分离,主从复制,哨兵 等等问题。

 

 

 

当数据超过必定量 , redis会把数据swap到文件中去,若是使用到swap中的文件的值,redis会把文件在swap到内存中,进行读写,十分智能。支持的数据类型也比较多 ,除了k-v 还有hset ,hash  ,zset等等

 

 

 

 

 


 

 

 

最近在作在线课堂,用到了 Memcache ,这个东西基本和redis的使用场景类似,基于内存的nosql。可是支持的数据类型只有k-v的形式。这是不一样于redis的一点。

其二的话, Memcache 不支持文件持久化。

其三, memcache 的多实例,是基于客户端的,这个比较有意思要好好聊一聊了,象咱们日常接触的mysql,redis,多实例同步基本是读写分离,主从复制,主机写,从机读,这样的模式。能够说是基于服务端的多实例方案。可是 memcache 有点好玩了,它的多实例之间不进行同步,那它是怎么作到负载均衡的时候保证数据的完整性呢?

 

说到这里,我想先介绍一下memcache的主流的客户端程序(JAVA)

  • 官方提供的基于传统阻塞io由Greg Whalin维护的客户端  

     较早推出的客户端,稳定,持久运行。

 

  • Dustin Sallings实现的基于java nio的Spymemcached  

    A simple, asynchronous, single-threaded memcached client written in java. 支持异步,单线程的memcached客户端,用到了java1.5版本的concurrent和nio,存取速度会高于前者,可是稳定性很差,测试中常 报timeOut等相关异常。   

  • XMemcache

           Memcached一样是基于java nio的客户端,java nio相比于传统阻塞io模型来讲,有效率高(特别在高并发下)和资源耗费相对较少的优势。传统阻塞IO为了提升效率,须要建立必定数量的链接造成链接 池,而nio仅须要一个链接便可(固然,nio也是能够作池化处理),相对来讲减小了线程建立和切换的开销,这一点在高并发下特别明显。所以 XMemcached与Spymemcached在性能都很是优秀,在某些方面(存储的数据比较小的状况下)Xmemcached比 Spymemcached的表现更为优秀,具体能够看这个Java Memcached Clients Benchmark。 

 

 

根据上面的介绍,大概能够了解到,官方提供的是阻塞的客户端,要利用线程池来实现并发,可是官方提供的包还有一个很是致命的问题,不提供 CAS 的同步功能。

什么是 CAS ?

了解过java下面的 java.util.concurrent.atomic; 下面的类的同窗应该知道, CAS (check and swap),这是一种乐观锁的实现,程序陷入一个循环,获得旧值,执行CAS方法,传入旧值,新值,若旧值未发生变化 ,则用旧值,换出新值。

while(true){
    
     Object oldValue = atomicObject.get("key1") ;

     Object newValue = new Object();
  
     Object value  =   checkAndSwap("key1",oldValue,newValue) ;


     if(value!=null&&oldValue.equals(value))  

           break;
     
}

 

 

解释完 CAS ,回到刚才的问题,为何没有实现 CAS ,是官方包一个致命的弱点,明白了 CAS 原理的同窗,应该发现其实它就是一个同步的手段,那为何不能使用 syncronized 的。那是由于数据并发发生在不一样项目里面,没有办法给多个项目以前共用一个 syncronized 。这个时候只能利用memcache提供的锁,利用 CAS 做为同步手段。

庆幸spyMemcache和xmemcache都提供了 CAS 的操做。

 

那么问题来了,刚刚最先提出的问题如何解答?( CAS 多实例同步问题。)其实啊memcache根本不须要进行多实例同步,它的多实例是依赖于客户端程序实现的。

好比spymemcache:

 para.memcache.server=192.168.202.121:11211,192.168.202.121:11210 配置两个server便可。其他的操做和操做一个memcache是一摸同样的,客户端会根据Hash散列算法( HashMap 的实现算法)将键值对放到对应的 memcache 中,因为算法一致性,因此存取双方都能得知键值在哪个 memcache 中。这样就实现了多实例了。

 

 另外spymemcache客户端还有一个比较厉害的地方,它能直接将java对象序列化,做为k-v中的v,get(k)的时候自动反序列化成对象,无需直接操做JSONObject,固然前提是对象实现

 Serializable 接口,并给定一个 serialVersionUID 。redis也能够直接存储二进制文件,可是官方提供的客户端程序,并无封装好序列化和反序列化,须要本身实现。


 

 

说了这么多nosql,好像传统sql无用武之地通常。其实传统的sql才是最稳定的,适用面积最广,最安全,而且提供了事务回滚,保证数据一致性,这是nosql为了提升速度,加强扩展性,所要面临的一部分舍弃。

相关文章
相关标签/搜索