文章目录
redis学习路线思维导图,(真正的好运气,都不过是藏在努力里)后期慢慢更新,未完待续!
redis简述
概念
Redis是一个开源的使用ANSI
C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted
set(有序集合)和hash(哈希类型)。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。
Redis 与其他 key - value 缓存产品主要有以下三个特点:
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave模式的数据备份。
优势
性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
redis与Memcached区别
Memcached是多线程,而Redis使用单线程。(个人认为Memcached在读写处理速度上由于Redis)
Memcached使用预分配的内存池的方式,Redis使用现场申请内存的方式来存储数据,并且可以配置虚拟内存。
Redis可以实现持久化(也就是说redis需要经常将内存中的数据同步到硬盘中来保证持久化),主从复制,实现故障恢复。
Memcached只是简单的key与value,但是Redis支持数据类型比较多。包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。
redis持久化方式
RDB(Redis DB):快照是默认的持久化方式,这种方式是将内存中数据以快照的方式写到二进制文件中,默认的文件名称为dump.rdb.可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key键修改就自动做快照.
AOF(AppendOnlyFile):由于快照方式是在一定间隔时间做一次的,所以如果redis意外挂掉的话,就会丢失最后一次快照后的所有修改。aof比快照方式有更好的持久化,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到文件中,当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
高可用
Redis从2.8 版本正式提供了高可用实现Redis Sentinel,它能够保证Redis节点的故障发现和 故障自动转移。Redis从3.0 版本正式提出了分布式Redis Cluster ,它是Redis真正的分布式实现,提供了高可用、读写和容量的扩展性。
redis有3种高可用:
1)主从
2)哨兵
Redis sentinel是一个分布式系统中监控redis主从服务器,并在主服务器下线时自动进行故障转移。其中有3个特性:
监控(Monitoring): Sentinel会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification):当被监控的某个Redis服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知。
自动故障转移(Automatic failover):当一个主服务器不能正常工作时,Sentinel会开始一次自动故障转移操作。
3)集群
redis使用场景
redis下载安装
1、Github下载地址:https://github.com/MicrosoftArchive/redis/releases
2、百度网盘下载地址 https://pan.baidu.com/s/1z1_OdNVbtgyEjiktqgB83g 密码:kdfq
安装过程
1.首先先把下载的压缩包解压到一个文件夹中
2.打开cmd指令窗口
3.输入你刚才解压的文件路径
4.然后输入redis-server redis.windows.conf 命令
接下来部署Redis为windows下的服务 首先关掉上一个窗口再打开一个新的cmd命令窗口
然后输入指令redis-server --service-install redis.windows.conf
随后,进入右击此电脑–管理–服务和应用程序–服务 启动服务
Redis常用的指令
卸载服务:redis-server --service-uninstall
开启服务:redis-server --service-start
停止服务:redis-server --service-stop
测试redis,通过cd到我们解压的目录,输入指令通过Set get指令查看是否成功
参考原地址: https://blog.csdn.net/weixin_43527241/article/details/88723408
首先明确Redis与Jedis的区别
Jedis对Redis操作
上边博客的参考博客地址:
https://www.jianshu.com/p/a1038eed6d44 (jedis使用教程简书,偏向原理不偏向实践)
https://www.xuebuyuan.com/2158874.html
https://www.cnblogs.com/edisonfeng/p/3571870.html
https://blog.csdn.net/ycmnzmm/article/details/78861205(jedisCluster操作集群等)
redis的发布与订阅
实操redis操作五种数据类型
先来看相关API:
需要下载Jedis驱动或引入依赖请点击下载(2.9.0版本)
package test;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @Title: RedisTest
* @Description: 测试连接Redis缓存数据库及Redis操作数据类型解析使用
* @author: wangsai
* @date 2019/8/21 11:20
*/
public class RedisTest {
/**
* 连接Redis缓存数据库
*/
public Jedis connRedisUtil(){
//连接本地Redis
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
//查看是否运行
System.out.println("服务正在运行:"+jedis.ping());
return jedis;
}
/**
* 测试Redis操作(crud)String(字符串)类型
*/
@Test
public void stringTest(){
//连接本地Redis
Jedis jedis = connRedisUtil();
//添加数据
jedis.set("xing","wang");
jedis.set("ming","sai");
//根据Key查找value
System.out.println("读取姓:"+jedis.get("xing")+" 读取名:"+jedis.get("ming")
+" 没有相应的Key时:"+ jedis.get("wangsai")); //当没有相应的Key时获取结果为null
//拼接字符串
jedis.append("xing","王");
System.out.println("拼接结果:"+jedis.get("xing"));
//覆盖Key即可修改value
jedis.rename("xing","姓");
// jedis.set("xing","wang");//其中key是可以重命名的
System.out.println("覆盖即为修改:"+jedis.get("xing"));
//删除数据
jedis.del("xing");
jedis.del("ming");
//设置多个键值对
jedis.mset("name", "shi","age","22","sex","男");
//获取输出上边设置的多个键值对的值
System.out.println("多对键值对:"+jedis.mget("name","age","sex"));
jedis.del("name");
System.out.println("删除其中一个键值对:"+jedis.mget("name","age","sex"));
jedis.del("age","sex");
System.out.println("删除剩余的键值对:"+jedis.mget("name","age","sex"));
}
/**
* 测试Redis中的Hash(哈希)类型
*/
@Test
public void hashTest(){
//连接本地Redis
Jedis jedis = connRedisUtil();
Map<String,String> map = new HashMap<String,String>();
//向map中添加数据
map.put("name","王赛");
map.put("sex","男");
map.put("age","22");
jedis.hmset("student",map);
//取出student中的元素,执行结果是一个泛型的List
//第一个参数是存入redis中map对象的key,后面跟的是放入map中对象的key,后面的key可以是多个,是可变的
List<String> rsmap = jedis.hmget("student", "name","sex","age");
System.out.println(rsmap);
//删除map中的某个键值
/* jedis.hdel("student","age");
System.out.println(jedis.hmget("student","age"));//此时输出为null
jedis.hdel("student","name","sex");//删除剩余的键值对
System.out.println(jedis.hmget("student", "name","sex","age"));//此时全为空*/
System.out.println(jedis.hlen("student"));//返回key为student的键中存放的值的个数3
System.out.println(jedis.exists("student"));//是否存在key为student的记录,返回true
System.out.println(jedis.hkeys("student"));//返回map对象中的所有key
System.out.println(jedis.hvals("student"));//返回map对象中的所有value
Iterator<String> iter = jedis.hkeys("student").iterator();
while(iter.hasNext()) {
String key = iter.next();
System.out.println(key+":" + jedis.hmget("student", key));
}
jedis.hdel("student","name","sex","age");//删除剩余的键值对
}
/**
* 测试Redis中的List(列表)类型
*/
@Test
public void listCRUDTest(){
//连接本地Redis
Jedis jedis = connRedisUtil();
//清空数据
jedis.del("list");
//添加数据到列表中
jedis.lpush("list","王赛");
jedis.lpush("list","王世杰");
jedis.lpush("list","杜盈锐");
//获取数据并输出。其中第一个数字代表起始位置,后一个表示终止位置,-1表示读取全部
List<String> list = jedis.lrange("list",0,-1);
System.out.println(list);
//清空数据
jedis.del("list");
//使用rpush时,输出的顺序和添加时的顺序是一致的,lpush是相反的。即左右添加
jedis.rpush("list","spring");
jedis.rpush("list","struts");
jedis.rpush("list","hibernate");
System.out.println(jedis.lrange("list",0,-1));
jedis.del("list");
}
/**
* 测试Redis中的set(列表)类型
*/
@Test
public void setTest(){
//连接本地Redis
Jedis jedis = connRedisUtil();
//添加数据
jedis.sadd("student", "王赛");
jedis.sadd("student", "王世杰");
jedis.sadd("student","杜盈锐");
//删除数据
jedis.srem("student", "杜盈锐");
System.out.println(jedis.smembers("student"));//获取所有加入的value
System.out.println(jedis.sismember("student", "王赛"));//判断王赛是否是student集合的元素
System.out.println(jedis.srandmember("student"));//返回集合的一个随机元素
System.out.println(jedis.scard("student"));//返回集合的元素个数
jedis.srem("student","王赛","王世杰");
System.out.println(jedis.scard("student"));//返回集合的元素个数
}
/**
* 测试Redis中的sort set(有序列表)类型
*/
@Test
public void sortTest(){
//连接本地Redis
Jedis jedis = connRedisUtil();
//jedis 排序注意,此处的rpush和lpush是List的操作。是一个双向链表(单从表现来看的)
jedis.del("a");//先清除数据,再加入数据进行测试
jedis.rpush("a", "6");
jedis.lpush("a", "1");
jedis.lpush("a", "8");
jedis.lpush("a", "3");
System.out.println(jedis.lrange("a", 0, -1));
System.out.println(jedis.sort("a"));//[1,3,6,9] //输出排序后结果
System.out.println(jedis.lrange("a", 0, -1));
}
}
jedis官方中文文档
redis命令参考(很全)
jedis常用API
redis常用命令
jedis操作集群
jedi连接池
Windows下搭建Redis集群
Redis Cluster(集群)简介:
- redis是一个开源的key value存储系统,受到了广大互联网公司的青睐。
- redis集群采用P2P模式,是完全去中心化的,不存在中心节点或者代理节点;
- redis集群是没有统一的入口的,客户端(client)连接集群的时候连接集群中的任意节点(node)即可,集群内部的节点是相互通信的(PING-PONG机制),每个节点都是一个redis实例;
- 为了实现集群的高可用,即判断节点是否健康(能否正常使用),redis-cluster有这么一个投票容错机制:如果集群中超过半数的节点投票认为某个节点挂了,那么这个节点就挂了(fail)。这是判断节点是否挂了的方法;
那么如何判断集群是否挂了呢? -> 如果集群中任意一个节点挂了,而且该节点没有从节点(备份节点),那么这个集群就挂了。这是判断集群是否挂了的方法;
那么为什么任意一个节点挂了(没有从节点)这个集群就挂了呢? -> 因为集群内置了16384个slot(哈希槽),并且把所有的物理节点映射到了这16384[0-16383]个slot上,或者说把这些slot均等的分配给了各个节点。当需要在Redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果。再把这个结果对16384进行求余,这个余数会对应[0-16383]其中一个槽,进而决定key-value存储到哪个节点中。所以一旦某个节点挂了,该节点对应的slot就无法使用,那么就会导致集群无法正常工作。 - 集群支持主从复制和主节点的自动故障转移(与哨兵类似);当任一节点发生故障时,集群仍然可以对外提供服务。
- 数据分区:数据分区(或称数据分片)是集群最核心的功能。集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。
需要的部件及配置环境准备:
部件及相关配置:
- Redis
Redis下载链接 - Ruby语言运行环境
Ruby下载链接
具体的Ruby配置(Redis需要这个环境提前配置还是提前配置好):
安装时3个选项都勾选(下载的时候别忘记勾选,尤其是后两项: 意思是将ruby添加到系统的环境变量中,在cmd命令中能直接使用ruby的命令。)
**有问题时查看:**系统变量里面 path 有没有配置 ruby的安装目录bin
PATHEXT 需要配置 .RB;.RBW(我的点完勾选是没问题的) - Redis的Ruby驱动redis-xxxx.gem
驱动链接
建议不要下载的版本过高,3.2.1即可,我用3.2.2的时候报错:时间超时。 - 创建Redis集群的工具redis-trib.rb
集群工具下载说明,如果找不到直接点击下边直达链接
直达
注:( 安装Redis,并运行3个实例(Redis集群需要至少3个以上节点,低于3个无法创建)
新建文件夹:
为了省事将redis的文件夹下的文件复制到上边新建文件夹下边(真正需要的是redis.windows.conf和redis-server.exe和redis-server.pdb)
修改6个文件夹下redis.windows.conf 文件配置
如果cluster-enabled 不为yes, 那么在使用JedisCluster集群代码获取的时候,会报错。
cluster-node-timeout 调整为 15000,那么在创建集群的时候,不会超时。
cluster-config-file nodes-6379.conf 是为该节点的配置信息,这里使用 nodes-端口.conf命名方法。服务启动后会在目录生成该文件。
注意是没有注释的,不要留有空格!
安装Redis的Ruby驱动redis-xxxx.gem(博客上边有链接)
GEM 安装 Redis :切换到redis安装目录,需要在命令行中,执行 gem install redis
版本过高会出错,过高错误查看
下载安装集群脚本 redis-trib.rb 安装到redis目录下
启动每个节点并且执行集群构建脚本
先在 redis目录命令行下执行
redis-server.exe redis.windows.conf
其他新建文件夹节点
可以进入目录使用命令行启动命令也可以编写一个bat来启动redis,在每个节点目录下创建start.bat,内容如下(端口记得对应):
title redis-7000
redis-server.exe redis.windows.conf
在切换到redis目录下命令行执行
ruby redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
在出现 Can I set the above configuration? (type ‘yes’ to accept): 请确定并输入 yes 。
测试
操作某个节点指令 在 /redis 下执行
redis-cli.exe -c -p 7000
-c 表示 cluster
-p 表示 port 端口号
Set name wangsai
解决Bug:
Bug1:槽被占用
解决Bug1:
flushall删除所有的key
[槽被占用类型错误,修改Bug链接]
(https://blog.csdn.net/qiushisoftware/article/details/78837855)
flushall等redis-cli命令总结
配置启动操作关闭常用命令
redis-cli常用命令总结,上边查看过后此链接可略
Bug2:在允许网络访问时,去掉注释bind 127.0.0.1改为bind 0.0.0.0
(如果将集群的所有节点关闭,再重启redis是也是需要把各个节点的下边三个文件删除的,其中dump.rdb是集群搭建成功后生成 的)
Bug2参考链接
博客参考链接:
参考链接1
参考链接2
参考链接3
扩展知识:
由于需要测试某个端口是否可用,telnet就是查看某个端口是否可访问的。
windows10中配置telnet
telnet常用命令