目录

概述

-- 技术发展

技术的分类

1、解决功能性的问题(基础):Java、Jsp、RDBMS、Tomcat、HTML、Linux、JDBC、SVN

2、解决扩展性的问题(框架):Struts、Spring、SpringMVC、Hibernate、Mybatis

3、解决性能的问题:NoSQL、Java线程、Hadoop、Nginx、MQ、ElasticSearch

解决cpu压力(缓存数据库)、内存压力(缓存数据库)、IO压力(NoSQL数据库)

-- NoSQL数据库

NoSQL(Not Only SQL),“不仅仅是SQL”,泛指非关系型数据库。不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。

特点:不遵循SQL标准,不支持ACID,远超于SQL的性能

NoSQL适用场景:数据高并发的读写,海量数据的读写,数据高可扩展性

NoSQL不适用场景:

  • 需要事务支持
  • 基于sql的结构化查询存储,处理复杂的关系,需要即席查询
  • (用不着sql的和用了sql也不行的情况,请考虑用NoSql)

NoSQL数据库:

  • Memcached:很早出现的NoSQL数据库,数据都在内存中,不进行持久化,支持简单的kv,类型单一
  • Redis:支持持久化,支持多种数据结构,
  • MongoDB:文档型数据库

-- 列式存储数据库

  • HBase:用于需要对大量的数据进行随机、实时的读写操作的场景中。处理数据量非常庞大的表,可以用普通的计算机处理超过10亿行数据,还可处理有数百万列元素的数据表
  • Cassandra[kəˈsændrə]

-- 图关系数据库

Neo4j

Redis安装启动

Redis是一个开源的key-value存储系统

  • 官网下载:redis-6.2.6.tar.gz,https://redis.io/ ,官方只支持linux,windows有微软维护的
  • 安装:
    • gcc --version确定已安装gcc
    • 进入解压后的目录,执行make进行编译,编译后src目录下有相应的命令就可以执行了
  • 前台启动:src/redis-server,会在启动目录下生成dump.rdb,redis的数据库持久化文件
  • 后台启动:拷贝一份redis.conf到其他目录,修改其中的配置,然后利用该配置启动。
    • GENERAL配置下,257行,daemonize no改为yes
    • 下面的pid文件名配置为pidfile /var/run/redis_6379.pid,会在后台启动时生成,如果启动多个server注意也需要修改。
    • 执行命令../redis-6.2.6/src/redis-server myredis.conf带配置后台启动
    • 执行命令../redis-6.2.6/src/redis-cli进入客户端,ping验证
    • 关闭:../redis-6.2.6/src/redis-cli shutdown。也可以在客户端内关闭,执行SHUTDOWN,默认会save数据到启动目录dump.rdb,加参数nosave不保存数据

6379端口号来自于Merz的手机9键,默认16个库,从0-15,初始使用0号库,选择其他库SELECT 1,查看当前库的key数量dbsize,删除数据库数据flushdb,删除所有库数据flushall。redis使用采用单线程+多路IO复用技术执行命令。客户端可以使用tab进行命令自动补全

-- Redis配置文件

redis.conf、sentinel.conf(哨兵服务启动的配置文件)

点击查看代码 - redis.conf
## 使用配置启动时配置要作为第一个参数
# ./redis-server /path/to/redis.conf ## 字节单位 大小写不敏感
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes ################################## INCLUDES
## 包含其他配置,相同配置最后一行的生效
# include /path/to/local.conf
# include /path/to/other.conf ################################## NETWORK
## 绑定监听的地址 后面可跟多个 -表示ip不可用也不会启动失败
## 不写的话可以接收任何ip地址访问,生产环境应该写应用服务地址
bind 127.0.0.1 -::1 ## 保护模式 如果开启,在没有配置bind地址和密码的情况下,只接收本机访问
## (防止没有bind可以被任意外部ip访问)
protected-mode yes ## 配置端口
port 6379 ## 客户端无操作退出的超时时间 0关闭超时时间
timeout 0 ## 对客户端的心跳检测(发送ACKs 单位s)建议设置为60 0不检测
tcp-keepalive 300 ################################# GENERAL
## 是否后台启动 默认no
daemonize no ## 进程号文件
pidfile /var/run/redis_6379.pid ## 日志级别debug、verbose、notice、warning,默认为notice
loglevel notice ## 日志路径 后台运行默认/dev/null
logfile "" ## 数据库的个数 索引从0-15
databases 16 ################################ SNAPSHOTTING
## 设置保存数据库到磁盘 每多少秒 达到了多少个key的变化
# save 3600 1
# save 300 100
# save 60 10000 ## Redis无法写入磁盘时关闭写操作
stop-writes-on-bgsave-error yes ## 是否开启rdb压缩,会占用一定的cpu,采用LZF算法进行压缩
rdbcompression yes ## 是否开启校验和,让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能 rdbchecksum yes ## 设置文件名 路径
dbfilename dump.rdb
dir ./ ################################# REPLICATION
## replica配置master的密码 用户名(如果配置了ACL最好配master名因为默认用户无法运行psync)
# masterauth [master-passwordd]
# masteruser [username] ## replica失去与master的连接是否还继续使用旧数据提供服务,配置replica是否只读
replica-serve-stale-data yes
replica-read-only yes ## 是否开启无磁盘同步,及其同步延迟,0表示ASAP
repl-diskless-sync no
repl-diskless-sync-delay 5 ## replica发送ping到server的间隔,replica超时时间
# repl-ping-replica-period 10
# repl-timeout 60 ################################## SECURITY
## 设置密码
# requirepass foobared ################################### CLIENTS
## 设置同时连接的最大客户端数
# maxclients 10000 ############################## MEMORY MANAGEMENT
## 设置最大内存,达到后删除key的策略(默认不删除返回错误)
# maxmemory [bytes]
# maxmemory-policy noeviction ## 设置replica的内存 默认忽略(一般replica的内存比master要大)
# replica-ignore-maxmemory yes ############################## APPEND ONLY MODE
## 是否开启aof,文件名,
appendonly no
appendfilename "appendonly.aof" ## aof同步的配置:始终同步(性能较差但数据完整性较好)、每秒同步(本秒数据可能丢失)、不主动同步(交给操作系统)
# appendfsync always
appendfsync everysec
# appendfsync no ################################ REDIS CLUSTER
## 是否开启集群,集群配置文件
# cluster-enabled yes
# cluster-config-file nodes-6379.conf
# cluster-node-timeout 15000

常用五大数据类型

Redis键(key)

keys *查看所有key,支持表达式

exists k1查看某个k是否存在,也可以跟多个k,EXISTS k1 k2

type k1查看k的类型

del k1删除k,unlink k1非阻塞删除,仅从元数据中删除,真正的删除会在后续异步执行

expire k2 10设置k失效时间,ttl k2查看失效时间还有多久,过时返回-2,永久返回-1

select 1切换数据库,dbsize显示数据库k的数量,flushdb清空数据库,flushall清空所有数据库

rename k1 k2重命名

Redis字符串(String)

String是Redis最基本的类型,一个key对应一个value,字符串value最大可以是512M。String类型是二进制安全的。意味着Redis的string可以包含任何数据,比如jpg图片或者序列化的对象。

String的数据结构为简单动态字符串(Simple Dynamic String),采用预分配冗余空间的方式来减少内存的频繁分配。内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次最多扩1M的空间。需要注意的是字符串最大长度为512M。

set k1 v1添加键值对,set k1 v1 ex 100同时设置失效时间,set k1 v1 ex 100 nx数据库中不存在时添加,否则不添加。

get k1获取键对应的值

getset k1 v11获取当前值,并替换为新值

append k1 xx追加k1对应的值

strlen k1计算字符串的长度

setnx k2 v2数据库中不存在时添加,否则不添加,等价于set k2 v2 nx,nx指not exists

setex k2 100 v2同时设置失效时间,等价于set k1 v1 ex 100

incr k3值增加1,decr k3值减少1

incrby k3 10设置增加步长,decr k3 10设置减少步长

incrbyfloat k3 100.5增加一个小数,如果是个小数,则不能进行上述整数操作。注意:incr都是原子操作,不会被其他线程打断

mset k1 v1 k2 v2同时添加多个kv,msetnx不存在时添加,原子操作

mget k1 k2同时获取多个v

getrange k2 0 -1获取字符串的某一段,-1表示最后,左右都包含

setrange k2 0 aaa设置某一段,0是偏移量

Redis列表(List)

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

List的数据结构为快速链表quickList。首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist。

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

lpush/rpush k1 v1 v2 ...从左边、右边插入数据

lpop/rpop k1从左边、右边吐出一个值,没有数据时键也没有了

rpoplpush k1 k2从k1右边拿一个值插入k2的左边

lrange k1 0 -1输出指定范围内数据,-1表示最后一个

lindex 0按索引输出数据

llen k1输出长度

linsert k1 before/after v1 a在v1之前、之后插入a

lrem k1 2 v1从左边删除2个v1

lset k1 0 a替换0位置的数据为a

Redis集合(Set)

Redis集合是string类型的无序集合,它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

sadd <key> <member> [member ...]添加元素

smembers <key>取出所有元素

sismember <key> <member> 是否是集合的元素

smismember <key> <member> [member ...]是否是集合的元素,判断多个元素

scard <key>返回元素个数

srem <key> <member> [member ...]删除集合中的元素

spop <key> [count]随机吐出元素,会删除

srandmember <key> [count]随机取出元素,不会删除

smove <key1> <key2> <member>移动元素到另一个集合

sinter <key> [key ...]取集合的交集

sunion <key> [key ...]取集合的并集

sdiff <key> [key ...]取集合的差集,在k1,不在k2中

Redis哈希(Hash)

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似Java里面的Map<String,Object>,Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

hset <key> <field> value [field value ...]添加字段和值,hmset一样

hget <key> <field>取出某个字段的值

hexists <key> <field>某个字段是否存在

hsetnx <key> <field> value字段不存在时才添加字段

hkeys <key>返回所有的key

hvals <key>返回所有的value

hincrby <key> <field> <increment>某个字段增加整数,hincrbyfloat增加小数

Redis有序集合Zset(sorted set)

Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

zset底层使用了两个数据结构

(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]添加元素,nx表示不存在时添加,否则存在是覆盖的

ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]返回指定分数内的元素,offset是偏移量,count是返回总数量,WITHSCORES会带着分数一起返回

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]返回指定分数内的元素

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]返回指定分数内的元素,按从大到小

ZINCRBY key increment member增加元素分数

ZREM key member [member ...]删除指定元素

ZREMRANGEBYSCORE key min max按分数删除元素

ZREMRANGEBYRANK key start stop按排名删除元素

ZCOUNT key min max统计某个范围内的元素个数

ZRANK key member返回该集合中的排名

Redis的发布和订阅

发布消息PUBLISH channel message

订阅消息SUBSCRIBE channel [channel ...]

Redis新数据类型

Bitmaps

Bitmaps本身不是一种数据类型,实际上就是一个字符串(key-value),但是可以对字符串的位进行操作。

SETBIT key offset value设置bit值

GETBIT key offset获取bit的值

BITCOUNT key [start end]统计为1的数量

BITOP operation destkey key [key ...]可以与其他bitmap进行交集、并集、非、异或操作,结果存入destkey

HyperLogLog

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

什么事基数?

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

PFADD key element [element ...] 添加元素到hyperloglog,发生变化返回1,否则返回0

PFCOUNT key [key ...]近似计算基数

PFMERGE destkey sourcekey [sourcekey ...]合并pf到目标pf

GeoSpatial

Redis3.2中增加了对GEO类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。

GEOADD key [NX|XX] [CH] longitude latitude member [longitude latitude member ...]添加经纬度坐标

GEOPOS key member [member ...]查询坐标

GEODIST key member1 member2 [m|km|ft|mi]查询直线距离

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key] [STOREDIST key]查询半径内的元素

Redis客户端Jedis

直接访问

  • 引入pom
  • 配置文件注释掉bind(此时所有的ip都可以访问这台服务器的redis,使用bind+ip也无法启动不知道为什么)
  • 配置文件关闭保护模式protected-mode no,启动后就可以访问了,注意关闭防火墙。
<!--redis without springboot-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>

整合SpringBoot

        <!--redis with springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring2.x集成redis需要common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency> <!--redis配置里面需要 后面看下-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
spring:
redis:
host: 192.168.33.102
port: 6379
database: 0
timeout: 1800000 # 读超时时间
lettuce:
pool:
max-active: 20 # 连接的最大连接数 负数表示限制
max-wait: -1 # 最大阻塞时间 负数表示不限制
max-idle: 5 # 连接池中最大的空闲连接
min-idle: 0 # 连接池中最小的空闲连接
@Configuration
@EnableCaching
public class RedisConfig { @Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
StringRedisSerializer redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
template.setConnectionFactory(factory); template.setKeySerializer(redisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
} @Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
StringRedisSerializer redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常问题
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
config.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}

Redis事务、锁机制

Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

Redis事务的主要作用就是串联多个命令防止别的命令插队。

multi命令开始组队,exec命令开始执行,discard可以取消组队

  • 组队过程中某个命令出现了报告错误,执行时整个的所有队列都会被取消。
  • 如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

悲观锁、乐观锁

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。unwatch取消WATCH命令对所有key的监视

Redis事务的三个特性

  • 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 没有隔离级别的概念:队列中的命令没有提交之前都不会实际被执行
  • 不保证原子性:事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

高并发问题

  • 连接超时问题:使用连接池解决
  • 超卖问题(库存小,并发高,高并发下,会拿到同样的值进行减,剩余为1时有多个线程同时减),利用乐观锁解决,先watch,然后使用multi进行事务操作,如果有修改就不执行,解决超卖问题
  • 库存遗留问题(库存多,并发高,高并发下,同时拿到相同的值,已修改的话,未进行购买,但是仍然有剩余),使用lua脚本解决,将其中的事务改成一个luo脚本,本质上是利用了redis的单线程执行。

luo脚本

Lua 是一个小巧的脚本语言,Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数,Lua并没有提供强大的库,一个完整的Lua解释器不过200k,所以Lua不适合作为开发独立应用程序的语言,而是作为嵌入式脚本语言。

将复杂的或者多步的redis操作,写为一个脚本,一次提交给redis执行,减少反复连接redis的次数。提升性能。LUA脚本是类似redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis事务性的操作。但是注意redis的lua脚本功能,只有在Redis 2.6以上的版本才可以使用。

Redis持久化

RDB(Redis DataBase)

指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失

-- Fork

  • Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
  • 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术”
  • 一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。

-- 触发命令

  • save :save时只管保存,其它不管,全部阻塞。手动保存。不建议。默认是# save 3600 1 # save 300 100 # save 60 10000,其他参数参考配置
  • bgsave:Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。
  • 可以通过lastsave 命令获取最后一次成功执行快照的时间
  • 执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义

-- rdb备份恢复

  • config get dir获取rdb备份目录,将目录下的dump.rdb文件进行备份,启动时会直接加载
  • config set save ""给空字符串参数禁用保存策略

-- 优劣势

优势

  • 适合大规模的数据恢复
  • 对数据完整性和一致性要求不高更适合使用
  • 节省磁盘空间
  • 恢复速度快

    劣势
  • Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
  • 虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。
  • 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改

-- 总结

AOF(Append Only File)

以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录),** 只许追加文件不可以改写文件**,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

-- 持久化流程

(1)客户端的请求写命令会被append追加到AOF缓冲区内;

(2)AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;

(3)AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;

(4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;

默认不开启,appendonly.aof文件与 rdf路径一致。rdb和aof同时开启,默认取aof的数据(数据不会存在丢失)。同步策略参考配置。

-- aof备份恢复

  • AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。
  • 如遇到AOF文件损坏,通过redis-check-aof--fix appendonly.aof进行恢复

-- Rewrite

AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制, 当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof

AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作

no-appendfsync-on-rewrite:

如果 no-appendfsync-on-rewrite=yes ,不写入aof文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)

如果 no-appendfsync-on-rewrite=no, 还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。

auto-aof-rewrite-percentage:设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)

auto-aof-rewrite-min-size:设置重写的基准值,最小文件64MB。达到这个值开始重写。

例如:文件达到70MB开始重写,降到50MB,下次什么时候开始重写?100MB

系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,

如果Redis的AOF当前大小>= base_size +base_size*100% (默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写。

重写流程:

(1)bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。

(2)主进程fork出子进程执行重写操作,保证主进程不会阻塞。

(3)子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。

(4)1).子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。2).主进程把aof_rewrite_buf中的数据写入到新的AOF文件。

(5)使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。

-- 优劣势

优势

  • 备份机制更稳健,丢失数据概率更低。
  • 可读的日志文本,通过操作AOF稳健,可以处理误操作。

    劣势
  • 比起RDB占用更多的磁盘空间。
  • 恢复备份速度要慢。
  • 每次读写都同步的话,有一定的性能压力。
  • 存在个别Bug,造成恢复不能。

-- 总结

总结

官方推荐两个都启用。

如果对数据不敏感,可以选单独用RDB。

不建议单独用 AOF,因为可能会出现Bug。

如果只是做纯内存缓存,可以都不用。

官方建议

  • RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
  • AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.
  • Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
  • 只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
  • 同时开启两种持久化方式
  • 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据, 因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
  • RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
  • 建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份), 快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。

性能建议:

因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。

如果使用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。

代价,一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。

只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。

默认超过原大小100%大小时重写可以改到适当的数值。

Redis主从复制

主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

  • 读写分离,性能扩展
  • 容灾快速恢复

如何配置

  • 拷贝一份redis.conf,开启daemonize yes,修改pid文件名,修改端口(如果在同一台机器上),修改log名字(如果配置了且在同一台机器上),修改rdb名字(如果在同一台机器上),appendonly关闭或者修改名字(如果在同一台机器上)
  • 新建一个.conf,使用include /myredis/redis.conf命令包含刚刚修改过的配置,再在后面添加上述需要修改的配置,创建多个.conf文件
  • slave-priority 10 设置从机的优先级,值越小,优先级越高,用于选举主机时使用。默认100
  • ../redis-6.2.6/src/redis-cli -p 6380指定端口启动多台命令,info replication打印主从复制的相关信息
  • slaveof <ip> <port>配置某个实例为从服务器,在主机上写,在从机上读取数据(从机如果写会报错)。
  • 主机挂掉,重启就行,一切如初。从机重启需重设:slaveof 127.0.0.1 6379,否则就变成了master,与原来的主从没有任何关系。可以将该配置添加到配置文件,启动时自动称为从机

三种方式(主从、主从从、从变为主)

  • 使用slaveof <ip> <port>命令配置从机

  • 使用slaveof <ip> <port>命令配置从机的从机,上一个Slave可以是下一个slave的Master,Slave同样可以接收其他 slaves的连接和同步请求,那么该slave作为了链条中下一个的master, 可以有效减轻master的写压力,去中心化降低风险。

    中途变更转向:会清除之前的数据,重新建立拷贝最新的

    风险是一旦某个slave宕机,后面的slave都没法备份

    主机挂了,从机还是从机,无法写数据了

  • 使用slaveof no one命令配置从机为主机,当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。

复制原理

  • Slave启动成功连接到master后会发送一个sync命令
  • Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
  • 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
  • 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
  • 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行

哨兵模式

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

  • 新建配置文件:sentinel.conf(或拷贝默认配置文件sentinel.conf然后修改),增加sentinel monitor mymaster 127.0.0.1 6379 1,mymaster为监控对象的服务名称,1表示至少有多少个哨兵同意迁移
  • 使用redis-sentinel sentinel.conf命令启动,之后主机挂会选择从机作为主机,原来的主机启动后会变为从机,replica-priority可以设置成为主机的优先级

由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

  • 优先级在redis.conf中默认:slave-priority 100,值越小优先级越高
  • 偏移量是指获得原主机数据最全的
  • 每个redis实例启动后都会随机生成一个40位的runid

也可以从哨兵服务获取Redis连接

Redis集群

容量不够,redis如何进行扩容?

并发写操作, redis如何分摊?

另外,主从模式,薪火相传模式,主机宕机,导致ip地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息。

之前通过代理主机来解决,但是redis3.0中提供了解决方案。就是无中心化集群配置。

Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。

Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。

删除持久化数据:删除rdb,aof文件即可

配置集群

  • 在原来的配置基础上,再增加以下开启集群配置,nodes-xxx.conf会自动生成,启动6个实例
cluster-enabled yes
cluster-config-file nodes-6391.conf
cluster-node-timeout 15000
  • 使用命令将实例合成一个集群redis-cli --cluster create --cluster-replicas 1 192.168.11.101:6379 192.168.11.101:6380 192.168.11.101:6381 192.168.11.101:6389 192.168.11.101:6390 192.168.11.101:6391,会自动分配主从节点,选yes即可,1表示一个主机对应一个从机。
  • 使用命令redis-cli -p 6380 -c命令登录,会自动切换到写主机
  • CLUSTER NODES查看集群信息
  • CLUSTER INFO查询节点信息

一个集群至少要有三个主节点。选项 --cluster-replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。分配原则尽量保证每个主数据库运行在不同的IP地址,每个从库和主库不在一个IP地址上。

slots

一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个键都属于这 16384 个插槽的其中一个,

集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。

集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:

节点 A 负责处理 0 号至 5460 号插槽。

节点 B 负责处理 5461 号至 10922 号插槽。

节点 C 负责处理 10923 号至 16383 号插槽。

在redis-cli每次录入、查询键值,redis都会计算出该key应该送往的插槽,如果不是该客户端对应服务器的插槽,redis会报错,并告知应前往的redis实例地址和端口。

redis-cli客户端提供了 –c 参数实现自动重定向。

如 redis-cli -c –p 6379 登入后,再录入、查询键值对可以自动重定向。

不在一个slot下的键值,是不能使用mget,mset等多键操作

可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中去。mset k1{g1} v1 k2{g1} v2 k3 {g1} v3不好使!

CLUSTER KEYSLOT k1获取key所在的slot,返回12706,为slot索引

CLUSTER COUNTKEYSINSLOT 12706查看该slot里有多少key

CLUSTER GETKEYSINSLOT 12706 2返回该slot里的前2个key

故障恢复

主节点下线,从节点会称为主节点,原来的主节点会成为从节点,超时时间配置的为15s

如果某一段插槽的主从都挂掉,而cluster-require-full-coverage 为yes ,那么 ,整个集群都挂掉。如果为no ,那么,该插槽数据全都不能使用,也无法存储

Jedis访问集群

/**
* created by Bingmous on 2021/12/16 17:15
*/
public class RedisClusterConfig {
public static void main(String[] args) {
Set<HostAndPort> set = new HashSet<HostAndPort>();
set.add(new HostAndPort("10.194.227.216",6379)); JedisCluster jedisCluster = new JedisCluster(set);
jedisCluster.set("k1", "v1");
System.out.println(jedisCluster.get("k1")); //即使连接的不是主机,集群会自动切换主机存储。主机写,从机读。
//无中心化主从集群。无论从哪台主机写的数据,其他主机上都能读到数据。
HashSet<HostAndPort> set2 = new HashSet<>();
set2.add(new HostAndPort("10.194.227.216", 6380));
JedisCluster jedisCluster2 = new JedisCluster(set2);
System.out.println(jedisCluster2.get("k1"));
}
}

特点

好处

  • 实现扩容
  • 分摊压力
  • 无中心配置相对简单

    不足
  • 多键操作是不被支持的
  • 多键的Redis事务是不被支持的。lua脚本不被支持
  • 由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至redis cluster,需要整体迁移而不是逐步过渡,复杂度较大。

Redis应用问题解决

缓存穿透

key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决方案

一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

解决方案:

(1) 对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟

(2) 设置可访问的名单(白名单):

使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。

(3) 采用布隆过滤器:(布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。

布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。)

将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。

(4) 进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务

缓存击穿

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案

key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。

解决问题:

(1)预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长

(2)实时调整:现场监控哪些数据热门,实时调整key的过期时长

(3)使用锁:

(1)就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db。

(2)先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key

(3)当操作返回成功时,再进行load db的操作,并回设缓存,最后删除mutex key;

(4)当操作返回失败,证明有线程在load db,当前线程睡眠一段时间再重试整个get缓存的方法。

缓存雪崩

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key

正常访问



缓存失效瞬间

缓存失效时的雪崩效应对底层系统的冲击非常可怕!

解决方案:

(1)构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)

(2)使用锁或队列:

用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况

(3)设置过期标志更新缓存:

记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。

(4)将缓存失效时间分散开:

比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

分布式锁

随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!

分布式锁主流的实现方案:

  1. 基于数据库实现分布式锁
  2. 基于缓存(Redis等)
  3. 基于Zookeeper

    每一种分布式锁解决方案都有各自的优缺点:
  4. 性能:redis最高
  5. 可靠性:zookeeper最高

    这里,我们就基于redis实现分布式锁。

-- redis命令

set k1 v1 nx px 10000,ex second设置失效时间,等价于setex k1 second v1。px millisecond,设置失效时间,单位为毫秒,等价于psetex k1 millisecond v1。nx表示只有键不存在时才添加,等价于setnx k1 v1。xx表示只有键存在时才操作。

  • setnx k1 0,设置k1,执行并发每次值加一,ab -n 5000 -c 100 http://192.168.140.1:8080/test/testLockab并发测试,-n表示请求次数,-c表示并发数
  • 实现1,代码中设置锁lock 111
    • 如果设置成功返回true,表示没有锁,并且自己设置成功,然后获取k1的值,进行++,然后删除lock。
    • 如果设置失败返回false,表示有锁,可以一定时间后再去获取,比如0.1s
    • 问题:如果在获得锁之后业务异常,那么锁将无法释放,解决办法是设置失效时间,即使异常也会自动释放
  • 实现2,设置过期时间,获取锁时就设置,避免set后设置过期时间前异常,还是无法释放锁。执行完业务逻辑后,释放锁
    • 问题:如果锁失效了,业务逻辑还没有执行完,再去释放锁,此时别的线程已经拿到锁了,释放的就是别的线程的锁。解决办法,获得锁时设置一个唯一的uuid,释放前获取这个锁,判断是不是自己的锁
  • 实现3,给自己的锁设置唯一的uuid,在del锁时判断是不是自己的锁
    • 问题:删除操作缺乏原子性,如果删除前判断是自己的锁之后锁刚好过期,此时没有了锁,而另外一个线程又刚好获得了锁,这是就会释放别的线程的锁
  • 实现4,使用lua脚本保证删除的原子性,要么删了自己的,要么就不删,别判断了之后删了别人的
点击查看代码
@RequestMapping("/redis-lock")
public void testRedisLock() {
String uuid = UUID.randomUUID().toString();
//1 获取锁
// Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111"); //20 获得锁的同时设置过期时间
// Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111", 3L, TimeUnit.SECONDS); //30 获得锁时设置uuid
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3L, TimeUnit.SECONDS); //2 如果为true 获取成功
if (lock) { Object num = redisTemplate.opsForValue().get("num"); //获取值
if (num == null) { //没有值 直接返回
return;
}
int i = Integer.parseInt(num + "");
redisTemplate.opsForValue().set("num", ++i); //30 删除锁时判断是不是自己的锁
// String lock1 = (String) redisTemplate.opsForValue().get("lock");
// if (uuid.equals(lock1)) {
// redisTemplate.delete("lock");
// } //40 使用lua脚本保证删除的原子性
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class); //设置返回值类型
redisScript.setScriptText(script); //设置lua脚本
redisTemplate.execute(redisScript, Arrays.asList("lock"), uuid); //lock为第一个key KEYS[1],uuid为第一个参数ARGV[1] // redisTemplate.delete("lock");
} else {
try {
Thread.sleep(100);
testRedisLock(); //获取不到就等100ms后再调 直到获得锁 注意 如果业务出现异常没有释放锁 这里会一致递归调下去会Stack Overflow
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

  • 互斥性。在任意时刻,只有一个客户端能持有锁。
  • 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  • 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
  • 加锁和解锁必须具有原子性。

Redis6.0新功能

ACL

Redis ACL是Access Control List(访问控制列表)的缩写,该功能允许根据可以执行的命令和可以访问的键来限制某些连接。

在Redis 5版本之前,Redis 安全规则只有密码控制 还有通过rename 来调整高危命令比如 flushdb , KEYS* , shutdown 等。Redis 6 则提供ACL的功能对用户进行更细粒度的权限控制 :

(1)接入权限:用户名和密码

(2)可以执行的命令

(3)可以操作的 KEY

ACL LIST查看用户权限列表

ACL CAT查看添加权限指令的类别

ACL CAT [categoryname]查看指令类别的所有命令

ACL WHOAMI查看当前用户

ACL SETUSER [rule [rule ...]]创建和编辑用户ACL,如acl setuser user2 on >password ~cached:* +get密码为password

默认用户为:"user default on nopass ~* &* +@all"

  • on/off表示激活/禁用用户,注意,已验证的连接仍然可以工作。如果默认用户被标记为off,则新连接将在未进行身份验证的情况下启动,并要求用户使用AUTH选项发送AUTH或HELLO,以便以某种方式进行身份验证。
  • nopass表示没有密码,设置密码使用>xxx
  • 权限的添加删除:
    • +<command> 将指令添加到用户可以调用的指令列表中
    • -<command> 从用户可执行指令列表移除指令
    • +@<category> 加该类别中用户要调用的所有指令,有效类别为@admin、@set、@sortedset…等,通过调用ACL CAT命令查看完整列表。特殊类别@all表示所有命令,包括当前存在于服务器中的命令,以及将来将通过模块加载的命令。
    • -<category> 从用户可调用指令中移除类别
    • allcommands +@all的别名
    • nocommand-@all的别名
  • 可操作键的添加或删除:~<pattern>添加可作为用户可操作的键的模式。例如~*允许所有的键

IO多线程

Redis6终于支撑多线程了,告别单线程了吗?

IO多线程其实指客户端交互部分的网络IO交互处理模块多线程,而非执行命令多线程。Redis6执行命令依然是单线程。

Redis 6 加入多线程,但跟 Memcached 这种从 IO处理到数据访问多线程的实现模式有些差异。Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。之所以这么设计是不想因为多线程而变得复杂,需要去控制 key、lua、事务,LPUSH/LPOP 等等的并发问题。整体的设计大体如下:



另外,多线程IO默认也是不开启的,需要再配置文件中配置

io-threads-do-reads yes

io-threads 4

工具支持Cluster

之前老版Redis想要搭集群需要单独安装ruby环境,Redis 5 将 redis-trib.rb 的功能集成到 redis-cli 。另外官方 redis-benchmark 工具开始支持 cluster 模式了,通过多线程的方式对多个分片进行压测。

Redis新功能持续关注

Redis6新功能还有:

1、RESP3新的 Redis 通信协议:优化服务端与客户端之间通信

2、Client side caching客户端缓存:基于 RESP3 协议实现的客户端缓存功能。为了进一步提升缓存的性能,将客户端经常访问的数据cache到客户端。减少TCP网络交互。

3、Proxy集群代理模式:Proxy 功能,让 Cluster 拥有像单实例一样的接入方式,降低大家使用cluster的门槛。不过需要注意的是代理不改变 Cluster 的功能限制,不支持的命令还是不会支持,比如跨 slot 的多Key操作。

4、Modules API

Redis 6中模块API开发进展非常大,因为Redis Labs为了开发复杂的功能,从一开始就用上Redis模块。Redis可以变成一个框架,利用Modules来构建不同系统,而不需要从头开始写然后还要BSD许可。Redis一开始就是一个向编写各种系统开放的平台。

Redis学习笔记(详细)的更多相关文章

  1. redis学习笔记(详细)——高级篇

    redis学习笔记(详细)--初级篇 redis学习笔记(详细)--高级篇 redis配置文件介绍 linux环境下配置大于编程 redis 的配置文件位于 Redis 安装目录下,文件名为 redi ...

  2. Redis学习笔记一:数据结构与对象

    1. String(SDS) Redis使用自定义的一种字符串结构SDS来作为字符串的表示. 127.0.0.1:6379> set name liushijie OK 在如上操作中,name( ...

  3. Redis学习笔记(二)Redis支持的5种数据类型的总结之String和Hash

    引言 在Redis学习笔记(一)中我们已经会安装并且简单使用Redis了,接下来我们一起来学习下Redis支持的5大数据类型. 简介 Redis是REmote DIctionary Server(远程 ...

  4. Redis学习笔记(2)——Redis的下载安装部署

    一.下载Redis Redis的官网下载页上有各种各样的版本,如图 但是官网下载的Redis项目不正式支持Windows.如果需要再windows系统上部署,要去GitHub上下载.我下载的是Redi ...

  5. redis 学习笔记(6)-cluster集群搭建

    上次写redis的学习笔记还是2014年,一转眼已经快2年过去了,在段时间里,redis最大的变化之一就是cluster功能的正式发布,以前要搞redis集群,得借助一致性hash来自己搞shardi ...

  6. Redis学习笔记~目录

    回到占占推荐博客索引 百度百科 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合). ...

  7. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  8. Redis学习笔记7--Redis管道(pipeline)

    redis是一个cs模式的tcp server,使用和http类似的请求响应协议.一个client可以通过一个socket连接发起多个请求命令.每个请求命令发出后client通常会阻塞并等待redis ...

  9. Redis学习笔记之ABC

    Redis学习笔记之ABC Redis命令速查 官方帮助文档 中文版本1 中文版本2(反应速度比较慢) 基本操作 字符串操作 set key value get key 哈希 HMSET user:1 ...

  10. (转)redis 学习笔记(1)-编译、启动、停止

    redis 学习笔记(1)-编译.启动.停止   一.下载.编译 redis是以源码方式发行的,先下载源码,然后在linux下编译 1.1 http://www.redis.io/download 先 ...

随机推荐

  1. linux中rpm安装

    目录 一:linux中rpm安装 1.rpm简介 2.区别 3.RPM命令五种基本模式 二:RPM安装全面解析 1,下载软件包 2, 安装软件包 3, 尝试卸载 4, 更新(升级) 5,软件包名称: ...

  2. STL中的隐性性能开销与副作用

    1 隐性性能开销 1.1 STL容器的clear的时间复杂度不是O(1) 很多人潜意识认为STL容器中clear()成员函数的时间复杂度为常量时间复杂度O(1).原因是大家觉得对于vector而言,c ...

  3. ApacheCN C/C++ 译文集 20211201 更新

    笨办法学C 中文版 前言 导言:C的笛卡尔之梦 练习0:准备 练习1:启用编译器 练习2:用Make来代替Python 练习3:格式化输出 练习4:Valgrind 介绍 练习5:一个C程序的结构 练 ...

  4. ApacheCN 数据科学译文集 2020.8

    协议:CC BY-NC-SA 4.0 不要担心自己的形象,只关心如何实现目标.--<原则>,生活原则 2.3.c 在线阅读 ApacheCN 面试求职交流群 724187166 Apach ...

  5. IDE集成git

    目录 简介 Git安装 IDE集成Git IDE集成Git代码的创建分享上传 代码的下载和普通上传 分子的创建以及合并 代码的回滚 查看历史版本 简介 Git 是一个开源的分布式版本控制软件,用以有效 ...

  6. 通过Xib加载控制器的View

    1.创建窗口self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];2.设置窗口根控制器2.1从XIB当 ...

  7. NSString基本概念

    1.NSString基本概念 什么是NSString? 一个NSString对象就代表一个字符串(文字内容) 一般称NSString为字符串类 2.NSString创建方式 最直接的方式(常量字符串) ...

  8. java中静态代码块初始化顺序

    (一)java 静态代码块 静态方法区别    一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下, ...

  9. 源码推荐 VVebo剥离的TableView绘制

    源码推荐 VVebo剥离的TableView绘制 https://github.com/johnil/VVeboTableViewDemo 此项目由VVebo剥离,希望你能通过这个demo看到我是如何 ...

  10. 聊一聊DTM子事务屏障功能之SQL Server版

    背景 前面写了两篇如何用 C# 基于 DTM 轻松实现 SAGA 和 TCC 的分布式事务,其中有一个子事务屏障的功能,很好的处理了空补偿.悬挂.重复请求等异常问题. https://dtm.pub/ ...