NoSQL泛指非关系型的数据库
非关系型数据库和关系型数据库的差别:
- 性能NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高
- 可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展
- 关系型数据库的优势:复杂查询可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询;事务支持使得对于安全性能很高的数据访问要求得以实现
- 对于这两类数据库,对方的优势就是自己的弱势,所以如何利用好这两种数据库的强项,使其相互补充,是一个很重要的需要好好设计的问题
redis简介
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)
这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序
与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了主从同步
redis官网:https://redis.io/
redis中文网:http://www.redis.net.cn/
redis服务端安装
[root@web ~]# cd /usr/local/src/ [root@web src]# wget http://download.redis.io/releases/redis-3.2.5.tar.gz [root@web src]# tar -zxf redis-3.2.5.tar.gz [root@web src]# cd redis-3.2.5 [root@web redis-3.2.5]# make [root@web redis-3.2.5]# vim /usr/local/src/redis-3.2.5/redis.conf //默认配置文件,把daemonize no 改为daemonize yes,允许后台启动 [root@web redis-3.2.5]# cd src [root@web src]# pwd /usr/local/src/redis-3.2.5/src [root@web src]# ls -rwxr-xr-x 1 root root 5580311 11月 25 11:18 redis-benchmark //基准测试 -rwxr-xr-x 1 root root 22185 11月 25 11:18 redis-check-aof //aof持久化 -rwxr-xr-x 1 root root 7826902 11月 25 11:18 redis-check-rdb //rdb持久化 -rwxr-xr-x 1 root root 5709036 11月 25 11:18 redis-cli //linux上的redis客户端 -rwxr-xr-x 1 root root 7826902 11月 25 11:18 redis-sentinel //哨兵,用于redis集群选举 -rwxr-xr-x 1 root root 7826902 11月 25 11:18 redis-server //redis服务端程序 [root@web src]# ./redis-server /usr/local/src/redis-3.2.5/redis.conf //启动redis [root@web src]# netstat -lnp //监听127.0.0.1:6379 Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 4443/./redis-server
redis客户端安装
[root@web ~]# pip install redis [root@web ~]# ipython In [1]: import redis
注意:默认配置文件定义监听localhost
如果客户端和服务端不在同一台服务器上,服务端的配置文件监听地址需要改为bind 0.0.0.0
redis客户端的使用
[root@web redis_py]# cat demon1.py #!/usr/bin/env python import redis r = redis.Redis(host='localhost', port=6379, db=0, password=None) //实例化Redis这个类获得一个对象r,对象的方法就是redis的所有命令 r.set('name', 'aaa') //set()方法往服务端存入两个键值对 r.set('age', 30) print r.get('name') //get(key)方法获取key对应的value print r.keys() //keys()方法打印所有的key [root@web redis_py]# python demon1.py aaa ['age', 'name']
redis连接池
redis客户端使用连接池管理所有请求服务端的连接,避免每次建立、释放连接造成多余的开销
默认情况下,每个redis实例都会维护自己的连接池
可以直接建立一个连接池,实例化对象的时候使用连接池作为参数,这样可以实现多个redis实例共享连接池
[root@web redis_py]# cat demon2.py #!/usr/bin/env python import redis def getConnection(): config = { 'host': 'localhost', 'port': 6379, 'db': 0, 'password': None } pool = redis.ConnectionPool(**config) r = redis.Redis(connection_pool=pool) return r if __name__ == '__main__': r = getConnection() r.set('gender', 'M') print r.get('gender') [root@web redis_py]# python demon2.py M
管道:
redis客户端执行每次请求都会向连接池申请创建连接,请求完毕断开连接
redis是c/s模式的tcp server,使用和http类型的请求响应协议。一个client可以通过socket连接向服务端发起多个请求,每发送一个请求后,client会阻塞并等待redis服务端响应,服务端处理完请求后悔将结果通过响应报文返回给client,也就是说client一次只能发送一个请求
client: INCR X
server: 1
client: INCR X
server: 2
client: INCR X
server: 3
client: INCR X
server: 4
基本上四个命令需要8个tcp报文才能完成,由于通信会有网络延迟,假如从client和server之间的包传输时间需要0.125秒,那么上面的四个命令8个报文至少会需要1秒才能完成,这样即使redis每秒能处理100个命令,而我们的client也只能一秒钟发出四个命令,没有充分利用 redis的处理能力
客户端要想一次发送多个请求,需要使用mset、mget等命令,或者使用管道
client可以将四个命令放到一个tcp报文一起发送,server则可以将四条命令的处理结果放到一个tcp报文返回
需要注意的是,用pipeline方式打包命令发送,redis在处理完所有请求后会缓存请求结果到内存中。打包的命令越多,缓存消耗内存也越多。所以并是不是打包的命令越多越好。具体多少合适需要根据具体情况测试
client: INCR X
client: INCR X
client: INCR X
client: INCR X
server: 1
server: 2
server: 3
server: 4
管道的用法:
In [6]: help(r.pipeline) Help on method pipeline in module redis.client: pipeline(self, transaction=True, shard_hint=None) method of redis.client.Redis instance //获取一个连接对象,通过连接对象创建一个管道 Return a new pipeline object that can queue multiple commands for //返回一个管道对象 later execution. ``transaction`` indicates whether all commands //自动执行多条命令(把多个请求发送到服务端) should be executed atomically. Apart from making a group of operations atomic, pipelines are useful for reducing the back-and-forth overhead //提高处理能力 between the client and server
使用管道和不使用管道的效率对比:
[root@web redis_py]# cat demon3.py #!/usr/bin/env python import redis import datetime from demon2 import getConnection def withpipeline(r): p = r.pipeline(transaction=True) for i in xrange(1000): key = 'test1' + str(i) value = i+1 p.set(key, value) p.execute() def withoutpipeline(r): for i in xrange(1000): key = 'test2' + str(i) value = i+1 r.set(key, value) if __name__ == '__main__': r = getConnection() start = datetime.datetime.now() withpipeline(r) end = datetime.datetime.now() offset = (end-start).microseconds print 'With pipeline time: {0}'.format(offset) start = datetime.datetime.now() withoutpipeline(r) end = datetime.datetime.now() offset = (end-start).microseconds print 'Without pipeline time: {0}'.format(offset) [root@web redis_py]# python demon3.py With pipeline time: 16403 Without pipeline time: 43398