Redis系列-1 Redis介绍

背景:

本文介绍Redis相关知识,包括Redis的使用、单线程机制、事务、内存过期和淘汰机制。后续将在《三方件-3 Redis持久化机制》中介绍Redis基于RDB和AOF的持久化机制;在《三方件-4 Redis集群》介绍主从、哨兵和Cluster集群相关的内容;在《三方件-5 Redis缓存问题》中介绍缓存击穿,缓存穿透,缓存雪崩等问题。

1.Redis介绍

C语言开发的、基于内存的、跨平台的非关系型数据库(Nosql)。Redis基于键值对存储结果,键只能为字符串,值的类型有:字符串String、散列 Hash、列表 List、集合 Set、有序集合 Sorted Set。因其基于内存而脱离了常规数据库的IO操作,从而具备高性能的读写(10W/s的读和 8W/s写)。核心处理使用单线程进行,避免了并发问题,以及减少了线程切换带来的性能开销。
redis作为内存数据库,可用于存放缓存数据。在高并发场景中存放热点数据,可以提高数据访问速度,也可以缓解数据库压力;除此之外,分布式锁也是Redis的一个应用场景。
Memcached 作为Nosql,常用于Redis做比较, 存在以下几个方面的差异:
[1] 效率: Redis基于单线程(memcached使用多线程),读写小数据时,Redis性能超过Memcached; 处理较大数据时,Memcached性能超过Redis
[2] 值的类型:redis支持多种数据类型; Memcached 仅支持字符串
[3] 持久化:Redis支持RDB和AOF两种持久化策略,宕机后可恢复数据; Memcached纯内存存储,不支持持久化
[4] 数据同步和分布式:redis基于持久化数据提供了实例之间的数据同步,Redis支持主从复制和数据分区,适用于构建分布式系统 而Memcached不支持
[5] 事务和Lua脚本: Redis支持事务和Lua脚本,可以执行复杂操作; Memcached 不支持
总之,Memcached适用于大量并发读和简单键值存储的场景,而Redis适用于复杂数据结构、数据有持久化或分布式要求的场景等。

2.Java使用方式

可借助docker快速安装redis, 准备redis.conf配置文件:

dir ./
dbfilename dump.rdb
save 900 1
save 300 10
save 60 10000appendonly yes
appendfilename "appendonly.aof"
appendfsync everysecrequirepass xxxxxxx
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

使用docker安装redis环境:

# 准备配置文件和持久化数据存放路径
mkdir -p /path/to/redisdata
touch /path/to/redis.conf# 启动docker容器
docker run --restart=always
-p 16379:6379
--name myredis
-v /path/to/redis.conf:/etc/redis/redis.conf 
-v /path/to/redisdata:/data 
-d redis:7.0.12 redis-server /etc/redis/redis.conf

运行后,docker的工作目录为/data,因此可在宿主机的/path/to/redisdata目录下查看持久化数据。
Java中存在以下三种使用Redis方式。

2.1 Jedis

Jedis提供了比较全面的Redis命令(同步的API)支持,本质上是通过socket直连Redis服务器,一个Jedis对象对应一个连接,因此Jedis对象本身是线程不安全的。以下通过案例介绍使用方式。
引入pom依赖:

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version>
</dependency>

案例:

public class JedisDemo {public static void main(String[] args) {// Redis 服务器配置String host = "127.0.0.1";int port = 6379;String password = "123456";try (Jedis jedis = new Jedis(host, port)) {// 校验密码jedis.auth(password);// 操作1:添加键值对jedis.set("keyStr", "myStr");// 操作2:根据键取值String value = jedis.get("keyStr");System.out.println("键 keyStr 的值为: " + value);// 操作3:根据键删除键值对jedis.del("keyStr");} catch (Exception e) {System.out.println(e);}}
}

2.2 Redisson

Redission提供了很多分布式功能,如常见的分布式锁。
引入pom依赖:

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.1</version>
</dependency>

案例:

public class RedissonDemo {public static void main(String[] args) throws InterruptedException {RedissonClient redisson = getRedissonClient();RLock lock = redisson.getLock("myLock");// 4. 加锁操作lock.lock();try {// 模拟耗时操作System.out.println("Begin...");Thread.sleep(1000 * 10);System.out.println("End.");} finally {// 5. 释放锁lock.unlock();}redisson.shutdown();}private static RedissonClient getRedissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("123456");RedissonClient redisson = Redisson.create(config);return redisson;}
}

2.3 Lettuce

Lettuce基于Netty框架实现,使用非阻塞IO与Redis服务器通信,是一个高性能的Redis客户端。SpringBoot提供了Starter, 可以在SpringBoot项目中轻松引入。
引入pom依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version>
</dependency>

在application.yml中添加配置信息:

spring:redis:host: 127.0.0.1port: 6379#Redis使用的数据库database: 0#连接超时事件毫秒timeout: 18000lettuce:pool:#连接池最大连接数max-active: 20#最大阻塞等待时间max-idle: 5#连接池最小空闲连接min-idle: 0

添加配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}

案例:

@SpringBootTest
public class MyRedisTest {@Autowiredprivate RedisTemplate redisTemplate;@Testpublic void testMyRedis() {String key = "key001";String value = "value001";redisTemplate.opsForValue().set(key,value);assertEquals(value, redisTemplate.opsForValue().get(key));}
}

上面通过redisTemplate对象通过不同方法封装了对不同数据类型的处理:
[1] opsForValue()中封装了操作String类型的方法;
[2] opsForList()中封装了操作List类型的方法;
[3] opsForSet()中封装了操作Set类型的方法;
[4] opsForHash()中封装了操作Hash类型的方法;
[5] opsForZSet()中封装了操作ZSet类型的方法.

3.单线程机制

Redis的核心工作由单线程完成,即使用一个线程完成对内存数据库的读写,由此保证了线程安全性。
虽然在Redis6.0(2020)后引入了多线程机制,但是仅将IO通信部分委托给多线程(IO多路复用),核心部分仍为单线程(后用核心线程表示)。由此,将redis核心线程从IO中解脱出来,专门进行内存数据库的读写,接收和发送由多线程这个管家来完成。
在这里插入图片描述

如上图所示,selector线程阻塞监听客户端的请求(修改和查询数据库),当有请求准备完成后,通知核心线程去操作数据库,操作的结果也通过建立好的通道返回给客户端。
上图本质上就是NIO+核心线程的模型,核心线程读写数据库。
再说一下为什么核心线程不用多线程,现在服务器都是多CPU、多核心,只要处理好线程安全问题,完全可以使用多线程处理核心业务(数据库读写):一方面,现有的Redis处理的读写速度是8~10W每秒,即使再堆CPU内核和线程也无法继续提高数据库操作速度,本质原因是短板效应——内存和IO的速度远低于CPU,尽管通过多路复用IO已经缓解了IO部分的效率问题;另一方面,线程的切换和线程安全问题可能会带来性能开销和复杂的程序设计问题。

4.Redis事务

Redis中指令都是单线程执行的,因此每个指令原子的、隔离的和持久性的。当需要将多个指令串起来执行时,需要用到Redis事务机制。
Redis中的事务属于伪事务,不具备原子性和一致性,仅具备隔离性和持久性。通过Redis事务API可以将多个命令串起来输入到Redis中,Redis会依次执行这些指令,当有指令执行失败时,不会停止和回滚,而是忽略异常继续执行下一个指令,从而丧失了原子性和一致性。多个客户端向Redis服务器发送事务指令时,Redis服务器会按照提交给Redis的顺序依次执行各个事务( Redis的事务可以保证一个事务内的命令依次执行而不被其他命令插入 ),从而保证了事务之间的隔离性和持久性。
Redis事务通过MULTI、EXEC、DISCARD三个指令来支持事务,
MULTI与DISCARD指令组合时,不会执行中间的指令(直接丢弃);MULTI与EXEC执行组合,将多个读写操作进行串联:

53:0>multi
"OK"
53:0>set "key1" "value1"
"QUEUED"
53:0>set "key2" "value2"
"QUEUED"
53:0>exec
1) "OK"
2) "OK"
3) "OK"
4) "OK"
5) "OK"
53:0>get key1
"value1"
53:0>get key2
"value2"
53:0>

在执行事务前,可以通过watch监听感兴趣的键是否发送变化。watch属于乐观锁,当事务命令被执行时,会比较watch关注的键是否在此阶段(watch执行到事务执行之间)是否发送了变化;如果有变化,则取消执行事务;否则会正常执行事务;最后(无论是否执行事务)取消watch监控。

5.数据过期

redis可以对数据添加过期时间,数据过期后会被redis删除。关于过期数据的删除, 存在以下三种策略:
[1] 立即删除:
当数据过期后,立即被redis删除;可以保证内存的最大新鲜度,即内存里的数据都是有效的。由于每条数据过期,都会执行删除操作,极大占用了CPU资源。
[2] 惰性删除
当数据过期后,不会立即删除,直到下次数据被访问时才会删除。该策略对CPU资源比较友好,但是内存中会存在大量已过期的数据。
[3] 定期删除
立即删除对内存友好而CPU不友好,而惰性删除对CPU友好而内存不友好,定期删除策略在二者中做了折中处理。
定期扫描过期数据,扫描到过期数据时立即删除,定期之外的数据仍采用惰性删除策略。

6.内存淘汰

Redis可通过maxmemory配置修改Redis占有内存的最大值。 当内存告急时(达到maxmemory)时,Redis通过内存淘汰机制保证服务继续运行。根据是否删除、键的选择(是否设置过期时间)、删除方式(随机、LFU、LRU)的组合,有如下8种淘汰策略(通过maxmemory-policy进行配置):
[1] noeviction:默认的配置,支持查看和删除数据,拒绝所有写入操作并返回客户端错误消息;

[2] volatile-ttl:在设置了过期时间的key中, 淘汰过期时间剩余最短的;
[3] volatile-lru: 在设置了过期时间的key中, 根据LRU淘汰;
[4] volatile-lfu: 在设置了过期时间的key中, 根据LFU淘汰;
[5] volatile-random: 在设置了过期时间的key种, 随机淘汰;

[6] allkeys-lru: 从所有 key 中使用 LRU 算法进行淘汰;
[7] allkeys-lfu: 从所有 key 中使用 LFU 算法进行淘汰;
[8] allkeys-random: 从所有 key中随机淘汰。

其中: LRU(Least Recently Used)表示最近最少使用,LFU(Least Frequently Used)表示最不经常使用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python 11Pandas数据可视化实验

实验目的&#xff1a; 学会使用Pandas操作数据集&#xff0c;并进行可视化。 数据集描述&#xff1a; 该数据集是CNKI中与“中药毒理反应”相关的文献信息&#xff0c;包含文章题目、作者、来源&#xff08;出版社&#xff09;、摘要、发表时间等信息。 实验要求&#xff1…

QT-QTCreator环境配置

准备工作&#xff1a; 下载QT: 链接&#xff1a;https://pan.baidu.com/s/1prJcsC4DGqhKiXvLuPQFVA?pwd60b3 提取码&#xff1a;60b3下载WindowsKits&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1QNiS3HpbH5M5kXx5AhkqnQ?pwde2h8 提取码&#xff1a;e2h8安装的…

Python-快速搭建一个管理平台

目录 &#x1f4dc; 准备工作 一、项目介绍 ✨ 二、制作数据库表 添加信息 ⚒️ 三、运行client.exe &#x1f680; 1、连接数据库&#xff0c;选择对应表&#xff0c;生成代码 2、把后端代码依次复制到项目中 3、把前端代码依次复制到前端项目中 4、添加路由 四、运行后端项目…

[1678]旅游景点信息Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 旅游景点信息管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql…

数据结构:图

数据结构&#xff1a;图 前言 在自动化程序分析中&#xff0c;图和树的一些算法起到了至关重要的作用&#xff0c;所以在开始自动化程序分析的研究前&#xff0c;我用了两天复习了一遍数据结构中的图。本章主要内容有图的基本概念&#xff0c;图的存储和图相关的经典算法&…

OpenCV(二)—— 车牌定位

从本篇文章开始我们进入 OpenCV 的 Demo 实战。首先&#xff0c;我们会用接下来的三篇文章介绍车牌识别 Demo。 1、概述 识别图片中的车牌号码需要经过三步&#xff1a; 车牌定位&#xff1a;从整张图片中识别出牌照&#xff0c;主要操作包括对原图进行预处理、把车牌从整图…

数据结构--顺序表经典OJ题

例1&#xff1a;合并有序顺序表 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff…

测试开发工具开发 -JMeter 函数二次开发

在JMeter中开发自定义函数是一个常见的需求&#xff0c;允许我们扩展JMeter的功能以适应特定的测试需求。自定义函数可以用来处理数据&#xff0c;生成输出&#xff0c;或者执行特定的运算。通过JMeter函数二次开发可以帮我们解决实际测试过程中造数难的问题 用过JMeter的同学…

JAVASE->数据结构|顺序表底层逻辑

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1. 什么是 List 2. List 常见接口介绍 3. …

java并发编程-AQS介绍及源码详解

介绍 AQS 的全称为 AbstractQueuedSynchronizer &#xff0c;就是抽象队列同步器。 从源码上可以看到AQS 就是一个抽象类&#xff0c;它继承了AbstractOwnableSynchronizer&#xff0c;实现了java.io.Serializable接口。 public abstract class AbstractQueuedSynchronizere…

信号与线性系统 1绪论

信号 信号是随时间变化的某种物理量&#xff08;狭义&#xff09; 本课程中&#xff0c;信号用 函数&#xff08;而且是一维函数&#xff09;表示 连续 离散 信号分类 确定与随机&#xff1a;是否能以确定的时间函数表示离散与连续&#xff1a;是用全体实数还是特定整数来描述…

普乐蛙景区vr体验馆VR游乐场设备身历其境体验

小编给大家推荐一款gao坪效产品【暗黑战车】&#xff0c;一次6人同乘&#xff0c;炫酷外观、强大性能和丰富内容适合各个年龄层客群&#xff0c;紧张刺激的VR体验让玩家沉浸在元宇宙的魅力中&#xff0c;无论是节假日还是平日&#xff0c;景区商场助力门店提高客流量和营收~ ◆…

苹果和OpenAI再续前缘,iOS 18会是颠覆级的吗?|TodayAI

据彭博社最新报道&#xff0c;苹果公司已经与人工智能领域的先锋企业OpenAI重启了对话&#xff0c;双方目前正在讨论一项可能的合作&#xff0c;以将OpenAI的生成式人工智能技术整合到苹果即将推出的iOS 18操作系统中。这一举措表明&#xff0c;苹果正加速其在人工智能技术上的…

Go Web 开发基础【用户登录、注册、验证】

前言 这篇文章主要是学习怎么用 Go 语言&#xff08;Gin&#xff09;开发Web程序&#xff0c;前端太弱了&#xff0c;得好好补补课&#xff0c;完了再来更新。 1、环境准备 新建项目&#xff0c;生成 go.mod 文件&#xff1a; 出现报错&#xff1a;go: modules disabled by G…

【JavaEE网络】网络编程及其应用概述

目录 面向字节流粘包问题 TCP异常情况TCP/UDP对比 网络层重点协议IP协议IP地址 面向字节流 粘包问题 在面向字节流的情况下&#xff0c;会产生一些其他的问题&#xff1a;粘包问题&#xff0c;这里“粘”的是“应用层数据报”&#xff0c;通过TCP read/write的数据&#xff0…

AI手机,走入小径分岔的花园

博尔赫斯在他的成名作《小径分岔的花园》里&#xff0c;描述了一种奇妙的世界观&#xff1a;一个可能性被选择之后&#xff0c;出现了许多不同的后世&#xff0c;许多不同的时间。 在现实世界中&#xff0c;选择不会如此神奇。但站在岔路口的抉择&#xff0c;也一定会带来结果的…

Mysql的关联查询以及语句

一、mysql的连接查询 1、等值连接 这里是三张表的等值连接 select rp.role_id,rp.permission_id from role_permission rp, role r, permission p where rp.role_idr.id and rp.permission_idp.id 2、内连接&#xff1a; 角色&#xff1a;系统管理员 是否拥有权限&#xf…

【Docker】docker部署lnmp和搭建wordpress网站

环境准备 docker&#xff1a;192.168.67.30 虚拟机&#xff1a;4核4G systemctl stop firewalld systemctl disable firewalld setenforce 0 安装docker #安装依赖包 yum -y install yum-utils device-mapper-persistent-data lvm2 #设置阿里云镜像 yum-config-manager --add…

【Web】D^3CTF之浅聊d3pythonhttp——TE-CL请求走私

目录 step0 题目信息 step1 jwt空密钥伪造 step1.5 有关TE&CL的lab step2 TE-CL请求走私 payload1 payload2 step0 题目信息 注意到题目源码前端是flask写的&#xff0c;后端是web.py写的 frontend from flask import Flask, request, redirect, render_templat…

基于Python的人脸识别系统设计与实现(论文+源码)_kaic

基于Python的人脸识别系统设计与实现 摘 要 随着人工智能的发展,人脸识别系统在我们的生活中越来越被广泛应用。人脸识别系统是指能够从数字图像或视频源中识别人的技术。人脸识别系统可以通过多种方法工作&#xff0c;但是&#xff0c;它们通常是通过将给定图像中的面部特征与…