NoSQL介绍
NoSQL是以key-value形式存储,和传统的关系型数据库不一样,不一定遵循传统数据库的一些基本要求,比如说遵循SQL标准、ACID属性、表结构等,这类数据库主要有以下特点:非关系型、分布式、开源、水平可扩展的。
- 特点
- 处理超大量的数据
- 运行在便宜的PC服务器集群上
- 击碎了性能瓶颈
- 适用场景
- 对数据高并发读写
- 对海量数据的高效率存储和访问
- 对数据的高可扩展性和高可用性
Redis介绍
Redis是一个开源的,先进的key-value存储。它通常被称为数据结构服务器,因为键可以包含字符串、哈希、链表、集合和有序集合。
Redis是一个key-value存储系统。它支持存储的value类型很多,包括string(字符串)、list(链表)、set(集合)、zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集和并集及更丰富的操作。Redis支持各种不同方式的排序。为了保证效率,数据都是缓存在内存中,它也可以周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。
- 适用场合
- 取最新N个数据的操作
- 排行榜应用,取TOP N操作
- 需要精确设定过期时间的应用
- 计数器应用
- Uniq操作,获取某段时间所有数据排重值
- 实时系统,反垃圾系统
- Pub/Sub构建实时消息系统
- 构建队列系统
- 缓存
Redis安装与部署
- Ubuntu安装Redis
- apt-get install redis-server
- 安装(Linux)
- 访问 https://redis.io/
- 点击下载最新稳定版
- 或右键复制下载地址使用wget 命令下载
- 下载后 编译源程序
- tar zxvf 安装包名.tar.gz
- cd 解压目录
- make
- cd src && make install


- Redis服务端默认连接端口是6379
- 启动Redis服务
- redis-server
- redis.conf
- 查看是否启动
- ps -aux|grep redis
- 重启Redis
- redis-server restart
- 默认情况下,Redis不是在后台运行,需要开启Redis的后台运行
- vi 路径/.redis.conf
- 将daemonize的值改为yes
- 客户端连接
- redis-cli
- 停止Redis实例
- redis-cli-shutdown或
- pkill redis-server
Redis的配置



Redis数据类型
String类型
String是最简单的类型,一个key对应一个value,string类型是二进制安全的。Redis的string可以包含任何数据,比如jpg图片或者序列化的对象。
操作 | 描述 | 例子 |
set | 设置key对应的值为string类型的value | set name lilei |
get | 获取key对应的string值,如果key不存在,返回nul | get name |
getset | 设置key的值,并返回key的旧值。 | getset key1 30 |
setnx | 设置key对应的值为string类型的value,如果key已经存在,返回0,nx是not exist的意思。 | setnx name lilei |
setex | 设置key对应的值为string类型的value,并指定此键值对应的有效期 | setex haircolor 10 red |
setrange | 设置指定key的value值的子字符串 | set name lilei@126.com setrange name 6 gmail.com |
mset | 一次设置多个key的值,成功返回ok表示所有的值都设置,失败返回0表示没有任何值被设置。 | mset name1 lilei1 name2 lilei2 |
msetnx | 一次设置多个key的值,成功返回ok表示所有的值都设置,失败返回0表示没有任何值被设置。但是不会覆盖已经存在的key | msetnx name1 lilei2 name3 lilei3 |
getrange | 获取key的value值得子字符串 | getrange name 0 5 |
mget | 一次获取多个key的值,如果对应key不存在则对应返回nil | mget name1 name2 name3 |
incr | 对key的值做加加操作并返回新的值 | incr number1 |
incrby | 同incr类似,加指定值,key不存在时会设置key,并认为原来的value是0 | incrby number1 6 |
decr | 对key的值做减减操作并返回新的值 | decr number1 |
decrby | 同decr类似,减指定值。 | decrby number1 5 |
append | 给指定key的字符串追加value,返回新字符串值的长度。 | append name1 @qq |
strlen | 取指定key的value值的长度 | strlen name1 |
hashes类型
Redis hash是一个string类型的field和value的映射表。它的添加、删除操作都是0(1)(平均)。hash特别适合用于存储对象。相较于将对象的每个字段存成单个string类型。将一个对象存储在hash类型中会占用更少的内存,并且 可以更方便的存取整个对象。
操作 | 描述 | 例子 |
hset | 设置hash field为指定值,如果key不存在,则先创建 | hset user:001 name lilei |
hget | 获取指定的hash field | hget user:001 name |
hsetnx | 设置hash field为指定值,如果key不存在则先创建,存在则返回0 | hsetnx user:001 name lilei |
hmset | 同时设置hash的多个field | hmset user1 name lilei1 age 13 |
hmget | 获取全部指定的hash field | hmget user1 name age |
hincrby | 指定的hash field加上给定值 | hincrby user1 age 2 |
hexists | 测试指定field是否存在 | hexists user1 age |
hlen | 返回指定hash的field数量 | hlen user1 |
hdel | 删除指定hash的field | hdel user1 age |
hkeys | 返回hash的所有field | hkeys user1 |
hvals | 返回hash的所有value | hvals user1 |
hgetall | 获取某个hash中全部的field和value | hgetall user1 |
lists类型
List是一个链表结构,主要功能是push、pop、获取一个范围的所有值等,操作中key理解为链表的名字。Redis的list类型其实就是一个每个子元素都是string类型的双向链表。可以通过push、pop操作从链表的头部或者尾部添加删除元素,这样list既可以作为栈,又可以作为队列。
操作 | 描述 | 例子 |
lpush | 在key对应list的头部添加字符串元素 | lpush list1 world |
lrange | 取出元素 | lrange list1 0 -1 |
rpush | 在key对应list的尾部添加字符串元素 | rpush list1 world |
linsert | 在key对应list的特定位置前或后添加字符串 | linsert list1 before word hello |
lset | 设置list中指定下标的元素值 | lset list1 0 hello |
lrem | 从对应list中删除n个和value相同的元素。(n<0从尾删除,n=0全部删除) | lrem list1 1 hello |
ltrim | 保留指定key的值范围内的数据 | ltrim list1 1 -1 |
lpop | 从list的头部删除元素,并返回删除元素 | lpop list1 |
rpop | 从list的尾部删除元素,并返回删除元素 | rpop list1 |
rpoplpush | 从第一个list的尾部移除元素并添加到第二个list的头部 | rpoplpush list1 list2li |
lindex | 返回名称为key的list中index位置的元素 | lindex list1 0 |
llen | 返回key对应list的长度 | llen list1 |
sets类型
Set是集合,它是string类型的无序集合。set是通过hash table实现的,添加、删除和查找的复杂度都是0(1).对集合可以取并集、交集、差集。通过这些操作我们可以实现sns中的好友推荐和blog的tag功能。
操作 | 描述 | 例子 |
sadd | 向名称为key的set中添加元素 | sadd set1 hello |
srem | 删除名称为key的set中的元素 | srem set1 hello |
spop | 随即返回并删除名称为key的set中的一个元素 | spop set1 |
sdiff | 返回所有给定key与第一个key的差集(谁在前以谁为标准) | sdiff set1 set2 |
smembers | 查看元素 | smembers set1 |
sdiffstore | 返回所有给定key与第一个key的差集,并将结果存为另一个key | sdiffstore set3 set1 set2(将set1跟set2的差集存到set3) |
sinter | 返回所有给定key的交集 | sinter set1 set2 |
sinterstore | 返回所有给定key的交集,并将结果存为另一个key | sinterstore set3 set1 set2 (将set1跟set2的交集存到set3) |
sunion | 返回所有给定key的并集 | sunion set1 set2 |
sunionstore | 返回所有给定key的并集 , 并将结果存为另一个key | sunionstore set3 set1 set2 |
smove | 从第一个key对应的set中一处member并添加到第二个对应的set中 | smove set1 set2 hello |
scard | 返回名称为key的set的元素个数 | scard set2 |
sismember | 测试member是否是名称为key的set的元素 | sismember set1 hello |
srandmember | 随机返回名称为key的set的一个元素,但不删除元素 | srandmember set1 |
sorted sets类型
serted set是set的一个升级版本,它在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。可以理解为有两列的mysql表,一列存value,一列存顺序。操作中key理解为zset的名字。
操作 | 描述 | 例子 |
zadd | 向名称为key的zset中添加元素member,score用于排序。如果该元素存在,则更新其顺序。 | zadd zset1 1 one |
zrange | 返回zset给定区间内的元素 | zrange zset1 0 -1 withscores |
zrem | 删除名称为key的zset中的元素member | zrem zset1 two |
zincrby | 如果在名称为key的zset中已经存在元素member,则改元素的score增加increment否则向该集合中添加改元素,其score的值为increment | zincrby zset1 2 one |
zrank | 返回名称为key的zset中member元素的排名(按score从小到大排序)即下标 | zrank zset1 two |
zrevrank | 返回名称为key的zset中member元素的排名(按scroe从大到小排序)即下标 | zrevrank zset1 two |
zrevrange | 返回名称为key的zset(按score从大到小顺序)中的index从start到end的所有元素 | zrevrange zset1 0 -1 withscores |
zrangebyscore | 返回集合中score在给定区间内的元素 | zrangebyscore zset1 2 3 withscores |
zcount | 返回集合中score在给定区间的数量 | zcount zset1 1 3 |
zcard | 返回集合中元素个数 | zcard zset1 |
zremrangebyrank | 删除集合中排名在给定区间内的元素 | zremrangebyrank zset1 1 1 |
zremrangebyscore | 删除集合中索引在给定区间内的元素 | zremrangebyscore zset1 1 2 |
Redis常用命令
Redis提供了丰富的命令对数据库和各种数据库类型进行操作,这些命令可以在linux终端使用。
键值相关命令
操作 | 描述 | 示例 |
keys | 返回满足给定pattern的所有key | keys *(*代表取出所有key) |
exists | 确认一个key是否存在 | exists name |
del | 删除一个key | del name |
expire | 设置一个key的过期时间 | expire addr 10(设置addr10秒过期) |
ttl | 查看key还有多长时间过期(负数代表过期) | ttl addr |
move | 将当前数据库中的key转移到其他数据库中 | move age 1(1为数据库) |
select | 选择数据库。Redis数据库编号从0~15. | select 0(0为数据库) |
persist | 移除给定key的过期时间(ttl结果为负数,代表取消) | persist age |
randomkey | 随即返回key空间的一个key | randomkey |
rename | 重命名key | rename age new_age |
type | 返回值的类型 | type name |
服务器相关命令
命令 | 描述 | 示例 |
ping | 测试连接是否存活 | ping |
echo | 在命令行打印内容 | echo nihao |
quit | 退出连接 | quit |
dbsize | 返回当前数据库中key的数目 | dbsize |
info | 获取服务器的信息和统计 | info |
config get | 实时传储收到的请求 | config get * |
flushdb | 删除当前选择数据库中的所有key | flushdb |
flushall | 删除所有数据库中的所有key | flushall |
Redis高级应用
- 安全性
- 主从复制
- 事务处理
- 持久化机制
- 发布订阅消息
- 虚拟内存的使用
安全性
设置客户端连接后进行任何其它指定前需要使用的密码。
注意:因为redis速度相当快,所以在一台好的服务器下,一个外部的用户可以在一秒钟进行150k次的密码尝试,这意味着你需要指定非常强大的密码来防止暴力破解。
- 修改redis.conf文件
- 找到requirepass foobared
- 添加一行 requirepass 密码
- 重启服务
- pkill redis-server
- redis-server
- 验证方式
- 进入客户端
- redis-cli
- auth 密码
- redis-cli -a 密码
- 进入客户端
主从复制
Redis主从复制配置和使用都非常简单。通过主从复制可以允许多个slave server拥有和master server相同的数据库副本
- 特点
- Master可以拥有多个slave
- 多个slave可以连接同一个master外,还可以连接到其它slave
- 主从复制不会阻塞master,在同步数据时,master可以继续处理client请求
- 提高系统的伸缩性
- 过程
- Slave与mas ter建立连接,发送sync同步命令
- Master会启动一个后台进程,将数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存
- 后台完成保存后,就将此文件发送给slave
- slave将此文件保存到硬盘上
- 配置主从服务器
- 配置slave服务器很简单,只需要在slave的配置文件中加入以下配置
- slaveof 192.168.1.1 6379 # 指定master的ip和端口
- masterauth lamp# 主机密码
- 执行info即可知道主从信息
- 配置slave服务器很简单,只需要在slave的配置文件中加入以下配置
事务处理
Redis对事务的支持目前还比较简单。Redis只能保证一个client发去的事务中的命令可以连续的执行,而中间不会插入其它client的命令。当一个client在连接中发出multi命令时,这个连接会进入一个事务上下文,该连接后续的命令不会立即执行,而是先放到一个队列中,当执行exec命令时,redis会顺序执行队列中的所有命令。
# 示例 # 进入事务上下文 multi # 键入命令 set age 10 set age 20 # 执行 exec # 或者取消事务 discard
乐观锁复杂事务控制
乐观锁:大多数是基于数据版本(version)的记录机制实现的。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个”version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,如果提交的数据版本号大于数据库当前版本号,则予以更新,否则认为是过期数据。
乐观锁实例:假设有一个age的key,开两个session对age进行赋值操作
# 第一步 session1 get age watch age # 监视age multi # 第二步 session2 set age 30 get age # 第三步 session1 set age 20 exec get age
watch命令会监视给定的key,当exec时候如果监视的key从watch后发生过变化,则整个事务会失败。也可以调用watch多次监视多个key,这样就可以对指定的key加乐观锁了。注意watch的key是对整个的连接有效的,事务也一样,如果连接断开,监视和事务都会被自动清除。当然exec、discard、unwatch命令都会清除连接中的所有监视。
持久化机制
Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到硬盘来保证持久化。
- 持久化方式
- snapshotting(快照)也是默认方式。
- Append-only file(缩写aof)的方式。
Snapshotting方式
快照是默认的持久化方式。这种方式是将内存中的数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key被修改就自动做快照。
# 示例 save 900 1 # 900秒内如果超过1个key被修改,则发起快照保存
aof方式
由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到文件中,让redis重启时都会重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
由于os会在内核中缓存write做的修改,所以可能不是立即写到磁盘上。这样aof的方式的持久化也还是有可能会丢失部分修改。
可以通过配置文件告诉redis我们想要通过fsync函数强制os写入磁盘的时机。
# 启动aof持久化方式 appendonly yes # 收到写命令就立即写入磁盘,最慢,但是保证完全的持久化 appendfsync always # 每秒钟写入磁盘一次,在性能和持久化方面做了折中 appendfsynceverysec # 完全依赖os,性能最好,持久化没保证 appendfsync no
发布订阅消息
发布订阅(pub/sub)是一种消息通信模式,主要的目
的是解除消息发布者和消息订阅者之间的耦合,Redis
作为一个pub/sub的server,在订阅者和发布者之间
起到了消息路由的功能。订阅者可以通过subscribe和
psubscribe命今向redis server订阅自己感兴趣的消
息 类 型 , 将 信 息 类 型 称 为 通 道 ( channel)。当发布
者通过publish命令向redis server发送特定类型的信
息时,订阅该倍息类型的全部client都会收到此消息。
# 示例 # session1 subscribe tv1 //订阅tv1 # session2 subscribe tv1 tv2 // 订阅tv1、tv2 # session3 publish tv1 nihao // 广播 tv1 session1 和session2会收到信息
虚拟内存的使用
的虚拟内存与作系统的虚拟内存不是一回事, 但是思路和目的都是相同的。就是暂时把不经常访问的数据从内存交换到磁盘中,从而腾出宝贵的内存空间 用 于 其 他 需 要 访 问 的 数 据 。 尤 其 是 对 于redis这样的内存数据库,内存总是不够用的。除了可以将数据分割到多个redis s e r v e r外。另外能够提高库容量的办法就是使用虚拟内存把那些不经常访问的数据交换
到磁盘上。
# 开启vm功能 vm-enabled yes # 交换出来的value保存的文件路径 vm-swap-file /tmp/redis.swap # redis使用的最大内存上限 vm-max-memory 10000000 # 每个页面的大小32字节 vm-page-size 32 # 最多使用多少页面 vm-pages 13123123 # 用于执行value对象换入的工作线程数量 vm-max-threads 4