# Redis

Redis 是一个开源(BSD 许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件,它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA 脚本(Lua scripting), LRU 驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis 哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

高并发、高性能、高可用

高可用 HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。
假设系统一直能够提供服务,我们说系统的可用性是 100%。
如果系统每运行 100 个时间单位,会有 1 个时间单位无法提供服务,我们说系统的可用性是 99%。2018 年 9 月 7 日

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。
  • Redis 支持数据的备份,即 master-slave 模式的数据备份。 Redis

# Redis 优势

  • 性能极高 – Redis 能读的速度是 110000 次 /s, 写的速度是 81000 次 /s 。
  • 丰富的数据类型 – Redis 支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC 指令包起来。
  • 丰富的特性 – Redis 还支持 publish/subscribe, 通知,key 过期等等特性。

# 下载与安装

redis 稳定版的 github 下载

redis 可视化工具

# 非关系型数据库

非关系型,分布式,一般不保证遵循 ACID 原则的数据存储系统,结构不稳定。

# 优点:

  • 根据需要添加字段,不需要多表联查,仅需要 id 取出对应 value
  • 适用于 SNS(社区化网络服务软件。比如 facebook,wb)
  • 严格上讲不是一种数据库 ,而是一种数据结构化存储方法的集合

# 缺点

  • 只适合存储一些较为简单的数据
  • 不适合复杂查询的数据
  • 不适合持久存储海量数据
区别
内容关系型数据库非关系型数据库
查询数据存储硬盘中,速度慢数据存缓存,速度快
存储格式只支持基础类型K-V,文档,图片
扩展性有多表查询机制,扩展困难数据之间没有耦合,容易扩展
持久性适用于持久存储,海量存储不适用持久存储,海量存储
数据一致性事务能力强,强调数据的强一致性事务能力弱,强调数据的最终一致性
成本有些需要收费基本都是开源

# 使用

# 查看

直接在地址栏输入 cmd 回车打开命令窗口,输入 redis-server redis.windows.conf 然后回车,显示如下信息说明启动成功。

1629432738813

# 配置

  • bind
  • protected-mod

# 设置服务

由于命令式窗口启动服务后如果关闭 cmd 命令式窗口服务就停止了,为了方便起见设置 Redis 本地 Windows 服务

安装 Windows 本地服务:

redis-server --service-install redis.windows-service.conf

常用 Redis 服务命令

(1)开启服务:redis-server --service-start

(2)停止服务:redis-server --service-stop

(3)卸载服务:redis-server --service-uninstall

# redis 数据类型

Redis 支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及 zset (sorted set:有序集合)。

# String(字符串)

  • string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象。

二进制安全原理

C 字符串中的字符必须符合某种编码(比如 ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得 C 字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据。

  • string 类型是 Redis 最基本的数据类型,<span style="color:red">string 类型的值最大能存储 512MB。 </span>
  • 使用 set key value 存储字符串
127.0.0.1:6379> set game apex
OK
127.0.0.1:6379> get game
"apex"

# Hash(哈希)

  • Redis hash 是一个键值 (key=>value) 对集合。

  • Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

  • 使用了 HMSET, HGET 命令,HMSET 设置了 field=>value 对,HGET 获取对应 field 对应的 value

  • 每个 hash 可以存储 2^32-1 个键值对

# List(列表)

  • Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
  • 列表最多可存储 2^32 - 1 元素 (4294967295, 每个列表可存储 40 多亿)。

# Set(集合)

  • Redis 的 Set 是 string 类型的无序集合。
  • 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O (1)。
  • sadd set string 命令添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。
  • sunion sismember
  • smembers set 命令获得 set 集合中的元素

# zset (有序集合)

  • Redis zset 和 set 一样也是 string 类型元素的集合, 且不允许重复的成员

  • 不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。

  • zset 的成员是唯一的,但分数 (score) 却可以重复。

  • zadd 命令添加元素到集合,元素在集合中存在则更新对应 score

1629603987925

# redis 命令

<1> 设置键值对 --------- set key value

127.0.0.1:6379> set redis learn
OK
127.0.0.1:6379> get redis
"learn"

redis 是 key, learn 是 value

<2> 删除 key ---------del key

127.0.0.1:6379> del redis
(integer) 1
127.0.0.1:6379> get redis
(nil)

<3> 判断 key 是否存在 ---------exists key

127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> exists redis
(integer) 0

返回 1 则存在,0 不存在

<4> 设置 key 过期时间 ---------expire key seconds**

127.0.0.1:6379> expire name 10
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> exists name
(integer) 0

过期的 key 自动删除

<5> 设置 key 过期特定时间(时间戳)-------expireat key timestamp**

<6> 查找所有符合给定模式 ( pattern) 的 key ------keys pattern

127.0.0.1:6379> keys *
1) "game"
127.0.0.1:6379> keys g*
1) "game"

​ * ?

<7> 移动数据库中的 key -------move key db

move game 1

<span style="color:red">redis 默认使用数据库 0</span>

<8> 移除 key 的过期时间,key 将持久保持 ---------persist key

<9> 以毫秒为单位返回 key 的剩余的过期时间 ----------pttl key

<10> 以秒为单位,返回给定 key 的剩余生存时间 (TTL, time to live)----------ttl key

<11> 修改 key 的名称 ---------rename key newkey

<12> 从当前数据库随机返回一个 key------randomkey

<13> 仅当 newkey 不存在时,将 key 改名为 newkey ---renamenx key newkey

<14> 返回 key 所存储的值的类型 -------type key

<15>

# redis 连接

初始 redis 没有设置密码,Redis 中的连接命令基本上是用于管理与 Redis 服务器的客户端连接。

客户端如何向 Redis 服务器验证自身,并检查服务器是否正在运行。

redis 127.0.0.1:6379> AUTH "password" 
OK 
redis 127.0.0.1:6379> PING 
PONG
命令说明
auth password使用给定密码验证服务器
echo message打印给定的字符串信息
ping检查服务器是否运行正常
quit关闭当前连接
select index更改当前连接的所选数据库

# redis 备份

# 语法

redis Save 命令基本语法如下:

redis 127.0.0.1:6379> SAVE

该命令将在 redis 安装目录中创建 dump.rdb 文件。

# redis 管道

Redis 是一个 TCP 服务器,支持请求 / 响应协议。 在 Redis 中,请求通过以下步骤完成:

  • 客户端向服务器发送查询,并从套接字读取,通常以阻塞的方式,用于服务器响应。
  • 服务器处理命令并将响应发送回客户端。

管道:

管道的基本含义是,客户端可以向服务器发送多个请求,而不必等待回复,并最终在一个步骤中读取回复。

优势:通过管道从连接到本地主机速度增加五倍,因特网连接的至少快一百倍。

# redis 持久化

redis 提供了两种持久化的方式,分别是 RDB(Redis DataBase)和 AOF(Append Only File)。

RDB,简而言之,就是在不同的时间点,将 redis 存储的数据生成快照并存储到磁盘等介质上;

AOF,则是换了一个角度来实现持久化,那就是将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

# RDB

redis 在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。

对于 RDB 方式,redis 会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何 IO 操作的,这样就确保了 redis 极高的性能。

如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。

# AOF

我们通过配置 redis.conf 中的 appendonly yes 就可以打开 AOF 功能。如果有写操作(如 SET 等),redis 就会被追加到 AOF 文件的末尾。

默认的 AOF 持久化策略是每秒钟 fsync 一次(fsync 是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis 仍然可以保持很好的处理性能,即使 redis 故障,也只会丢失最近 1 秒钟的数据。

如果在追加日志时,恰好遇到磁盘空间满、inode 满或断电等情况导致日志写入不完整,也没有关系,redis 提供了 redis-check-aof 工具,可以用来进行日志修复。

因为采用了追加方式,如果不做任何处理的话,AOF 文件会变得越来越大,为此,redis 提供了 AOF 文件重写(rewrite)机制,即当 AOF 文件的大小超过所设定的阈值时,redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了 100 次 INCR 指令,在 AOF 文件中就要存储 100 条指令,但这明显是很低效的,完全可以把这 100 条指令合并成一条 SET 指令,这就是重写机制的原理。

在进行 AOF 重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响 AOF 文件的可用性。

AOF 方式的另一个好处,我们通过一个 “场景再现” 来说明。某同学在操作 redis 时,不小心执行了 FLUSHALL,导致 redis 内存中的数据全部被清空了,这是很悲剧的事情。只要 redis 配置了 AOF 持久化方式,且 AOF 文件还没有被重写(rewrite),我们就可以用最快的速度暂停 redis 并编辑 AOF 文件,将最后一行的 FLUSHALL 命令删除,然后重启 redis,就可以恢复 redis 的所有数据到 FLUSHALL 之前的状态了。但是如果 AOF 文件已经被重写了,那就无法通过这种方法来恢复数据了。

虽然优点多多,但 AOF 方式也同样存在缺陷,比如在同样数据规模的情况下,AOF 文件要比 RDB 文件的体积大。而且,AOF 方式的恢复速度也要慢于 RDB 方式。

如果你直接执行 BGREWRITEAOF 命令,那么 redis 会生成一个全新的 AOF 文件,其中便包括了可以恢复现有数据的最少的命令集。

如果运气比较差,AOF 文件出现了被写坏的情况,也不必过分担忧,redis 并不会贸然加载这个有问题的 AOF 文件,而是报错退出。这时可以通过以下步骤来修复出错的文件:

1. 备份被写坏的 AOF 文件
2. 运行 redis-check-aof –fix 进行修复
3. 用 diff -u 来看下两个文件的差异,确认问题点
4. 重启 redis,加载修复后的 AOF 文件

# redis 发布订阅

1629772278161

# redis 事务

Redis 事务允许在单个步骤中执行一组命令。以下是事务的两个属性:

  • 事务中的所有命令作为单个隔离操作并按顺序执行。不可以在执行 Redis 事务的中间向另一个客户端发出的请求。
  • Redis 事务也是原子的。原子意味着要么处理所有命令,要么都不处理。

1629772410535

# java 连接 Redis

jedis API

在 Java 程序中使用 Redis 之前,需要确保在机器上安装了 Redis 的 Java 驱动程序和 Java 环境。可以先在将 Java 电脑上并配置好环境。

在 pom.xml 添加依赖

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
      <version>2.9.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.9.0</version>
    </dependency>

之后可以使用测试类:

import redis.clients.jedis.Jedis; 
public class RedisJavaTest { 
	@Test
   public void redisTest() { 
      //Connecting to Redis server on localhost 
      Jedis jedis = new Jedis("localhost"); 
      System.out.println("Connection to server sucessfully"); 
      //check whether server is running or not 
      System.out.println("Server is running: "+jedis.ping()); 
   } 
}
@Test
    public void test1() {
        //1. 获得连接对象
        // 如果你的 Redis 客户端没有设置访问密码的话,可以直接使用下面的构造方法,如果设置了密码,则使用 JedisShardInfo 对象来设置访问配置
		//Jedis jedis = new Jedis("192.168.0.1", 6379);
        JedisShardInfo shardInfo = new JedisShardInfo("redis://127.0.0.1:6379");// 这里是连接的本地地址和端口
        shardInfo.setPassword("password");// 这里是密码
        Jedis jedis = new Jedis(shardInfo);
        //2. 获得数据
        String username = jedis.get("username");
        System.out.println(username);
        //3. 存储数据
        jedis.set("addr", "南京") ;
        System.out.println(jedis.get("addr"));
    }
更新于 阅读次数 本文阅读量:

请我喝[茶]~( ̄▽ ̄)~*

Windlinxy 微信支付

微信支付

Windlinxy 支付宝

支付宝