Redis入门指南

1.1、NoSql简介

在世界上最热门的话题其实就是NoSQL数据库,可是对于数据库的认识,最初只有关系型数据库,但是关系型数据库并不是一直以来的持续发展。

关系型数据库的操作核心语法:SQL,但是SQL语法要求太严格了,而且在进行SQL处理的时候一旦处理不当就会产生大量的笛卡尔积,所以有很多的人不认可SQL操作,而这一部分人就住宅使用命令来完成数据库的操作,例如:微软在90年度的时候有一个数据库:ForPro,这个数据库最初的时候是只能够依靠自己的命令来进行处理,而后由于SQL的大力推广,后来FoxPro数据库不得已又支持了SQL语法。
关系型数据库的“问题”
传统关系型中的事务控制是一个很好的机制,但是其本身有一个最大的缺点:速度慢(处理速度太慢)。单节点的数据库你即使再厉害,你所在的服务器的硬件性能再好,你也无法承受几亿条数据。
NoSQL数据库
首先在实际的开发之中,关系型数据库不能被替代,因为它存储的数据都是结构化的数据,但是一些操作频繁较高的数据呢?例如:在所有的电商平台上都会存在一个购物车功能,那么现在的技术开发要求考虑PC端、移动端数据通用。

购物车分析
但是这样的解决方案太麻烦了,因为你现在既然要操作的是数据库,数据库最好可用有这样大并发数据访问的处理支持。而传统型数据库因为有了事务这一概念,才让整个的执行变得异常缓慢。
购物车分析
传统关系型数据库依然要进行保留,依然要保留原始的结构化数据,而NoSQL要负责那些高并发的用户数据操作。
NoSQL数据库分类
在现在的开发之中,国内使用最多的NoSQL数据库:Redis、Memcached、MongoDB。

如果你现在的项目之中没有NoSQL数据库,基本上就可定性:属于传统项目,不需要考虑所谓的高并发处理机制,你项目的使用人群会比较小众。

1.2、认识Redis

首先Redis提供给用户的只是一个源代码的开发程序包。
Redis简介
以后下使用Redis的时候尽量选择3.2版本,因为新版本才存在有一个官方提供的Redis集群支持(RedisClust)。
Redis特点
Redis整体的特点是速度快,支持的数据类型多,但是并不只有Redis具备这样的特点,Redis是属于缓存数据库的第二代产品,而第一代产品就是memcached数据库
Redis与Memcached区别
面试题:Redis与Memcached有哪些不同?

  • Redis支持更多的数据类型,而且Redis数据库中的数据允许被持久化(保存在磁盘中)。

1.3、Redis安装与配置

1.3.1、Redis安装

Redis给出的开发包只是源代码的开发包(C程序的源文件),既然是C语言的文件,那么如果要想使用Redis,就需要进行代码的编译处理。理论上这些编译的环境可以在任意的操作系统之中执行,但是考虑到实际的应用环境,更多的是在Linux下完成。

如果非要在Windows中执行,那么你可以去下载一个cygwin的UNIX模拟环境。

1、 将Redis开发包上传到Linux系统之中,但是需要注意,由于给出的开发包属于源代码,所以建议压缩到 【/usr/local/src 】的目录之中

tar xzvf /srv/ftp/redis-3.2.9.tar.gz -C /usr/local/src/

2、进入到Redis源代码所在的安装目录:

cd /usr/local/src/redis-3.2.9/

3、进行程序的编译处理,输入:make

4、编译完成之后要进行Redis安装,输入:make install

5、Redis属于内存缓存数据库,那么如果你选择是一台单独的Redis服务器,则应该考虑将所有的可用内存都交给Redis来进行支配,所以我们理论上还需要执行如下的一行代码:

echo "vm.overcommit_memory=1" >> /etc/sysctl.conf

本次操作指的是进行一次内存的分配策略,在进行设置时vm.overcommit_memory的属性有如下三个取值:

  • 0:表示进行处理的时候首先要检查是否有足够的内存供应,如果现在没有足够的内存供应,则无法分配,内存申请失败,如果有可用内存则直接进行申请开辟
  • 1:表示将所有的内存都交给应用使用,而不关心当前的内存状态如何
  • 2:表示运行分配超过所有物理内存和交换空间的内存的总和

6、将以上的配置写入到内核参数之中:/sbin/sysctl -p

7、为了方便使用Redis数据库,那么建立一个Redis支持的命令工具目录:

mkdir -p /usr/local/redis/{bin,conf}

8、通过源代码目录拷贝出Redis所需要的程序运行文件:

作用命令
1. 拷贝Redis服务启动程序:cp /usr/local/src/redis-3.2.9/src/redis-server /usr/local/redis/bin/
2. 拷贝Redis命令行客户端:cp /usr/local/src/redis-3.2.9/src/redis-cli /usr/local/redis/bin/
3. 性能测试工具:cp /usr/local/src/redis-3.2.9/src/redis-benchmark /usr/local/redis/bin/

9、拷贝出一个配置文件:

 cp /usr/local/src/redis-3.2.9/redis.conf /usr/local/redis/conf/

1.3.2、Redis数据库配置

如果要想配置Redis数据库,主要的配置文件就是redis.conf,所有的配置项一定要在此处完成。

1、Redis作为一个具备有持久化功能的缓存数据库,所以其一定会有一个用于数据存储的目录,那么一般在Redis处理的时候会有三类文件需要做保存:Redis运行时的pidRedis相关处理日志Redis的数据文件,所以建立一个目录用于存放这些数据:

mkdir -p /usr/data/redis/{run,logs.dbcache}

2、修改redis.conf的配置文件:

vim /usr/local/redis/conf/redis.conf
作用命令
1、配置Redis运行端口:port 6379
2、配置Redis是否为后台运行:daemonize no
3、设置进程保存路径:pidfile /usr/data/redis/run/redis_6379.pid
4、设置日志保存目录logfile “/usr/data/redis/logs/redis.log”
5、该Redis支持的数据库个数:databases 16
6、保存数据文件目录:dir /usr/data/redis/dbcache

3、启动Redis服务:

/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
  • 如果要启动Redis-Server就必须明确的指明要使用的redis.conf配置文件;

4、Redis启动会占用6379的端口,所以查看端口:netstat -nptl

  • 此时发现Redis运行的时候是在6379本机下才可以执行,所以无法对外提供服务

5、启动Redis客户端:

作用命令
1、方式一:连接本机6379端口的Redis/usr/local/redis/bin/redis-cli
2、方式二:连接远程的格式/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379

Redis正常启动

6、设置一个数据:set mldn java

7、取得数据:get mldn

8、关闭Redis服务:

  • 取得要关闭的Redis服务的进程,而后使用kill直接杀死;
  • 直接使用killall redis-server干掉所有的Redis的服务

1.4、Redis-benchmark测试与操作命令

Redis支持各种的数据类型,而且Redis操作的速度很快,在Redis数据库里面有一个【redis-benchmark】性能测试工具,可以直接使用这个工具来观察Redis使用,该命令所需要的参数如下:

/usr/local/redis/bin/redis-benchmark --help

Redis-benchmark测试参数
范例:下面模拟1000个客户端进行数据的处理

/usr/local/redis/bin/redis-benchmark -h 127.0.0.1 -p 6379 -c 1000 -d 10 -n 10000

此时的命令之中的具体参数含义如下:

  • -h:要连接的Redis服务器的地址
  • -p:要连接Redis的运行端口
  • -c:指的是模拟的客户端数量
  • -d:每一次操作的数据长度
  • -n:每一次用户发出的请求数量

此时的命令之中的具体参数含义如下:

  • PING_INLINE:44247.49 requests per second
  • SET:42918.46 requests per second
  • GET:43478.26 requests per second
  • INCR:42372.88 requests per second
  • LPUSH:43290.04 requests per second
  • RPUSH:41666.67 requests per second
  • LPOP:42918.46 requests per second
  • RPOP:44052.86 requests per second
  • SADD:43859.65 requests per second

你会清楚的发现,Redis在整体的执行速度上的确是很快,毕竟现在的虚拟机的配置水平是很低的。

Redis最大的特征在于可以进行各种数据类型的操作,包括:字符串、数字,集合(List、Set、Hash)。

1.5、字符串类型

在之前使用的set,get命令操作的都是字符串,而字符串支持的操作命令有如下几种:
Redis字符串数据操作
在Redis里面有一个特别重要的命令【keys】,可以进行全部数据的列出。其中后面的【*】表示数据的匹配。

1、设置新的数据:set username-mldn hello

2、取得对应的数据:get username-mldn

  • 如果在进行数据查询的时候没有对应的key的内容,则返回的是(nil)数据
  • 在数据取得的时候没有【*】的通配,只有【keys *】命令提供有这一操作

3、清空仓库:flushdb

4、不覆盖设置内容:

setnx username-mldn happy

setnx username-admin happy

  • 对于setnx的返回结果有如下两类:0(表示没有设置成功)、1(设置成功)

  • 如果你选择设置的两个数据的key的内容是相同的,默认情况下是会发生有覆盖的

    set username-mldn hello

    set username-mldn admin

6、设置数据保存的有效时间:setex 110-code 10 8789

  • 现在就表示该设置的内容在10秒之后就会自动销毁
  • 在实际的使用之中验证码的信息保存就使用了此类数据类型,因为该类型的数据到店后自动消失
  • 在某一个key具备有指定的有效时间设置之后实际上可以使用【ttl key】查看当前剩余有效时间,如果该内容已经消失了则返回【-2】,如果没有消失,则返回剩余的时间,或者在有效期间内使用【persist key】,让该key取消有效时间,这个时候如果使用【ttl】命令查看则返回的结果是【-1

7、设置多个key内容:

mset username-110 hello username-120 world username-119 cry

那么此时同时设置有三个key的信息,如果此时想和之有相同的key的信息,那么默认会出现覆盖的问题。

mset username-110 hello1 username-120 world1 username-119 cry1

8、 不覆盖的设置key的内容:

  • 包含有一个重复的内容以及两个不重复的内容,因为有一个存在所以返回的是【0】,并且所有的内容都不允许设置:

    msetnx username-110 hello2 username-1 hello username-2 world

  • 包含全部新的内容,现在成功返回【1

    msetnx username-1 hello username-2 world

9、 内容追加:append username-110 World,返回的是当前的内容的长度

10、取得指定key的内容长度:strlen username-110

11、 删除指定的数据内容:del 110-code username-1 username-99

如果现在指定的key不存在,也不会影响程序的执行,只会删除存在的key的信息

1.6、Hash数据类型

Hash是一种最为常见的数据类型,其保存的数据结构为【key = value】,但是需要提醒的是这个时候的key与value并不是我们redis中key和value,hash是作为一种类型,可以这样理解关系:【RedisKey = HashValue】,利用Hash类型可以保存更多的数据。
Hash类型
1、设置是一个Hash类型,保存一个用户的用户名和真实姓名:

  • 结构:mid为用户名的保存的属性名称、mldn为真实的用户名;

    hset member-mldn mid mldn

    hset member-mldn name smith

    也就是说mldn用户下保存了两个数据一个是它的登录名(mid),一个是他的真实姓名(name);

2、取得指定key的内容:

  • 取得指定key中的mid的数据:hget memeber-mldn mid

  • 取得指定key中的name的数据:hget member-mldn name

在这里插入图片描述
如果要想在某一个数据的key上保存更能多的内容,那么就应该使用Hash类型完成。

3、默认情况下hset会进行覆盖设置,那么使用hsetnx就可以避免掉这种覆盖设置的问题:

  • 设置重复数据:hsetnx member-admin mid hello, 返回的结果为0(false)

  • 设置不重复的数据:hsetnx member-aa mid hello,返回结果为1(true)

  • 这个时候所有的【keys *】可以见到的内容只是所有的key的名称

4、数据批量设置:hmset member-pp name wusheng age 55 province hb

5、判读某个key的某个属性是否存在:hexists member-pp school

6、取得全部的数据的内容长度:hlen member-mldn

7、 删除指定的key的内容:hdel member-pp age,name

8、取得一个hash中的所有的key(成员)内容:hkeys member-pp

9、取得指定hash中的所有内容:hvals member-mldn

10、选哟取得key对应的value内容:hgetall member-mldn

  • 它在进行数据排列的时候采用的模式为:hash-key、hash-value、hash-key、hash-value

1.7、数字操作

现在已经接触了基本类型和Hash类型,可以发现,在整个的数据保存的时候都可以进行数字的保存,所以现在也可以针对于数字进行各种处理,处理的命令如下:
Redis数字操作
1、如果要进行数字的操作,那么肯定要设置两个数字的内容:

  • 设置一个基本类型:set shopcar-mldn-pid 100
  • 设置一个Hash类型:hset sc-mldn pid-72378 100

2、进行普通数据类型的数字操作:

  • 自增1处理:incr shopcar-mldn-pid,随后会返回当前增长后的数据内容
  • 默认增长为1,现在要求增长为5:incrby shopcar-mldn-pid 200
  • 自减1处理:decr shopcar-mldn-pid
  • 自减指定的数据:decrby shopcar-mldn-pid 100

3、进行Hash数据类型的数字操作:hincrby sc-mldn pid-72378 1

实际上整个数字操作里面只需要记住两个命令:【incrby】、【hincrby】就够了。

1.8、List数据类型

List数据类型是一种比较麻烦的处理操作。在实际的项目开发里面,List就是一个链表结构,那么链表结构的时间复杂度是n,而且在进行链表数据处理的时候主要是进行内容的保存、节点的设置、递归遍历。
List类型
1、(左边压入)创建一个描述关键字的集合:

lpush sks mldn java hello happy word cloud

push属于入栈,栈的特点是先进后出

2、进行指定范围的链表数据输出,如果设置为【-1】则表示输出全部:lrange sks 0 -1

3、(右边压入)进行入栈处理:rpush sks 1 2 3 4 5 6 7

4、在指定元素(hello)上进行追加内容:

  • 在指定元素前追加:linsert sks before hello hello-before

  • 在指定元素后追加:linsert sks after hello hello-after

    如果此时你保存的集合内容存放有重复的数据,则以第一个数据为准

5、修改指定索引数据:lrange sks 0 -1

6、 删除数据:lrem sks 5 hello

7、保留指定范围内的数据:ltrim sks 0 9,范围编号不在0~9之间的所有的数据将被删除掉

8、(栈顶)元素出栈:lpop sks

9、(栈底)元素出栈:rpop sks

10、 将移除的数据保存到另一个集合:rpoplpush sks dsk

表示将sks的集合中的栈底的一个元素出栈,而后压入到dsk这个集合的栈顶

11、取得指定索引对应的数据:lindex sks 0

12、 取得集合个数:llen sks

1.9、Set数据类型

Set也是一种常见的数据类型,其最大的特征是基于数据的集合比对处理,例如:可以实现数据的交集、并集、差集。
在这里插入图片描述
1、向集合之中追加新元素:sadd user-mldn a b c d e

此时向该集合之中追加了五个元素,可以把每个元素想象为一个用户名

2、查询set集合处理:smembers user-mldn,List集合是有序的,Set集合是无序的

3、删除set集合元素:srem user-mldn a

4、从集合中弹出元素(该元素会自动进行删除处理):spop user-mldn

5、返回两个集合的差集:

描述命令
准备出第一个集合sadd user-mldn a b c d e
准备出第二个集合:sadd user-admin a c e x y z
进行差运算:sdiff user-mldn user-admin

6、保存差集的运行结果到其他集合:

sdiffstore user-admin-mldn user-admin user-mldn

将“user-admin”与“user-mldn”两个用户的数据进行差集的计算处理,并且将结果保存“user-admin-mldn”集合中。

查看差集的保存:smembers user-admin-mldn

7、交集运算:sinter user-mldn user-admin

将交集保存到指定的集合里面去:sinterstore user-admin-mldn-inter user-admin user-mldn

8、并集运算:sunion user-admin user-mldn

将并集保存到指定的集合里面:sunionstore user-admin-mldn-union user-admin user-mldn

9、弹出数据到另外的集合中:smove user-mldn user-mldn-temp a

10、返回集合个数:scard user-mldn

11、判断指定的集合中是否包含有指定的元素存在:sismember user-mldn b,如果存在返回1,不存在返回0

12、随机返回集合中的一个数据:srandmember user-mldn 3,其中后面可以设置返回的数据个数,如果不设置默认为1

2.0、SortedSet集合

Set集合的最大特征是可以进行数据比对,但是Set数据本身属于无序的保存,所以如果需要进行数据的顺序保存,则可以采用SortedSet,这个也不算是一个顺序保存,更多的情况下该集合可以保存一个分数,而这个分数的操作就可以作为一些数据的统计结果出现。
SortedSet类型
1、增加sortedSet数据:

zadd user-mldn 1 pid-1

zadd user-mldn 1 pid-2

zadd user-mldn 1 pid-3

现在假设这些商品的信息该用户只看了一次,所以每一个数据的分数为1

2.、取得SortedSet集合中的全部数据:

  • 显示所有的数据的元素: zrange user-mldn 0 -1

  • 显示每一个元素和其对应的分数:zrange user-mldn 0 -1 withscores

  • 也可以输出指定范围的数据:zrange user-mldn 0 2 withscores

3、从集合里面删除数据:zrem user-mldn pid-1

4.、元素分数的增长:zincrby user-mldn 5 pid-1,会返回有当前增长后的数据内

5、取得指定元素的索引内容:zrank user-mldn pid-1,索引值仍然从0开始

6、数据反转处理取得索引:zrevrank user-mldn pid-1

7、反转后取得数据:zrevrange user-mldn 0 -1 withscores

8、根据分数范围取得数据:

  • 闭区间处理:zrangebyscore user-mldn 3 6 withscores,包含了 3 和 6

  • 开区间处理:zrangebyscore user-mldn (3 (6 withscores

  • 设置一个范围:zrangebyscore user-mldn 1 10 withscores limit 0 2

9、取得指定分数范围的数据量:zcount user-mldn 2 8

10、取得指定key中的集合数量:zcard user-mldn

  • 取得指定的分析的key:keys *

11、根据索引下标删除数据:zremrangebyrank user-mldn 0 5

2.1、数据类型总结

Redis严格来讲由于其处理的速度很快,某种程度上已经不完全属于数据库的支持了,所以对于数据类型我个人可以给出一些简单的总结:

1、基本类型(String、int):基本类型的操作更加适合于用户进行短期的数据存储,因为在实际的开发中,字符串可以进行各种复杂操作,而且字符串也可以描述出各种数据的含义。那么在实际的开发之中,可以利用此类型使用Nginx的集群数据保存、Shiro数据的集群保存、SpringData数据保存(序列化)、JSON数据的保存。

2、Hash类型:hash类型更多的情况下描述的是一个结构化的信息,但是这种结构化的信息个人认为不如对象序列化好用,但是我们至少需要知道Hash这样的类型可以进行内容的详细分类。

3、List(栈、队列):在实际的开发之中可以利用此类型实现消息队列的功能,或者进行缓存的功能,很多公司又可能不直接使用消息队列中间件,而直接利用Redis代替。

4、Set数据类型:最大的支持功能在于集合的运算上,例如:相似度检测、好友推荐到等等都可以通过这种集合的处理方式来完成,应用案例:新浪微博。

5、SortedSet:主要进行数据的流式分析。就以用户浏览商品操作为例:
SortedSet应用场景

2.2、Redis事务处理

Redis本身支持事务处理,但是这种支持的事务处理本身是存在有设计缺陷的,而去与传统的关系型数据库的事务处理有些不同,首先来看一下Redis中的事务支持命令:

  • 打开事务:multi
  • 取消事务:discard
  • 提交事务:exec

范例:观察Redis中的事务

描述命令
设置一个数据:set age 30
打开事务支持:multi
【QUEUED】进行数据操作:set age 300
【QUEUED】进行数据操作:set age 3000
关闭事务:discard

一旦开启了Redis的事务控制,则表示所有的更新操作都要追加一个更新队列之中。由于现在在执行完更新之后发现数据本身出现有问题了,所以选择了关闭事务,一旦事务关闭之后那么该操作将会回滚到最初的状态。

范例:执行事务提交

描述命令
设置一个数据:set age 30
打开事务支持:multi
【QUEUED】进行数据操作:set age 50
【QUEUED】进行数据操作:set age 3000
提交事务:exec

如果在事务开启状态下进行了更新处理,随后只有执行了exec指令后才表示事务真正提交,才会真正影响到原始数据。

但是需要提醒的是,Redis设计之初就是不考虑事务的,所以以上的事务只能够说是Redis的一个玩笑,因为这种事务本身设计的并不完善。

描述命令
设置一个数据:set id mldn
打开事务支持:multi
【QUEUED】进行数据操作:incr id
【QUEUED】进行数据操作:set age 500
提交事务:exec

这个时候一旦提交事务一定会出现错误信息【ERR value is not an integer or out of range】,因为id为字符串而【incr id】命令是进行数字的增长。而且一但出现了错误之后,其他的更新操作依然可以正常完成。

2.3、Redis乐观锁

在数据库执行操作的时候,为了保证数据的一致性,即:A用户更新数据的时候B用户不能够更新。所谓的锁,在数据库的设计上分为两种:

  • 悲观锁:基于数据库的操作实现;
SELECT * FROM member WHERE mid=1 FOR UPDATE
  • 乐观锁:基于算法的实现,在数据表上追加一个锁的处理列:

在Redis里面是直接支持有乐观锁的,如果要想观察乐观锁的处理,则可以打开两个不同的session来进行处理。

1、【第一个Session】执行如下的操作:

描述命令
设置一个数据:set age 30
进行该数据的监听:watch age
启用事务:multi

这个时候并没有对age数据做任何的修改;

2、【第二个session】对数据进行修改操作:

描述命令
覆盖age数据:set age 500
取得age数据:get age

3、【第一个session】

描述命令
修改数据:set age 60
提交事务:exec

此时由于第二个Session已经更新了原始的数据,那么就表示该原始数据上的一个标记列更新,只有第一个session再进行更新的时候会发现返回了【(nil)】,意味着本次更新失败。

2.4、Redis密码设置

如果说你选择的Redis没有进行认证的处理操作,那么所有的程序都可以进行连接。直接使用redis-cli命令只需要设置上主机名称和端口号就可以进行连接处理。那么安全必须要设置密码。

在Redis数据库设计的时候并没有像其它的数据库一样装备了一堆复杂的密码或者权限的概念,在Redis里面只需要设置一个认证密码就可以解决问题。

1、修改【redis.conf】配置文件:

vim /usr/local/redis/conf/redis.conf 

追加一下内容:requirepass mldnjava

2、随后关闭掉redis服务并且重新启动:

  • 关闭redis服务:
killall redis-server
  • 重新启动redis服务
/usr/local/redis/bin/redis-server /user/local/redis/conf/redis.conf

3、登录Redis服务器

/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379
  • 这个时候发现可以正常登录Redis数据库,但是一旦执行操作【keys *】,那么就会出现如下错误信息:

    (error) NOAUTH Authentication required.

  • 此时可以执行如下命令进行认证处理:auth mldnjava

4、直接在登录客户端的时候进行认证编写,使用一个【-a】的参数即可:

/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379 -a mldnjava

所有的Redis服务一定要有认证密码,而且作为Redis集群设计的时候一定要将所有的密码统一。

2.5、Redis性能监控

Redis是作为缓存数据库使用,那么一旦在开发之中使用了Redis,就表示有可能会大面积的去向Redis里面保存数据,那么选择如果要想只当当前的运行状态,那么就需要对其进行监控处理,如果要进行Redis监控,必须通过其他组件完成, 本次通过【redis-stat】工具实现Redis监控操作,这个工具可以直接通过github找到。

1、为了更加清楚的发现redis-stat特点,下面建立三个Redis运行进程,模拟方式很简单,配置不同的Redis端口即可,也就是说你发需要准备出不同的redis.conf配置文件;

2、建立redis数据的保存目录,要求可以同时保存三个Redis进程

mkdir -p /usr/data/redis/{redis-6379,redis-6380,redis-6381}/{run,logs,dbcache}

3、将之前的redis.conf配置文件拷贝一份:

cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis-6379.conf

4、编辑每一个配置文件,修改各自的内容,以redis-6379为例:

vim /usr/local/redis/conf/redis-6379.conf
描述命令
取消外网访问限制:#bind 127.0.0.1
设置端口:port 6379
设置pid保存路径:pidfile /usr/data/redis/redis-6379/run/redis_6379.pid
设置日志文件路径:logfile "/usr/data/redis/redis-6379/logs/redis.log"
数据文件目录:dir /usr/data/redis/redis-6379/dbcache

5、将redis-6379.conf复制为redis-6380.conf、redis-6381.conf

cp /usr/local/redis/conf/redis-6379.conf /usr/local/redis/conf/redis-6380.conf
cp /usr/local/redis/conf/redis-6379.conf /usr/local/redis/conf/redis-6381.conf

随后进入到每一个配置文件进行6379内容的更新:1,$s/6379/6380/g

6、启动所有的Redis服务:

/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6379.conf 
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6380.conf 
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6381.conf 

7、通过GITHUB下载redis-stat开发包

  • 如果要想使用redis-stat检测包必须下载ruby相关环境:apt-get install ruby ruby-dev rubygems,Centos系统使用:yum install ruby ruby-dev rubygems

  • 将该工具下载到【/usr/local】目录之中

  • 进行redis-stat的下载:git clone https://github.com/junegunn/redis-stat.git

8、下载下来的redis-stat里面实际上只有一个执行命令:

/usr/local/redis-stat/bin/redis-stat 
  • 进入到redis-stat所在目录:cd /usr/local/redis-stat/bin

如果要想使用这个命令则必须使用ruby进行该命令的处理:

gem install redis-stat

解决ruby下载慢的问题:https://www.cnblogs.com/joyce306/p/9542777.html

9、启动redis-stat工具进行监听控制:

/usr/local/redis-stat/bin/redis-stat 192.168.68.164:6379 192.168.68.164:6380 192.168.68.164:6381 -a mldnjava

Redis-stat工具监听
10、该工具还支持WEB启动查看,也就是说它内部自动提供一个HttpServer:

/usr/local/redis-stat/bin/redis-stat 192.168.68.164:6379 192.168.68.164:6380 192.168.68.164:6381 -a mldnjava --server=80 --daemon --verbose

启动浏览器:
Redis-stat的HttpServer访问
11、使用redis提供的工具来做测试:

/usr/local/redis/bin/redis-benchmark -h 192.168.68.164 -p 6379 -a mldnjava -c 1000 -d 10 -n 10000
/usr/local/redis/bin/redis-benchmark -h 192.168.68.164 -p 6380 -a mldnjava -c 1000 -d 10 -n 10000
/usr/local/redis/bin/redis-benchmark -h 192.168.68.164 -p 6381 -a mldnjava -c 1000 -d 10 -n 10000

2.6、连接Redis数据库

Redis本身提供一个java语言支持(不仅仅支持java,各个语言都支持),这个组件为jedis,也就是说如果你要进行Redis编程开发,就需要通过Maven获取该组件

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.0.1</version>
</dependency>

1、建立一个jedis的Maven项目

2、修改pom.xml配置文件,追加相应的开发包以及插件:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cn.mldn</groupId>
  <artifactId>jedis</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>jedis</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <jedis.version>3.0.1</jedis.version>
    <junit.version>4.12</junit.version>
    <jdk.version>1.8</jdk.version>
    <encoding.charset>UTF-8</encoding.charset>
  </properties>

  <dependencies>

    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>${jedis.version}</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>jedisDemo</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
          <configuration>
            <source>${jdk.version}</source>
            <target>${jdk.version}</target>
            <encoding>${encoding.charset}</encoding>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

3、如果要进行Redis数据库的连接,千万不要做地址的绑定处理。

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
public class ConnectRedisServer {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "mldnjava"; //认证地址
    public static void main(String[] args) {
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        System.out.println(jedis.ping());
        jedis.close();
    }
}

如果此时服务器返回的内容为【PONG】,就表示连接成功。

2.7、设置字符串数据

Jedis如果要进行数据操作实际上与Redis使得命令是相同的,也就是说整体的Jedis处理的时候所使用的方法名称就是命令名称。

1、设置字符串数据:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
public class ConnectRedisServer {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) {
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        jedis.set("user-mldn","hello");
        jedis.set("user-admin","happy");
        System.out.println(jedis.get("user-admin")); //获取数据
        jedis.close();
    }
}

2、设置有效时间的数据:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
public class ConnectRedisServer {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        jedis.setex("code-mldn",3,"7369"); //该数据只保留3秒,3秒内可以使用,超过无法使用
        System.out.println("立即获取数据:" + jedis.get("code-mldn"));
        Thread.sleep(3500);
        System.out.println("3.5秒后获取数据:" + jedis.get("code-mldn"));
        jedis.close();
    }
}

3、操作Hash数据:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
public class HashDataDemo {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        jedis.hset("user-mldn","name","阿三");
        jedis.hset("user-mldn","age","18");
        System.out.println(jedis.hget("user-mldn","name"));
        System.out.println(jedis.hget("user-mldn","age"));
        jedis.close();
    }
}

4、操作List数据:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
public class ListDataDemo {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        jedis.lpush("user-admin","database","cas","openssh","codis","tidb");
        jedis.rpush("user-admin","hello","world");
        System.out.println(jedis.lpop("user-admin"));
        System.out.println(jedis.lpop("user-admin"));
        System.out.println(jedis.lpop("user-admin"));
        System.out.println(jedis.lpop("user-admin"));
        System.out.println(jedis.lpop("user-admin"));
        System.out.println(jedis.lpop("user-admin"));
        jedis.close();
    }
}

5、取得全部List数据:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
import java.util.List;
public class ListDataDemo {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        //jedis.lpush("user-admin","database","cas","openssh","codis","tidb");
        //jedis.rpush("user-admin","hello","world");
        List<String> all = jedis.lrange("user-admin",0,-1);
        System.out.println(all);
        jedis.close();
    }
}

6、操作Set数据:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
import java.util.Set;
public class SetDataDemo {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        jedis.sadd("user-admin","a","b","c","d","e");
        jedis.sadd("user-mldn","a","c","e","x","y","z");
        Set<String> all = jedis.sinter("user-admin","user-mldn");
        System.out.println(all);
        jedis.close();
    }
}

7、操作SortedSet集合:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class SortedSetDataDemo {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        //定义好一个Map集合
        Map<String, Double> map = new HashMap<>();
        map.put("pid-1-1", 2.0);
        map.put("pid-1-2", 1.0);
        map.put("pid-2-1", 5.0);
        jedis.zadd("user-mldn",map);
        Set<String> zrangeByScore = jedis.zrangeByScore("user-mldn",1.0,5.0);
        System.out.println(zrangeByScore);
        jedis.close();
    }
}

8、取得对应的成绩数据:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class SortedSetDataDemo2 {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        //定义好一个Map集合
        Map<String, Double> map = new HashMap<>();
        map.put("pid-1-1", 2.0);
        map.put("pid-1-2", 1.0);
        map.put("pid-2-1", 5.0);
        jedis.zadd("user-mldn",map);
        Set<Tuple> all = jedis.zrangeByScoreWithScores("user-mldn",1.0,5.0);
        Iterator<Tuple> iter = all.iterator();
        while (iter.hasNext()){
            Tuple tuple = iter.next();
            System.out.println("元素名称:" + tuple.getElement() + "、分数:" + tuple.getScore());
        }
        jedis.close();
    }
}

9、keys处理操作,使用keys可以获取全部的key的信息

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
import java.util.Set;
public class keysDemo {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static void main(String[] args) throws Exception{
        //进行Redis的连接只需要设置主机名和端口号即可,不需要考虑认证问题
        Jedis jedis = new Jedis(REDIS_HOST,REDIS_PORT);
        jedis.auth(REDIS_AUTH); //进行REDIS访问认证
        Set<String> keys = jedis.keys("user-*");
        System.out.println(keys);
        jedis.close();
    }
}

从Jedis整体的设计风格,不会让使用者觉得其特别复杂,相反会觉得很轻松上手。

2.8、Jedis连接池

如果直接使用Jedis可以直接进行数据库的操作,但是每一次的打开和关闭实在是太浪费性能了,所以为了提升操作性能一定要使用数据库连接池的模式来进行处理,幸运的是Jedis开发包直接提供了数据库连接池的操作支持。

范例:实现数据库连接池:

package cn.mldn.jedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisConnectPool {
    public static final String REDIS_HOST = "192.168.136.128"; //主机地址
    public static final int  REDIS_PORT = 6379; // 端口号
    public static final int TIMEOUT = 2000; //设置连接超时时间
    public static final String REDIS_AUTH = "123456"; //认证地址
    public static final int MAX_TOTAL = 1000; //设置最大连接数
    public static final int MAX_IDLE = 200; //设置最小维持连接数
    public static final int MAX_WAIT_MILLIS = 1000; //设置最大等待时间
    public static final boolean TEST_ON_BORROW = true; //是否进行可用测试
    public static void main(String[] args) throws Exception{
        //首先如果要想使用Jedis连接池,则必须有一个类可以保存所有连接池相关属性的配置项
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(MAX_TOTAL); //设置最大连接数
        poolConfig.setMaxIdle(MAX_IDLE); //设置空闲连接数
        poolConfig.setMaxWaitMillis(MAX_WAIT_MILLIS); //最大连接时间
        poolConfig.setTestOnBorrow(TEST_ON_BORROW); //是否要进行连接测试,以保证返回的连接为可用连接
        JedisPool pool = new JedisPool(poolConfig,REDIS_HOST,REDIS_PORT,TIMEOUT,REDIS_AUTH);
        Jedis jedis = pool.getResource(); //通过连接池获取连接对象
        jedis.set("mldn","www.mldn.cn");
        jedis.close();
        pool.close();
    }
}

以后所有的数据库开发都必须使用连接池技术完成。

2.9、主从模式概述

Redis数据库与传统数据库属于并行关系,也就是说传统的关系型数据库保存的是结构化数据,而Rdis保存的是一些所谓的【临时】数据,因为Redis具备以下很强的功能【持久化数据】,发现Redis好像也可以做一些传统数据库的开发。但是现在Redis处理进行数据的存储之外,实际上也可以在一些系统的架构设计之中作为数据的缓存点:
单节点设计问题
那么一旦出现了问题之后必须保证所有的数据可以进行快速恢复处理,所以这个时候数据备份就成为了一个核心的主题,对于备份实际上有两种做法:

  • 理想备份:等到夜深人静、月黑风高时,自己一个人在机房默默的拿着硬盘开始拷贝

  • 在线备份:当数据做出任何处理操作的时候都进行及时的备份,所以这样的设计在Redis里面称为主从设计

主从设计

3.0、主从模式实现

如果要想实现主从模式的配置,首先一定要准备出三台Redis实例,本次为了方便将在一台主机上进行模拟,也就是说在这一台主机上将准备出三个Redis实例,分别对应的端口为:6379、6380、6381,其中6379运行的Redis服务为主服务,而其它两个端口运行的服务为从服务。

1、如果要想进行主从的模式匹配,主服务器上不需要做出任何的变化,也就是说
主服务器根本就不关心是否有从服务器

2、所有的从服务的配置问题(redis-6380.conf、redis-6381.conf)必须要求明确的设置出它对应的主服务器

  • 编辑redis-6380.conf配置文件:
vim /usr/local/redis/conf/redis-6380.conf
描述命令
配置服务器的IP地址:replicaof 192.168.136.128 6379
设置端口:masterauth mldnjava
  • 随后redis-6381.conf配置文件采用与之一样的方式完成处理

3、启动所有的Redis数据服务

/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6379.conf
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6380.conf
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6381.conf

4、登录6379端口的Redis服务(主服务)查看所有的副本信息:

/usr/local/redis/bin/redis-cli -h 192.168.136.128 -p 6379 -a 123456 info replication

connected_slaves:2
slave0:ip=192.168.136.128,port=6380,state=online,offset=252,lag=0
slave1:ip=192.168.136.128,port=6381,state=online,offset=252,lag=0

如果可用发现以上的信息就表示现在6379下有两个从节点。

5、操作主节点(6379)的数据:set mldn java

  • 退出此客户端,随意登录6380或6381主机

这个时候一定是通过主节点进行数据的设置,而后同步到所有的从节点上,这样的好处是可以进行数据的备份处理,如果你现在直接在从节点上操作,从节点会出现【(error)READONLY You can’t write against a read only replica.】,因为设置了从节点只能是只读状态

主从设计的最大的好处在于:可以自动对数据做备份

主从模式的最大的缺点在于:只能够做备份,而出现灾难之后无法立即恢复
主从设计的缺点

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值