Redis-学习笔记

Remote Dictionary Server(Redis) 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API,是跨平台的非关系型数据库。
Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。

一、安装(Win)

一般来说Redis的安装都是在Linux上进行的,而Redis官网也是没有直接提供Windows的安装包,因此如果想在Win上使用,需要我们用点特殊手段

1、下载安装包

GtiHub上的tporadowski 大神提供了 支持 Windows平台的 Redis 安装包,目前仍在维护,目前最新版本是 5.0.14,但是更新速度跟Redis官网相差好几个大版本。

下载地址:Releases · tporadowski/redis · GitHub

(能用就行,要啥自行车)

2、解压

这里是zip压缩包,我直接解压即可,选择自己想要的路径

 

3、启动Redis

打开cmd窗口,切换到Redis安装路径,输入 redis-server 启动 redis 服务

4、测试功能

重新打开CMD窗口,进入redis窗口,输入:redis-cli,建立连接

 

二、Java客户端

1、引入依赖

SpringBoot的前置依赖大家自己引入一下,我们主要接收redis使用需要的依赖:Spring Data Redis

Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Spring Data Redis中提供了一个高度封装的类:RedisTemplate,对相关api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:

ValueOperations:string数据操作

SetOperations:set类型数据操作

ZSetOperations:zset类型数据操作

HashOperations:hash类型的数据操作

ListOperations:list类型的数据操作

2、设置配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfiguration {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        //设置redis的连接工厂对象
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置redis key的序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

注:当前配置类不是必须的,因为 Spring Boot 框架会自动装配 RedisTemplate 对象,但是默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别,故设置为StringRedisSerializer序列化器。

3、配置yml文件

server:
  port: 8080
spring:
  data:
    redis:
      host: localhost
      port: 6379

4、测试功能

创建一个test类,将RedisTemplate自动装配注入进来。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class MainTest {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Test
    public void test(){
        ValueOperations<Object, Object> valueOperations = redisTemplate.opsForValue();
        // 添加数据测试
        valueOperations.set("redis::test","Hello World");
        // 获取数据测试
        System.out.println(valueOperations.get("redis::test"));
    }
}

操作其他类型的数据同上,这里不做赘述,更换redisTemplate的方法获取不同的类型即可:

//string数据操作
ValueOperations valueOperations = redisTemplate.opsForValue();
//hash类型的数据操作
HashOperations hashOperations = redisTemplate.opsForHash();
//list类型的数据操作
ListOperations listOperations = redisTemplate.opsForList();
//set类型数据操作
SetOperations setOperations = redisTemplate.opsForSet();
//zset类型数据操作
ZSetOperations zSetOperations = redisTemplate.opsForZSet();

三、数据类型

Redis定义了丰富的原语命令,可以直接与Redis服务器交互。

但是,实际应用中,我们不太会直接使用这些原语命令,Redis提供了很多客户端,大多情况下我们是通过各式各样的客户端来操作Redis。

但是,任何语言的客户端实际上都是对Redis原语命令的封装,了解原语命令有助于理解客户端的设计原理,知其然,知其所以然。

众所周知,Redis支持五中数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及zset(sortedset:有序集合)

那么具体怎么使用他们呢?

1、String

简介:Redis的字符串是动态字符串,是可以修改的字符串,它的内部表示就是一个字符数组,内部结构的实现类似于Java的ArrayList,它的内部结构是一个带长度信息的字节数组。

特性:可以包含任何数据,比如jpg图片或者序列化的对象,规定字符串的长度不得超过512MB。Redis的字符串有两种存储方式,在长度特别短时,使用embstr形势存储,而长度超过44字节时候,使用raw形势存储

场景:

1、访问量统计:每次访问博客和文章使用 INCR 命令进行递增

2、将数据以二进制序列化的方式进行存储

String类型有三个特点:

1、String是Redis最基本的数据类型,结构为一个key对应一个value。

2、String类型是二进制安全的,意味着可以包含任何数据,比如jpg图片或者序列化的对象。
3、String类型的最大能存储512M。

Redis的原语命令很简单,而且有规律可循,一句话概括,就是干净利索脆,我们列举以下常用命令:

命令说明
SET key value设置指定 key 的值
GET key获取指定 key 的值
SETNX key value只有在 key 不存在时设置 key 的值
SETRANGE key offset value用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
GETRANGE key start end返回 key 中字符串值的子字符
MSET key value [key value …]Multi Set)同时设置一个或多个 key-value 对
MGET key1 [key2…]获取所有(一个或多个)给定 key 的值
SETEX key seconds value(Set Expire)将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)
PSETEX key milliseconds value(Precise Set Expire)这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位

比如我们想设置往Redis中存放一个用户名,用String类型存储:

127.0.0.1:6379> SET name chenlongfei

OK

“OK”是Redis返回的响应,代表设置成功。

取出这个name的值:

127.0.0.1:6379> GET name

“chenlongfei”

想修改name的值为“clf”,重新SET一遍,覆盖掉原来的值:

127.0.0.1:6379> SET name clf

OK

127.0.0.1:6379> GET name

“clf”

想删除该条数据:

127.0.0.1:6379> DEL name

(integer) 1 --该数字代表影响的记录总数

127.0.0.1:6379> GET name

(nil) --nil代表为空,不存在该对象

增删改查命令一分钟学会,想忘记都难,妈妈再也不用担心我的学习!

2、Hash

Redis的哈希是field和value之间的映射,即键值对的集合,所以特别适合用于存储对象。

Redis 中每个 hash 最多可以存储 232 - 1 键值对(40多亿)。

简介:Redis的字典相当于Java语言里面的HashMap,字典结构内部包含了两个Hashtable,通常情况下只有一个Hashtable是有值的,但是在字典扩容缩容时候,需要重新分配新的Hashtable,然后进行渐进式搬迁,这时候两个Hashtable存储的分别是旧的Hashtable和新的Hashtable;待搬迁结束后,旧的Hashtable被删除,新的Hashtable取而代之。

特性:适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去)。大字典的扩容是比较耗时的,需要重新申请新的数组,然后将旧字典所有链表中的元素重新挂接到新的数组下面,这是一个O(n)级别的操作,作为单线程的Redis很难承受这样耗时的过程,所以Redis使用渐进式rehash小步搬迁虽然慢一点,但是肯定可以搬完。

场景:存储、读取、修改对象属性,比如:用户(姓名、性别、爱好),文章(标题、发布时间、作者、内容)

命令说明
HMSET key field1 value1 [field2 value2… ](Hash Multi Set)同时将多个 field-value 对设置到哈希表 key 中
HMGET key field1 [field2…]获取所有给定字段的值
HSET key field value将哈希表 key 中的字段 field 的值设为 value
HGET key field获取存储在哈希表中指定字段的值
HGETALL key获取在哈希表中指定 key 的所有字段和值
HDEL key field2 [field2]删除一个或多个哈希表字段
HSETNX key field value只有在字段 field 不存在时,设置哈希表字段的值
HKEYS key获取所有哈希表中的字段
HVALS key获取哈希表中所有值

例如,我们想在Redis中存储一个用户信息,包括用户ID,用户名,邮箱地址三个字段:

127.0.0.1:6379>HMSET user_1 userId 123 userName clf email chenlongfei@163.com

OK

127.0.0.1:6379> HGETALL user_1

  1. “userId”

  2. “123”

  3. “userName”

  4. “clf”

  5. “email”

  6. “chenlongfei@163.com”

3、List

Redis列表是简单的字符串列表,按照插入顺序排序。

支持添加一个元素到列表头部(左边)或者尾部(右边)的操作。

一个列表最多可以包含 232- 1 ,即超过40亿个元素。

简介:Redis的列表相当于Java的LinkedList,List的结构底层实现不是一个简单的LinkedList,而是快速链表(quicklist)。首先在列表元素较少的情况下,会使用一块连续的内存存储,这个结构是ziplist,即压缩列表。它将所有的元素彼此紧挨着一起存储,分配的是一块连续的内存;当数据量比较多的时候才会改成quicklist。

特性:增删快,提供了操作某一段元素的API,普通的链表需要的附加指针空间太大,会浪费空间,加重内存的碎片化。Redis将链表和ziplist结合起来组成了quicklist,也就是将多个ziplist使用双向指针串联起来使用,既满足了快速的插入删除性能,又不会出现太大的空间冗余。

场景:

1、最新消息排行等功能(比如朋友圈的时间线)

2、消息队列

我们列举以下它的命令:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

例如,我们想用一个名为“Continents”的列表盛放五大洲的名字:

127.0.0.1:6379> LPUSH Continents Asia Africa America Oceania Antarctica

(integer) 5

127.0.0.1:6379> LRANGE Continents 0 4 --获取下标为0~4的元素

  1. “Antarctica”

  2. “Oceania”

  3. “America”

  4. “Africa”

  5. “Asia”

需要注意的是,Redis列表虽然名为列表,其实从特性上来讲更像是栈,以最近放进去的元素为头,以最早放进去的元素为尾,所以,Redis列表的下标呈倒序排列。上例中依次放进去的五个元素:Asia、Africa、America、Oceania、Antarctica,下标分别为4、3、2、1、0。

这与Java中List的概念完全不一样,需要特别注意。

与栈类似,当执行POP操作时,Redis列表弹出的是最新放进去的元素,类似于栈顶元素。

Redis列表还支持一种阻塞式操作,比如BLPOP(Blockd List Pop之缩写),移出并获取列表的第一个元素,如果列表没有元素(或列表不存在)会阻塞列表直到等待超时或发现可弹出元素为止。

例如,我们对一个不存在的列表“myList”执行BLPOP命令:

27.0.0.1:6379> BLPOP myList 20 – 弹出myList列表的第一个元素,如果没有,阻塞20秒该客户端会进入阻塞状态,如果20秒之内该列表存入了元素,则弹出:

27.0.0.1:6379> BLPOP myList 20 --若无元素则进入阻塞状态,限时20秒

  1. “myList”

  2. “hello”

(6.20s)

如果超时后仍然没有等到元素,则结束阻塞,返回nil:

127.0.0.1:6379> BLPOP myList 20

(nil)

(20.07s)

4、set(集合)

Redis集合是String类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

Redis集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

集合中最大的成员数为 2^32- 1 ,即每个集合最多可存储40多亿个成员。

Redis集合还有两大特点,一是支持随机获取元素,二是支持集合间的取差集、交集与并集操作。

简介:Redis的集合相当于Java语言里面的HashSet,内部的键值对是无须的、唯一的,Set的结构底层实现是字典,只不过所有的value都是NULL,其他的特性和字典一摸一样。

特性:

1、添加、删除、查找的复杂度都是O(1)

2、为集合提供了求交集、并集、差集等操作

当set集合容纳的元素都是整数并且元素个数较少时,Redis会使用intset来存储集合元素。intset是紧凑的数组结构,同时支持16位,32位和64位整数

场景:

1、共同好友

2、利用唯一性,统计访问网站的所有独立ip

3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐

集合的一大特点就是不能有重复元素,如果插入重复元素,Redis会忽略该操作:

127.0.0.1:6379> SADD direction east west south north

(integer) 4

127.0.0.1:6379> SMEMBERS direction

  1. “west”

  2. “east”

  3. “north”

  4. “south”

127.0.0.1:6379> SADD direction east

(integer) 0 --east元素已经存在,该操作无效

127.0.0.1:6379> SMEMBERS direction

  1. “west”

  2. “east”

  3. “north”

  4. “south”

5、SortedSet(有序集合)

Redis 有序集合和集合一样也是String类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。Redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

集合中最大的成员数为 232- 1 ,即每个集合最多可存储40多亿个成员。

简介:Redis有序列表类似于Java的SortedSet和HashMap的结合体,一方面是一个set,保证内部value的唯一性,另一方面可以给每个value赋予一个score,代表这个value的排序权重。它的内部实现是一个Hash字典 + 一个跳表。

特性:

数据插入集合时,已经进行天然排序

Redis的跳表共有64层,能容纳2的64次方个元素。

Redis之所以用跳表来实现有序集合

  1. 插入、删除、查找以及迭代输出有序序列这几个操作,红黑树都能完成,时间复杂度跟跳表是一样的。但是按照区间来查找数据,红黑树的效率就没有跳表高

  2. 跳表更容易代码实现,比起红黑树来说还是好懂、好写很多,可读性好,不容易出错

  3. 跳表更加灵活,可以通过改变索引构建策略,有效平衡执行效率和内存消耗

场景:

1、排行榜,取TopN操作

2、带权重的消息队列

例如,、使用有序列表来存储学生的成绩单:

127.0.0.1:6379> ZADD scoreList 82 Tom

(integer) 1

127.0.0.1:6379> ZADD scoreList 65.5 Jack

(integer) 1

127.0.0.1:6379> ZADD scoreList 43.5 Rubby

(integer) 1

127.0.0.1:6379> ZADD scoreList 99 Winner

(integer) 1

127.0.0.1:6379> ZADD scoreList 78 Linda

(integer) 1

127.0.0.1:6379> ZRANGE scoreList 0 100 WITHSCORES --获取名次在0~100之间的记录

1)“Rubby”

2)“43.5”

3)“Jack”

4)“65.5”

5)“Linda”

6)“78”

7)“Tom”

8)“82”

9)“Winner”

10)“100”

需要注意的是,Redis有序集合是默认升序的,score越低排名越靠前,即score越低的元素下标越小。

 四、存储结构

我们都知道,Redis存取都比Mysql快得多,除开众所周知的他是个内存数据库之外,还有什么原因呢?

Redis快的原因:

1、Redis 采用的是 ANSI C 语言编写,采用 C 语言编写的好处是底层代码执行效率高。依赖性低,使用 C 语言开发的库没有太多运行时(Runtime)依赖,并且系统兼容性好,稳定性高。

2、Redis 采用的 Key-Value 方式进行存储,数据的操作复杂度为 O(1)。

3、采用单线程模型,单线程避免了线程上下文切换和不必要的线程资源竞争。

4、采用了多路 I/O 复用技术,这里的多路是多个 Socket 网络连接,复用是指复用一个线程,采用多路技术的好处是同一个线程中可以处理多个 I/O 请求,减少网络 IO 消耗,提升了使用效率。

5、众所周知也是最最关键的原因,内存存储:Redis是使用内存(in-memeroy)存储,没有磁盘IO上的开销

而且,Redis的一种对象类型可以有不同的存储结构来实现,从而同时兼顾性能和内存。
在这里插入图片描述

字典是Redis最基础的数据结构,一个字典即一个DB,Redis支持多DB。

Redis字典采用Hash表实现,针对碰撞问题,采用的方法为“链地址法”,即将多个哈希值相同的节点串连在一起,从而解决冲突问题。

但是,“链地址法”的问题在于当碰撞剧烈时,性能退化严重,例如:当有n个数据,m个槽位,如果m=1,则整个Hash表退化为链表,查询复杂度O(n)。为了避免Hash碰撞攻击,Redis随机化了Hash表种子。

Redis的方案是“双buffer”,正常流程使用一个buffer,当发现碰撞剧烈(判断依据为当前槽位数和Key数的对比),分配一个更大的buffer,然后逐步将数据从老的buffer迁移到新的buffer。

redisObject是真正存储redis各种类型的结构,在Redis源码的redis.h文件中,定义了这些结构:

#define REDIS_LRU_BITS 24  
#define REDIS_LRU_CLOCK_MAX ((1<<REDIS_LRU_BITS)-1)/* Max value of obj->lru */  
#define REDIS_LRU_CLOCK_RESOLUTION 1000/* LRU clock resolution in ms */  
typedef struct redisObject {  
    unsigned type:4;  
    unsigned encoding:4;  
    unsigned lru:REDIS_LRU_BITS; /* lru time(relative to server.lruclock) */  
    intrefcount;  
    void*ptr;  
} robj;  

type即Redis支持的逻辑类型,包括:

/* Object types*/  
#define REDIS_STRING 0  
#define REDIS_LIST 1  
#define REDIS_SET 2  
#define REDIS_ZSET 3  
#define REDIS_HASH 4  

即前面所列举的五种数据类型。

而type定义的只是逻辑类型,encoding才是物理存储方式,一种逻辑类型可以使用不同的存储方式,包括:

/* Objectsencoding. Some kind of objects like Strings and Hashes can be 
 * internally represented in multiple ways. The'encoding' field of the object 
 * is set to one of this fields for thisobject. */  
#defineREDIS_ENCODING_RAW 0     /* Rawrepresentation */  
#defineREDIS_ENCODING_INT 1     /* Encoded asinteger */  
#define REDIS_ENCODING_HT2      /* Encoded as hash table */  
#defineREDIS_ENCODING_ZIPMAP 3  /* Encoded aszipmap */  
#defineREDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */  
#defineREDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */  
#define REDIS_ENCODING_INTSET6  /* Encoded as intset */  
#defineREDIS_ENCODING_SKIPLIST 7  /* Encoded asskiplist */  
#defineREDIS_ENCODING_EMBSTR 8  /* Embedded sdsstring encoding */  

(1) REDIS_ENCODING_RAW 即原生态的存储结构,就是以字符串形式存储,字符串类型在redis中用 sds ( s imple d ynamic s tring)封装,主要为了解决长度计算和追加效率的问题。
(2)REDIS_ENCODING_INT 代表整数,以long型存储。

(3) REDIS_ENCODING_HT 代表哈希表(Hash Table),以哈希表结构存储,与字典的实现方法一致。

(4)REDIS_ENCODING_ZIPMAP 其实质是用一个字符串数组来依次保存key和value,查询时是依次遍列每个key-value 对,直到查到为止。

(5)REDIS_ENCODING_LINKEDLIST 代表链表,以典型的链表结构存储。

(6) REDIS_ENCODING_ZIPLIST 代表一种双端列表,且通过特殊的格式定义,压缩内存适用,以时间换空间。ZIPLIST适合小数据量的读场景,不适合大数据量的多写/删除场景。

(7) REDIS_ENCODING_INTSET 是用一个有序的整数数组来实现的。

(8)REDIS_ENCODING_SKIPLIST 同时采用字典和有序集两种数据结构来保存数据元素。跳跃表(SkipList)是一个特殊的链表,相比一般的链表,有更高的查找效率,其效率可比拟于二叉查找树。缺点即浪费了空间,自古空间和时间两难全。

(9)REDIS_ENCODING_EMBSTR 代表使用embstr编码的简单动态字符串。好处有如下几点: embstr的创建只需分配一次内存,而raw为两次(一次为sds分配对象,另一次为objet分配对象,embstr省去了第一次)。相对地,释放内存的次数也由两次变为一次。embstr的objet和sds放在一起,更好地利用缓存带来的优势。需要注意的是,Redis并未提供任何修改embstr的方式,即embstr是只读的形式。对embstr的修改实际上是先转换为raw再进行修改。

1、 String的存储结构

Redis的所有的key都采用字符串保存,而值可以是字符串,列表,哈希,集合和有序集合对象的其中一种。

字符串存储的逻辑类型即REDIS_STRING,其物理实现(enconding)可以为 REDIS_ENCODING_INT、 REDIS_ENCODING_EMBSTR或REDIS_ENCODING_RAW。

首先,如果可以使用REDIS_ENCODING_EMBSTR编码,Redis首选REDIS_ENCODING_EMBSTR保存;

其次,如果可以转换,Redis会尝试将一个字符串转化为Long,保存为REDIS_ENCODING_INT,如“26”、“180”等;最后,Redis会保存为REDIS_ENCODING_RAW,如“chenlongfei”、“Redis”等。

2、 Hash的存储结构

REDIS_HASH可以有两种encoding方式: REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_HT

Hash表默认的编码格式为REDIS_ENCODING_ZIPLIST,在收到来自用户的插入数据的命令时:

(1)调用hashTypeTryConversion函数检查键/值的长度大于配置的hash_max_ziplist_value(默认64)

(2)调用hashTypeSet判断节点数量大于配置的hash_max_ziplist_entries(默认512)

以上任意条件满足则将Hash表的数据结构从REDIS_ENCODING_ZIPLIST转为REDIS_ENCODING_HT。

3、 List的存储结构

REDIS_SET有两种encoding方式,REDIS_ENCODING_ZIPLIST和REDIS_ENCODING_LINKEDLIST。

列表的默认编码格式为REDIS_ENCODING_ZIPLIST,当满足以下条件时,编码格式转换为REDIS_ENCODING_LINKEDLIST:

(1)元素大小大于list-max-ziplist-value(默认64)

(2)元素个数大于配置的list-max-ziplist-entries(默认512)

4、 Set的存储结构

REDIS_SET有两种encoding方式: REDIS_ENCODING_INTSET 和 REDIS_ENCODING_HT。

集合的元素类型和数量决定了encoding方式,默认采用REDIS_ENCODING_INTSET ,当满足以下条件时,转换为REDIS_ENCODING_HT:

(1)元素类型不是整数

(2)元素个数超过配置的set-max-intset-entries(默认512)

5、SortedSet的存储结构

REDIS_ZSET有两种encoding方式: REDIS_ENCODING_ZIPLIST(同上)和 REDIS_ENCODING_SKIPLIST。

由于有序集合每一个元素包括:<member,score>两个属性,为了保证对member和score都有很好的查询性能,REDIS_ENCODING_SKIPLIST同时采用字典和有序集两种数据结构来保存数据元素。字典和有序集通过指针指向同一个数据节点来避免数据冗余。

字典中使用member作为key,score作为value,从而保证在O(1)时间对member的查找跳跃表基于score做排序,从而保证在 O(logN) 时间内完成通过score对memer的查询。

有序集合默认也是采用REDIS_ENCODING_ZIPLIST的实现,当满足以下条件时,转换为REDIS_ENCODING_SKIPLIST:

(1)数据元素个数超过配置zset_max_ziplist_entries 的值(默认值为 128 )

(2)新添加元素的 member 的长度大于配置的zset_max_ziplist_value 的值(默认值为 64 )

五、Redis持久化

为什么要持久化?

众所周知,Redis本身运行时数据保存在内存中。

所以,那么在关闭redis的进程或者关闭计算机后数据肯定被会操作系统从内存中清掉。

而为了避免这一情况,redis默认采用了一种持久化方式,即RDB (Redis DataBase)——可以在redis的目录中找到dump.rdb文件,这就是使用RDB方式做持久化后生成的数据文件。

所以,redis如果没有做持久化,在重启redis后,数据会丢失,而redis默认就采用了一种持久化方式,即RDB。

1、持久化方式

redis的持久化方式有两种,RDB (Redis DataBase)和 AOF (Append Only File),下面分别对两种持久化方式做一个介绍。

1、 RDB

RDB(Redis DataBase)方式采用的思想是定时将内存中的数据进行快照,并写入dump.rdb文件当中,这个文件当中所存储的就是当前redis环境中的配置以及数据。

因此,每次当redis重启之后,redis会先读dump.rdb文件,将数据从硬盘写入到内存中。

1、RDB模式的配置方式

在redis的配置文件redis.conf中搜索save,这一个save可以设置在指定时间内,更新操作达到了固定次数,就将数据同步到数据文件,这里可以写多个save多条件配合使用。比如以下代码所示:

 # 表示900秒内有一次更改,或者900秒内有10次更改,或者60秒内有10000此更改执行同步操作
 save 900 1
 save 300 10
 save 60 10000

另外,如果想不使用RDB做持久化了,可以不配置任何的save,或者将save配成空字符串

2、dbfilename与dir

在redis的配置文件中如果使用RDB的方式做持久化,除了要注意save的配置外,还有两个配置需注意。

dbfilename:这一个配置表示存储的快照文件(数据文件)的文件名,redis默认为dump.rdb,所以我们看到redis目录中会有这样一个文件,这个文件中存放了二进制的内容。

dir:表示了dbfilename所配置的这一个文件的路径,这里最好配一个绝对路径,因为如果使用了相对路径,那么通过不同的方式其启动redis可能会出现文件找不到导致数据前后不一致的情况发生。

2、AOF

redis默认是关闭AOF(Append-only file)模式持久化的,如果要使用需要修改一下配置:

 # 默认为no,需修改为yes
 appendonly yes
 # AOF默认的持久化文件的文件名称
 appendfilename "appendonly.aof"

而指定更新日志条件的同步策略有三个可选条件:

 # 当操作系统进行数据缓存同步到磁盘文件
 # appendfsync no
 # 同步持久化,当数据发生变更时,立即同步到磁盘文件(效率慢些,能保证数据的完整性)
 # appendfsync always
 # 每秒同步一次(默认值,也是最佳的选择,速度快,可能会丢失一秒以内的数据(最多不过2秒))
 appendfsync everysec

另外,可以配置当持久化的文件到达一定程度后,进行重写,为什么要进行重写?由于AOF模式持久化记录的是操作命令,比如说当有这两个命令set key "value1", set key "value2"依次执行后,实际上要恢复数据只需要执行set key "value2"即可。经过类似的压缩,可以为原本已经很大的文件“瘦身”,以下的内容,即为执行此“瘦身”操作的配置。

 # 当AOF的持久化文件大小的增长率大于此配置时,自动开启重写,redis会自动执行“BGREWRITEAOF”命令;
 auto-aof-rewrite-percentage 100
 # 当AOF的持久化文件大小大于此配置时,自动开启重写,redis会自动执行“BGREWRITEAOF”命令;
 auto-aof-rewrite-min-size 3000mb

AOF模式的优缺点

AOF模式的优点如下:

(1)AOF模式可以更好的保护数据不丢失,在redis因为非正常原因挂掉时,其保存数据的完整度理论上高于RDB模式,因为采用appendfsync everysec去写入持久化文件,最多丢失一秒到两秒的数据;而RDB模式丢失的数据根据其配置的写入频率决定;

(2)AOF写入性能高,这归功于其是以append-only的方式写入;

而AOF的缺点如下:

(1)对于同样的数据,通常AOF文件的大小回比RDB的要大;

(2)因为AOF存的是命令而不是数据,所以恢复数据时可能较慢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/261008.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序时代,如何从零开始打造家居展示咨询平台

随着移动互联网的快速发展&#xff0c;小程序成为了各行各业推广和展示产品的新利器。对于家居展示咨询平台来说&#xff0c;打造一款精美实用的小程序不仅可以提升用户体验&#xff0c;还能够有效提高品牌形象和市场竞争力。下面就来介绍一下从零开始打造家居展示咨询平台的步…

字节跳动 Spark Shuffle 大规模云原生化演进实践

Spark 是字节跳动内部使用广泛的计算引擎&#xff0c;已广泛应用于各种大规模数据处理、机器学习和大数据场景。目前中国区域内每天的任务数已经超过 150 万&#xff0c;每天的 Shuffle 读写数据量超过 500 PB。同时某些单个任务的 Shuffle 数据能够达到数百 TB 级别。 与此同…

认识YAML和Propertis

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…

AcWing算法提高课-4.1.1格子游戏

算法提高课整理 CSDN个人主页&#xff1a;更好的阅读体验 原题链接 题目描述 Alice 和 Bob 玩了一个古老的游戏&#xff1a;首先画一个 n n n \times n nn 的点阵&#xff08;下图 n 3 n 3 n3 &#xff09;。 接着&#xff0c;他们两个轮流在相邻的点之间画上红边和蓝…

HTML输出特殊字符详细方法

以下是部分特殊字符代码表&#xff0c;它们的完整应用代码格式为&#xff1a;&#;用下面的四位数字替换&#xff0c;将得到对应的符号。&#xff08;注意&#xff1a;应用这些代码&#xff0c;编辑器应该切换到HTML模式&#xff09; ☏260f ☎260e ☺263a ☻263b ☼263c ☽…

css图片属性,图片自适应

CSS 图片属性指南&#xff1a;background-size 和 object-fit 在前端开发中&#xff0c;使用图片是非常常见的。为了让图片在网页中显示得更好&#xff0c;CSS 提供了多种属性来调整和控制图片的大小和布局。其中&#xff0c;background-size 和 object-fit 是两个常用的属性&a…

常见损失函数(Loss Function)

在线性回归中&#xff0c;损失函数&#xff08;Loss Function&#xff09;用于衡量模型的预测值与实际值之间的差异&#xff0c;是优化算法的目标。常见的线性回归损失函数包括&#xff1a; 均方误差&#xff08;Mean Squared Error&#xff0c;MSE&#xff09; 其中&#xff…

Apache+PHP环境配置 手动配置

准备工作&#xff0c;在G盘新建一个WAMP目录 1.获取Apache 打开下载地址Apache VS17 binaries and modules download&#xff0c;下载 httpd-2.4.58-win64-VS17.zip 将下载好的httpd-2.4.58-win64-VS17.zip拷贝到G:\WAMP目录下并解压到当前目录&#xff0c;得到Apache24目录 …

如何使用支付宝的沙箱环境在本地配置模拟支付并发布至公网测试

文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级子域名8. 测试使用固定二级子域名访问 前言 在沙箱环境调试支付SDK的时候&#xff0c;往往沙箱环境部署在本地&#xff0c;局限性大&#xff0c;在沙箱环境…

宝塔面板安装MySQL数据库并通过内网穿透工具实现公网远程访问

文章目录 前言1.Mysql 服务安装2.创建数据库3.安装 cpolar3.2 创建 HTTP 隧道 4.远程连接5.固定 TCP 地址5.1 保留一个固定的公网 TCP 端口地址5.2 配置固定公网 TCP 端口地址 前言 宝塔面板的简易操作性,使得运维难度降低,简化了 Linux 命令行进行繁琐的配置,下面简单几步,通…

Ubuntu 常用命令之 gunzip 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 gunzip是一个在Ubuntu系统下用于解压缩文件的命令。它主要用于解压.gz格式的文件。这个命令是gzip命令的反向操作&#xff0c;gzip用于压缩文件&#xff0c;而gunzip则用于解压缩文件。 gunzip命令的参数有 -c 或 --stdout 或 -…

月薪过万的运维工程师需要具备什么技能?

月薪过万通常意味着在工作中具备一定的技术深度和广度&#xff0c;如果想进入运维领域&#xff0c;首先你要了解&#xff0c;运维工程师是干什么的&#xff0c;需要解决哪些问题。 可能要考虑技术架构&#xff0c;结合风险、成本、技术等因素&#xff0c;确保系统的稳定性和可扩…

2023年全球架构师峰会(ArchSummit北京站2023)-核心PPT资料下载

一、峰会简介 ArchSummit聚焦业界强大的技术成果&#xff0c;秉承“实践第一、案例为主”的原则&#xff0c;展示先进技术在行业中的典型实践&#xff0c;以及技术在企业转型、发展中的推动作用。旨在帮助技术管理者、CTO、架构师做好技术选型、技术团队组建与管理&#xff0c…

flink sql1.18.0连接SASL_PLAINTEXT认证的kafka3.3.1

阅读此文默认读者对docker、docker-compose有一定了解。 环境 docker-compose运行了一个jobmanager、一个taskmanager和一个sql-client。 如下&#xff1a; version: "2.2" services:jobmanager:image: flink:1.18.0-scala_2.12container_name: jobmanagerports:…

网络安全:专科及普通本科的温柔乡

当代普通大学生的现状是卷又卷不过、躺又躺不平&#xff0c;把大把的青春都荒废在了思考我应该做什么才能有前途的问题上面。当然&#xff0c;这里说的是那些普通学历且对自己的职业生涯甚至是人生没有规划的大学生&#xff0c;包括专科、普通一本二本&#xff0c;并非985、211…

【Git】在 IDEA 中合并多个 commit 为一个

文章目录 1 未提交到远程分支1.1 需求说明1.2 reset 操作1.3 再次 push 2 已经提交到远程分支2.1 需求说明2.2 rebase 操作2.3 强制 push 分两种情况&#xff1a; 一种是本地提交还没推到远程&#xff0c;这种好处理另一种是已经提交到远程分支&#xff0c;这个略麻烦 1 未提…

升级ChatGPT4的方法

1. 主要流程&#xff1a;先申请一个美区apple id&#xff0c;然后往这个apple id充钱&#xff0c;用这个apple id的钱订阅chatgpt 2. 细节&#xff1a; &#xff08;1&#xff09;申请美区apple id&#xff1a; 其实这一步很简单&#xff08;曾经以为比较复杂&#xff09;&…

Hadoop 集群环境搭建

目录 第一部分&#xff1a;系统安装... 3 1&#xff1a;图形化安装... 3 2&#xff1a;选择中文... 3 3&#xff1a;安装选项... 3 4&#xff1a;软件选项... 4 5&#xff1a;安装位置... 4 6&#xff1a;网络配置... 6 7&#xff1a;开始安装... 7 8&#xff1a;创建用户... 7…

AI伴侣利用亚马逊云科技机器学习与人工智能服务,加速AI类产品的开发过程

2020年《纽约时报》调查显示&#xff0c;全球有超过1000万人以AI恋人作为伴侣&#xff1b;后浪发布的《2022年轻人未来恋爱白皮书》报告中显示&#xff0c;有近4成年轻人接受与虚拟人恋爱。随着人工智能技术的突破&#xff0c;越来越多年轻群体在AI伴侣软件亲手打造自己的理想恋…

直播电商“去网红化”势在必行,AI数字人打造品牌专属IP

近年来&#xff0c;网红直播带货“翻车”事件频发&#xff0c;给品牌商带来了信任危机和负面口碑的困扰&#xff0c;严重损害了企业的声誉。这证明强大的个人IP,对于吸引粉丝和流量确实能起到巨大的好处,堪称“金牌销售”,但太过强势的个人IP属性也会给企业带来一定风险&#x…