1.Redis介绍

REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的 key-value 存储系统,是跨平台的非关系型数据库,Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储的非关系型数据库,常被用于分布式缓存,作为进程外的缓存,它具有以下特点:

1.方便扩展

2.大数据量高性能

3.八大数据结构

4.分布式存储

2.什么时候使用Redis

1.在分析什么场景使用Redis时,我们首先看下面的系统设计图,我们用户发起请求到达Nginx,然后由Nginx来负载均衡到不同的服务实例,服务实例去访问数据库,正常来看没什么问题,但是如果集群的单个实例是一个独立的系统,如果我们在单个系统中使用了缓存就会出现问题,具体是什么问题呢?

2.当用户请求被负载均衡到不同的服务器时,第一个请求被服务实例1接收,它的执行流程是查询数据库返回然后缓存,第二个用户请求同样的内容,但是被负载均衡分配到服务实例2,对于服务实例2来说这是一个全新的请求,那么又会访问数据库,对于我们来说这是很浪费的,当然在正常请求比较少造成的影响不大,但是如果请求并发较高,缓存的命中几率被放大,导致请求直接访问数据库造成阻塞,影响系统可用性。

同理我们可以这样理解,我们为了服务器更好的承载,加入了更多的服务实例,那么组成集群的单个实例越多,与缓存命中率是成反比的,当然我们可以在负载均衡时使用一些措施,使用iphash,来将某一客户端的访问与固定单个实例绑定,但是比较局限,不够灵活,那么应该怎么去更好的解决这个问题呢?

此时我们尝试在上述的架构图中加入Redis,利用Redis的读写高性能的特点,来做统一的缓存,用于降低数据库的压力以及保证系统高可用,因为从读写速度而言CPU > 内存 > 磁盘

3.Redis通信原理
1.单线程和多线程对比

1.单线程原子性操,一个线程做一个任务,不需要锁也不需要线程的上下文的切换。

2.多线程要实现原子性,涉及到各种锁,上下文的切换性能的消耗。

3.单线程多进程 ,可以根据我们的服务,开启多个实例。

2.IO多路复用

多路复用的概念就是多个IO复用一个线程处理,简单的意思是在一个操作里同时监听多个输入输出源,它和我们的异步区别就是,前者是轮训等待任务执行完成拿到结果,而后者则是在任务执行的过程中,自己去执行其他的任务,在不同的操作系统对多路复用有不同的实现,例如Windows内核中实现根据Select 而LInux内核中的实现是Epoll接下来我们简单介绍下他们2种的区别。

Select

用户请求到达内核,内核将请求封装成一个句柄描述,放入本地消息队列,然后循环队列中的所有句柄,判断是否处理完成,如果完成待所有的循环走完后,就将请求转发到用户进程,但是会随着连接数增大,性能下降,处理数据太大的话,性能很差。

Epoll

用户请求到达内核,内核将请求封装成一个句柄描述和时间回调,放入本地消息队列,待处理完毕就会触发事件,不用去循环队列中的所有消息,内核再将请求转发到用户进程,随着连接数增大,性能基本没影响,适合并发强度大的场景.

4.基本数据结构

在实际过程中,我们利用Stackexchange.Redis来进行操作.Net与Redis的互操作,当然也可以使用Servicestack.Redis他也同样可以实现交互。

1.web中安装和配置环境

1.创建Net6 WebApi项目,并且NuGet下载StackExchange.Redis最新版安装到项目中。

2.扩展Redis客户端初始化连接,并且在Startup中添加到IOC容器

//扩展连接客户端
public static class RedisServiceCollectionExtensions
{
public static IServiceCollection AddRedisCache(this IServiceCollection services, string connectionString)
{
ConfigurationOptions configuration = ConfigurationOptions.Parse(connectionString);
ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(connectionString);
services.AddSingleton(connectionMultiplexer);
return services;
}
}
//注入容器
services.AddRedisCache("127.0.0.1:6379,password=xxx,connectTimeout=2000");

3.在Api中创建RedisController控制器,并注入ConnectionMultiplexer

public class RedisController : ControllerBase
{
private readonly ConnectionMultiplexer _connectionMultiplexer; private readonly IDatabase db;
public RedisController(ConnectionMultiplexer connectionMultiplexer)
{
_connectionMultiplexer = connectionMultiplexer;
db = _connectionMultiplexer.GetDatabase(0);
}
}
2.string类型

1.string类型数据时Redis中最基础的类型,其他类型在此基础上构建.

2.string类型不仅仅会开辟占有的空间,还会预留一部分空间,最大能存储 512MB,可以是简单的Key,value,也可以是复杂的xml/json的字符串、二进制图像或者音频的字符串、以及可以是数字的字符串。

TestData testData = new TestData();
//首先序列化
string json = JsonConvert.SerializeObject(entity);
//设置30秒后失效
db.StringSet("TestData", demojson,TimeSpan.FromSeconds(30));
3.Set 集合

1.redis集合(set)类型和list列表类型类似,都可以用来存储多个字符串元素的集合

2.和list不同的是set集合当中不允许重复的元素。而且set集合当中元素是没有顺序的,不存在元素下标,intzset 最大存储2的64次方,或者内容超过512个字节就使用HashTable

3.Redis中的Set数据结构它由数组HashTable组成,每一个数组值都经过hash计算,支持集合内的增删改查,并且支持多个集合间的交集、并集、差集操作

RedisValue[] values = db.SetMembers("testdatas");
List<TestData> data = new List<TestData>();
if (values.Length == 0)
{
// 2、从数据库中查询
data = testData.Add();
// 3、存储到redis中
List<RedisValue> redisValues = new List<RedisValue>();
foreach (var item in data)
{
string json = JsonConvert.SerializeObject(item);//序列化
redisValues.Add(json);
}
db.SetAdd("testdatas", redisValues.ToArray());
return data;
} // 4、序列化,反序列化
foreach (var redisValue in values)
{
TestData t = JsonConvert.DeserializeObject<TestData>(redisValue);//反序列化
data.Add(t);
}
4.hash

1.Redis hash数据结构 是一个键值对(key-value)集合,它是一个 string 类型的 field 和 value 的映射表。

2.hash数据结构相当于在value中又套了一层key-value型数据。

 //根据HashKey获取字段为AccessTime 的值
string time =db.HashGet("HashKey", "AccessTime");
if (string.IsNullOrEmpty(time))
{
test = data.FirstOrDefault(s => s.Id == 1);
//设置HashKey为AccessTime字段的值
db.HashSet("HashKey", "AccessTime", test.AccessTime);
}
// 次数加1
db.HashIncrement("HashKey", "AccessTime");
5.ZSet (有序集合)

1.它的实现是由Zskiplist+HashTable

2.redis有序集合也是集合类型的一部分,它保留了集合中元素不能重复的特性,但是不同的是,有序集合给每个元素多设置了一个分数,利用该分数作为排序的依据。

6.List

1.list类型是用来存储多个有序的字符串的,列表当中的每一个字符看做一个元素.

2.一个列表当中可以存储有一个或者多个元素,redis的list支持存储2^32次方-1个元素。

3.redis可以从列表的两端进行插入(pubsh)和弹出(pop)元素,支持读取指定范围的元素集,

或者读取指定下标的元素等操作。redis列表是一种比较灵活的链表数据结构,它可以充当队列或者栈的角色

4.reids的链表结构,可以轻松实现阻塞队列,可以使用左进右出的命令组成来完成队列的设计。比如:数据的生产者可以通过Lpush命令从左边插入数据,多个数据消费者,可以使用BRpop命令阻塞的“抢”列表尾部的数据。

7.事务操作

1.Redis中不支持事务回滚

2.在sqlserver中如果开启事务,修改数据,如果新的会话去同时操作会等待释放锁,而Redis中,在开启事务前首先监听了Key的版本号,如果在事务期间,新的会话可以修改目标Key,但是会影响当前事务提交不成功。

ITransaction transaction = db.CreateTransaction();
//执行操作
transaction.HashSetAsync("HashKey", "AccessTime", test.AccessTime);
bool commit = transaction.Execute();
if (commit)
{
Console.WriteLine("提交成功");
}
else
{
Console.WriteLine("提交失败");
}
5.Redis持久化
1.RDB 快照

RDB是Redis用来进行持久化的一种方式,是把当前内存中的数据集快照写入磁盘,恢复时是将快照文件直接读到内存里,持久化的RDB文件可以拷贝到不通过的服务,将数据

加载。

  • 1.bgsave :父进程启动一个子进程,由子进程将内存保存在硬盘文件,期间不会影响其他的指令操作.

  • 2.save:将内存数据镜像保存为RDB文件,由于redis是单线程模型期间会阻塞redis服务进程,redis服务不再处理任何指令,直到RDB文件创建完成.

  • 无论是bgsave还是save,其过程如下:

1.生成临时rdb文件,并写入数据.

2.完成数据写入,用临时文代替代正式rdb文件.

3.删除原来的db文件

save 900 1 #15分钟内有一条数据被修改则保存
save 300 10 #300秒有10条修改则保存
save 60 10000 #60秒内有10000条数据修改则保存 # 是否压缩rdb文件
rdbcompression yes # rdb文件的名称
dbfilename redis-6379.rdb # rdb文件保存目录
dir ~/redis

自动触发备份原理

1.Redis有一个周期性操作函数,默认每隔100ms执行一次,它的其中一项工作就是检查自动触发Bgsave命令的条件是否成立.

2.计数器记录了在上一次成功的持久化后,redis进行了多少次写操作,其值在每次写操作之后都加1,在成功完成持久化后清零.

RDB的优点

  1. 与AOF方式相比,通过rdb文件恢复数据比较快。
  2. rdb文件非常紧凑,适合于数据备份。
  3. 通过RDB进行数据备,由于使用子进程生成,所以对Redis服务器性能影响较小。
2.AOF 文件追加

Redis服务每次结束一个事件循环之前,都会调用flushAppendOnly函数,其中调用write函数将aof_buf写入文件,aof文件可以被修改。

1.开启AOF配置

# 开启aof机制
appendonly yes # aof文件名
appendfilename "appendonly.aof" # 写入策略,always表示每个写操作都保存到aof文件中,也可以是everysec或no
appendfsync always # 默认不重写aof文件
no-appendfsync-on-rewrite no # 保存目录
dir ~/redis

1.在配置文件开启将appendonly设为yes

2.设置文件路径dir,可以使用默认在当前目录下

3.设置追加方式一共有三种,一般选用第二种方式

  • 1.appendfsync always 只要有读写,性能最低但是安全性最高
  • 2.appendfsync everysec 1s钟的周期
  • 3.appendfsync no 等业务不繁忙的时候,这种操作最不可靠 性能最高但是安全性最低

2.AOF文件解读

1.打开追加的持久化文件

  • 第一个指令*2代表有2个参数,$6第一个参数6个字节为select, $1代表第二个参数0个字节
  • 第二个指令*3代表有3个参数,$3第一个参数3个字节为set,$4第2个参数4个字节为name,$3第3个参数3个字节为lll
3.Redis持久化加载

上面我们介绍了Redis支持2种持久化的方式,那我们需要判断在加载时选择哪种方式,因为不可能同时选择2种,其实在Redis加载时会判断是否开启了AOF,如果开启了AOF就会加载AOF文件,如果没有开启,那么就会选择加载RDB文件。

缓存中间件-Redis(一)的更多相关文章

  1. 老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化

    引言 今天周末,我在家坐着掐指一算,马上又要到一年一度的金九银十招聘季了,国内今年上半年受到 YQ 冲击,金三银四泡汤了,这就直接导致很多今年毕业的同学会和明年毕业的同学一起参加今年下半年的秋招,这个 ...

  2. 高并发系列之——缓存中间件Redis

    1 概念和使用场景 下载路径 2 基本存储类型 String List Set SortedSet Hash 3 事务 单线程执行,即只能保证一个client发起的事务中的命令可以连续的执行,而中间不 ...

  3. 缓存中间件-Redis(二)

    在上一篇中我们简单总结和介绍了Redis的几个方面 1.使用Redis背景 2.Redis通信多路复用的基本原理 3.Redis基本数据结构 4.Redis持久化方式 这一篇我们使用简单的业务场景来介 ...

  4. redis缓存中间件基础

    前序: 默认使用SimpleCacheConfiguration 组件ConcurrentMapCacheManager==ConcurrentMapCache将数据保存在ConcurrentMap& ...

  5. .net 分布式架构之分布式缓存中间件

    开源git地址: http://git.oschina.net/chejiangyi/XXF.BaseService.DistributedCache 分布式缓存中间件  方便实现缓存的分布式,集群, ...

  6. 再谈缓存和Redis

    自从上次分享<Redis到底该如何利用?>已经有1年多了,这1年经历了不少.从码了我们网站的第一行开始到现在,我们的缓存模块也不断在升级,这之中确实略有心得,最近也有朋友探讨缓存,觉得可以 ...

  7. springboot~hazelcast缓存中间件

    缓存来了 在dotnet平台有自己的缓存框架,在java springboot里当然了集成了很多,而且缓存的中间件也可以进行多种选择,向redis, hazelcast都是分布式的缓存中间件,今天主要 ...

  8. 谈缓存和Redis

    自从上次分享<Redis到底该如何利用?>已经有1年多了,这1年经历了不少.从码了我们网站的第一行开始到现在,我们的缓存模块也不断在升级,这之中确实略有心得,最近也有朋友探讨缓存,觉得可以 ...

  9. MyBatis加强(1)~缓存机制(一级缓存、二级缓存、第三方缓存技术redis、ehcache)

    一.缓存机制 使用缓存可以使应用更快地获取数据,避免频繁的数据库交互操作,尤其是在查询越多,缓存命中率越高 的情况下,缓存的作用就越明显. 1.缓存原理:Map ■ 查询时,先从缓存区查询:找到,返回 ...

随机推荐

  1. MySQL数据库阶段学习目录

    MySQL数据库学习目录 MySQL数据库初识 MySQL的库表详细操作 MySQL行(记录)的详细操作 快捷使用数据库.表.表内容增删改查 MySQL之单表查询 MySQL之多表查询 Navicat ...

  2. 使用tc ingress来限速接收方向

    Linux中的QoS分为入口(Ingress)部分和出口(Egress)部分,入口部分主要用于进行入口流量限速(policing),出口部分主要用于队列调度(queuing scheduling).大 ...

  3. 除了增删改查你对MySQL还了解多少?

    目录 除了增删改查你对MySQL还了解多少? MySQL授权远程连接 创建用户.授权 客户端与服务器连接的过程 TCP/IP 命名管道和共享内存 Unix域套接字文件 查询优化 MySQL中走与不走索 ...

  4. kvm管理查看信息,添加,删除,暂停恢复,克隆等

    KVM virsh管理指令 virsh 查看帮助信息 查看命令帮助 [root@KVM ~]# virsh Welcome to virsh, the virtualization interacti ...

  5. 什么是Spring MVC框架的控制器?

    控制器提供一个访问应用程序的行为,此行为通常通过服务接口实现.控制器解析用户输入并将其转换为一个由视图呈现给用户的模型.Spring用一个非常抽象的方式实现了一个控制层,允许用户创建多种用途的控制器.

  6. 面试问题之计算机网络:TCP滑动窗口

    滑动窗口协议是传输层进行流量控制的一种措施,接收方通过通知发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的,并且滑动窗口分为接收窗口和发送窗口.TC ...

  7. memcached 是原子的吗?

    所有的被发送到 memcached 的单个命令是完全原子的.如果您针对同一份数据 同时发送了一个 set 命令和一个 get 命令,它们不会影响对方.它们将被串行化. 先后执行.即使在多线程模式,所有 ...

  8. 学习Solr(三)

    本文以solr5为例说明在linux系统上单机安装过程. 一.    solr的安装 1.   solr能够安装在不同的操作系统上,安装solr前需要安装何时的JRE.当前版本5.5最低需要JRE1. ...

  9. 学习openstack(八)

      一.OpenStack初探 1.1 OpenStack简介 OpenStack是一整套开源软件项目的综合,它允许企业或服务提供者建立.运行自己的云计算和存储设施.Rackspace与NASA是最初 ...

  10. 【AD】Altium Designer 原理图的绘制

    原理图设置基础 原理图的设置    设置原理图图纸大小 在原理图的绘制过程中,各个元件的大小是不能调整的. 如果原理图纸张放不下,需要对图纸进行设置:设计->文档选项,右键->选项-> ...