缓存数据库介绍


NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库,随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。

NoSQL数据库的四大分类

键值(Key-Value)存储数据库

这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署。但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。[3]

 

列存储数据库。

这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。如:Cassandra, HBase, Riak.

 

文档型数据库

文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。

 

图形(Graph)数据库

图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。[2]

因此,我们总结NoSQL数据库在以下的这几种情况下比较适用:1、数据模型比较简单;2、需要灵活性更强的IT系统;3、对数据库性能要求较高;4、不需要高度的数据一致性;5、对于给定key,比较容易映射复杂值的环境。

 

NoSQL数据库的四大分类表格分析

分类

Examples举例

典型应用场景

数据模型

优点

缺点

键值(key-value)[3]

Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB

内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。[3]

Key 指向 Value 的键值对,通常用hash table来实现[3]

查找速度快

数据无结构化,通常只被当作字符串或者二进制数据[3]

列存储数据库[3]

Cassandra, HBase, Riak

分布式的文件系统

以列簇式存储,将同一列数据存在一起

查找速度快,可扩展性强,更容易进行分布式扩展

功能相对局限

文档型数据库[3]

CouchDB, MongoDb

Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容)

Key-Value对应的键值对,Value为结构化数据

数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构

查询性能不高,而且缺乏统一的查询语法。

图形(Graph)数据库[3]

Neo4J, InfoGrid, Infinite Graph

社交网络,推荐系统等。专注于构建关系图谱

图结构

利用图结构相关算法。比如最短路径寻址,N度关系查找等

很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案。[3] 


 redis


 

介绍

redis是业界主流的key-value nosql 数据库之一。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis优点

  • 异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。
  • 支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。这使得在应用中很容易解决的各种问题,因为我们知道哪些问题处理使用哪种数据类型更好解决。
  • 操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。
  • MultiUtility工具:Redis是一个多功能实用工具,可以在很多如:缓存,消息传递队列中使用(Redis原生支持发布/订阅),在应用程序中,如:Web应用程序会话,网站页面点击数等任何短暂的数据;

安装Redis环境

要在 Ubuntu 上安装 Redis,打开终端,然后输入以下命令:

$sudo apt-get update
$sudo apt-get install redis-server

这将在您的计算机上安装Redis

启动 Redis

$redis-server

查看 redis 是否还在运行

$redis-cli

这将打开一个 Redis 提示符,如下图所示:

redis 127.0.0.1:6379>

在上面的提示信息中:127.0.0.1 是本机的IP地址,6379是 Redis 服务器运行的端口。现在输入 PING 命令,如下图所示:

redis 127.0.0.1:6379> ping
PONG

这说明现在你已经成功地在计算机上安装了 Redis。

 

Python操作Redis

sudo pip install redis
or
sudo easy_install redis
or
源码安装
 
详见:https://github.com/WoLpH/redis-py

  

在Ubuntu上安装Redis桌面管理器

要在Ubuntu 上安装 Redis桌面管理,可以从 http://redisdesktop.com/download 下载包并安装它。

Redis 桌面管理器会给你用户界面来管理 Redis 键和数据。

Redis API使用

redis-py 的API的使用可以分类为:

  • 连接方式
  • 连接池
  • 操作
  • String 操作
  • Hash 操作
  • List 操作
  • Set 操作
  • Sort Set 操作
  • 管道
  • 发布订阅

连接方式


 

1、操作模式

redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。

import redis
 
r = redis.Redis(host='10.211.55.4', port=6379)
r.set('foo', 'Bar')
print r.get('foo')

 

2、连接池

redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。

操作


1. String操作

redis中的String在在内存中按照一个name对应一个value来存储。如图:

redisson获取锁失败 redis获取数据失败怎么办_数据库

set(name, value, ex=None, px=None, nx=False, xx=False)

 

在Redis中设置值,默认,不存在则创建,存在则修改

参数:

ex,过期时间(秒)

px,过期时间(毫秒)

nx,如果设置为True,则只有name不存在时,当前set操作才执行

xx,如果设置为True,则只有name存在时,岗前set操作才执行

setnx(name, value)

设置值,只有name不存在时,执行设置操作(添加)

setex(name, value, time)
设置值
参数:
    time,过期时间(数字秒 或 timedelta对象)
mget(keys, *args)

 

psetex(name, time_ms, value)

设置值

参数:

time_ms,过期时间(数字毫秒 或 timedelta对象)

mset(*args, **kwargs)

批量设置值

如:

mset(k1='v1', k2='v2')

mget({'k1''v1''k2''v2'})

get(name)

获取值

mget(keys, *args)

批量获取

如:

mget('ylr''wupeiqi')

r.mget(['ylr''wupeiqi'])

getset(name, value)

设置新值并获取原来的值

getrange(key, start, end)

 获取子序列(根据字节获取,非字符)

 参数:

# name,Redis 的 name

# start,起始位置(字节)

# end,结束位置(字节)

setrange(name, offset, value)

修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)

 参数:

offset,字符串的索引,字节(一个汉字三个字节)

value,要设置的值

setbit(name, offset, value)


# 对name对应值的二进制表示的位进行操作

 

# 参数:

# name,redis的name

# offset,位的索引(将值变换成二进制后再进行索引)

# value,值只能是 1 或 0

 

# 注:如果在Redis中有一个对应: n1 = "foo",

那么字符串foo的二进制表示为:01100110 01101111 01101111

所以,如果执行 setbit('n1'71),则就会将第7位设置为1

那么最终二进制则变成 01100111 01101111 01101111,即:"goo"

 

# 扩展,转换二进制表示:

 

# source = "武沛齐"

source = "foo"

 

for in source:

num = ord(i)

print bin(num).replace('b','')

 

特别的,如果source是汉字 "武沛齐"怎么办?

答:对于utf-8,每一个汉字占 3 个字节,那么 "武沛齐" 则有 9个字节

对于汉字,for循环时候会按照 字节 迭代,那么在迭代时,将每一个字节转换 十进制数,然后再将十进制数转换成二进制

11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000


*用途举例,用最省空间的方式,存储在线用户数及分别是哪些用户在线

 

getbit(name, offset)


# 获取name对应的值的二进制表示中的某位的值 (0或1)


bitcount(key, start=None, end=None)


# 获取name对应的值的二进制表示中 1 的个数

# 参数:

# key,Redis的name

# start,位起始位置

# end,位结束位置


strlen(name)


# 返回name对应值的字节长度(一个汉字3个字节)


incr(self, name, amount=1)


# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。

 

# 参数:

# name,Redis的name

# amount,自增数(必须是整数)

 

# 注:同incrby


incrbyfloat(self, name, amount=1.0)


# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。

 

# 参数:

# name,Redis的name

# amount,自增数(浮点型)


decr(self, name, amount=1)


# 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。

 

# 参数:

# name,Redis的name

# amount,自减数(整数)


append(key, value)

# 在redis name对应的值后面追加内容
 
# 参数:
    key, redis的name
    value, 要追加的字符串