NoSQL介绍

NoSQL是以key-value形式存储,和传统的关系型数据库不一样,不一定遵循传统数据库的一些基本要求,比如说遵循SQL标准、ACID属性、表结构等,这类数据库主要有以下特点:非关系型、分布式、开源、水平可扩展的。

  • 特点
    1. 处理超大量的数据
    2. 运行在便宜的PC服务器集群上
    3. 击碎了性能瓶颈
  • 适用场景
    1. 对数据高并发读写
    2. 对海量数据的高效率存储和访问
    3. 对数据的高可扩展性和高可用性

Redis介绍

Redis是一个开源的,先进的key-value存储。它通常被称为数据结构服务器,因为键可以包含字符串、哈希、链表、集合和有序集合。

Redis是一个key-value存储系统。它支持存储的value类型很多,包括string(字符串)、list(链表)、set(集合)、zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集和并集及更丰富的操作。Redis支持各种不同方式的排序。为了保证效率,数据都是缓存在内存中,它也可以周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。

  • 适用场合
    1. 取最新N个数据的操作
    2. 排行榜应用,取TOP N操作
    3. 需要精确设定过期时间的应用
    4. 计数器应用
    5. Uniq操作,获取某段时间所有数据排重值
    6. 实时系统,反垃圾系统
    7. Pub/Sub构建实时消息系统
    8. 构建队列系统
    9. 缓存

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不存在则对应返回nilmget name1 name2 name3
incr对key的值做加加操作并返回新的值incr number1
incrby同incr类似,加指定值,key不存在时会设置key,并认为原来的value是0incrby 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 fieldhget user:001 name
hsetnx设置hash field为指定值,如果key不存在则先创建,存在则返回0hsetnx user:001 name lilei
hmset同时设置hash的多个fieldhmset user1 name lilei1 age 13
hmget获取全部指定的hash fieldhmget user1 name age
hincrby指定的hash field加上给定值hincrby user1 age 2
hexists测试指定field是否存在hexists user1 age
hlen返回指定hash的field数量hlen user1
hdel删除指定hash的fieldhdel user1 age
hkeys返回hash的所有fieldhkeys user1
hvals返回hash的所有valuehvals user1
hgetall获取某个hash中全部的field和valuehgetall 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的差集,并将结果存为另一个keysdiffstore set3 set1 set2(将set1跟set2的差集存到set3)
sinter返回所有给定key的交集sinter set1 set2
sinterstore返回所有给定key的交集,并将结果存为另一个keysinterstore 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中的元素memberzrem zset1 two
zincrby如果在名称为key的zset中已经存在元素member,则改元素的score增加increment否则向该集合中添加改元素,其score的值为incrementzincrby 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的所有keykeys *(*代表取出所有key)
exists确认一个key是否存在exists name
del删除一个keydel 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空间的一个keyrandomkey
rename重命名keyrename age new_age
type返回值的类型type name

服务器相关命令

命令描述示例
ping测试连接是否存活ping
echo在命令行打印内容echo nihao
quit退出连接quit
dbsize返回当前数据库中key的数目dbsize
info获取服务器的信息和统计info
config get实时传储收到的请求config get *
flushdb删除当前选择数据库中的所有keyflushdb
flushall删除所有数据库中的所有keyflushall

Redis高级应用

  1. 安全性
  2. 主从复制
  3. 事务处理
  4. 持久化机制
  5. 发布订阅消息
  6. 虚拟内存的使用

安全性

设置客户端连接后进行任何其它指定前需要使用的密码。

注意:因为redis速度相当快,所以在一台好的服务器下,一个外部的用户可以在一秒钟进行150k次的密码尝试,这意味着你需要指定非常强大的密码来防止暴力破解。

  • 修改redis.conf文件
  • 找到requirepass foobared
  • 添加一行 requirepass 密码
  • 重启服务
    • pkill redis-server
    • redis-server
  • 验证方式
    1. 进入客户端
      • redis-cli
      • auth 密码
    2. redis-cli -a 密码

主从复制

Redis主从复制配置和使用都非常简单。通过主从复制可以允许多个slave server拥有和master server相同的数据库副本

  • 特点
    1. Master可以拥有多个slave
    2. 多个slave可以连接同一个master外,还可以连接到其它slave
    3. 主从复制不会阻塞master,在同步数据时,master可以继续处理client请求
    4. 提高系统的伸缩性
  • 过程
    1. Slave与mas ter建立连接,发送sync同步命令
    2. Master会启动一个后台进程,将数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存
    3. 后台完成保存后,就将此文件发送给slave
    4. slave将此文件保存到硬盘上
  • 配置主从服务器
    • 配置slave服务器很简单,只需要在slave的配置文件中加入以下配置
      • slaveof 192.168.1.1 6379 # 指定master的ip和端口
      • masterauth lamp# 主机密码
    • 执行info即可知道主从信息

事务处理

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需要经常将内存中的数据同步到硬盘来保证持久化。

  • 持久化方式
    1. snapshotting(快照)也是默认方式。
    2. 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

发表回复