4.27日学习打卡----初学Redis(四)

ops/2025/2/12 3:28:14/

4.27日学习打卡

目录:

  • 4.27日学习打卡
  • 一. Redis的配置文件
  • 二. Redis构建Web应用实践
    • 环境搭建
    • redis的优点
    • 引入本地缓存
    • Google 开源工具Guava
    • Guava实现本地缓存

在这里插入图片描述

一. Redis的配置文件

在这里插入图片描述

在Redis的解压目录下有个很重要的配置文件 redis.conf ,关于Redis的很多功能的配置都在此文件中完成的,一般为了不破坏安装的文件,出厂默认配置最好不要去改。

units单位

配置大小单位,开头定义基本度量单位,只支持bytes,大小写不敏感。
在这里插入图片描述
INCLUDES

Redis只有一个配置文件,如果多个人进行开发维护,那么就需要多个这样的配置文件,这时候多个配置文件就可以在此通过 include /path/to/local.conf 配置进来,而原本的 redis.conf 配置文件就作为一个总闸。
在这里插入图片描述
NETWORK
在这里插入图片描述

参数:

  • bind:绑定redis服务器网卡IP,默认为127.0.0.1,即本地回环地址。这样的话,访问redis服务只能通过本机的客户端连接,而无法通过远程连接。如果bind选项为空的话,那会接受所有来自于可用网络接口的连接。
  • port:指定redis运行的端口,默认是6379。由于Redis是单线程模型,因此单机开多个Redis进程的时候会修改端口。
  • timeout:设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接。默认值为0,表示不关闭。
  • tcp-keepalive :单位是秒,表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一直阻塞,官方给出的建议值是300s,如果设置为0,则不会周期性的检测。

GENERAL
在这里插入图片描述

具体配置详解:

  • daemonize:设置为yes表示指定Redis以守护进程的方式启动(后台启动)。默认值为 no
  • pidfile:配置PID文件路径,当redis作为守护进程运行的时候,它会把 pid 默认写到 /var/redis/run/redis_6379.pid 文件里面
  • loglevel :定义日志级别。默认值为notice,有如下4种取值:
  • debug(记录大量日志信息,适用于开发、测试阶段)
  • verbose(较多日志信息)
  • notice(适量日志信息,使用于生产环境)
  • warning(仅有部分重要、关键信息才会被记录)
  • logfile :配置log文件地址,默认打印在命令行终端的窗口上
  • databases:设置数据库的数目。默认的数据库是DB 0 ,可以在每个连接上使用select 命令选择一个不同的数据库,dbid是一个介于0到databases - 1 之间的数值。默认值是 16,也就是说默认Redis有16个数据库。

SNAPSHOTTING

这里的配置主要用来做持久化操作。
在这里插入图片描述

参数:
save:这里是用来配置触发 Redis的持久化条件,也就是什么时候将内存中的数据保存到硬盘
save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存
save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存
save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存

REPLICATION
在这里插入图片描述

参数:

  • slave-serve-stale-data:默认值为yes。当一个 slave 与 master 失去联系,或者复制正在进行的时候,

slave 可能会有两种表现:

  1. 如果为 yes ,slave 仍然会应答客户端请求,但返回的数据可能是过时,或者数据可能是空的在第一次同步的时候
  2. 如果为 no ,在你执行除了 info he salveof 之外的其他命令时,slave 都将返回一个 “SYNC with master in progress” 的错误
  • slave-read-only:配置Redis的Slave实例是否接受写操作,即Slave是否为只读Redis。默认值为yes。
  • repl-diskless-sync:主从数据复制是否使用无硬盘复制功能。默认值为no。
  • repl-diskless-sync-delay:当启用无硬盘备份,服务器等待一段时间后才会通过套接字向从站传送RDB文件,这个等待时间是可配置的。
  • repl-disable-tcp-nodelay:同步之后是否禁用从站上的TCP_NODELAY 如果你选择yes,
  • redis会使用较少量的TCP包和带宽向从站发送数据。

SECURITY
在这里插入图片描述
requirepass:设置redis连接密码。
比如: requirepass 123 表示redis的连接密码为123。
在这里插入图片描述
CLIENTS
**加粗样式**

参数:
maxclients :设置客户端最大并发连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件。 描述符数-32(redis server自身会使用一些),如果设置 maxclients为0 。表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息

MEMORY MANAGEMENT
在这里插入图片描述

参数:

  • maxmemory:设置Redis的最大内存,如果设置为0 。表示不作限制。通常是配合下面介绍的maxmemory-policy参数一起使用。
  • maxmemory-policy :当内存使用达到maxmemory设置的最大值时,redis使用的内存清除策略。有以下几种可以选择:
    1)volatile-lru 利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
    2)allkeys-lru 利用LRU算法移除任何key
    3)volatile-random 移除设置过过期时间的随机key
    4)allkeys-random 移除随机ke
    5)volatile-ttl 移除即将过期的key(minor TTL)
    6)noeviction noeviction 不移除任何key,只是返回一个写错误 ,默认选项
  • maxmemory-samples :LRU 和 minimal TTL 算法都不是精准的算法,但是相对精确的算法(为了节省内存)。随意你可以选择样本大小进行检,redis默认选择3个样本进行检测,你可以通过maxmemory-samples进行设置样本数。

APPEND ONLY MODE
在这里插入图片描述

参数:

  • appendonly:默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。但是redis如果中途宕机,会导致可能有几分钟的数据丢失,根据save来策略进行持久化,Append Only File是另一种持久化方式, 可以提供更好的持久化特性。Redis会把每次写入的数据在接收后都写入appendonly.aof文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。默认值为no。
  • appendfilename :aof文件名,默认是"appendonly.aof"
  • appendfsync:aof持久化策略的配置;no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快;always表示每次写入都执行fsync,以保证数据同步到磁盘;everysec表示每秒执行一次fsync,可能会导致丢失这1s数据

LUA SCRIPTING
在这里插入图片描述

参数:
lua-time-limit:一个lua脚本执行的最大时间,单位为ms。默
认值为5000.

REDIS CLUSTER
在这里插入图片描述

参数:

  • cluster-enabled:集群开关,默认是不开启集群模式。
  • cluster-config-file:集群配置文件的名称。
  • cluster-node-timeout :可以配置值为15000。节点互连超时的阀值,集群节点超时毫秒数
  • cluster-slave-validity-factor :可以配置值为10。

二. Redis构建Web应用实践

在这里插入图片描述

环境搭建

引入依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.5</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.3</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency>

编写配置文件

spring.application.name=spring-redis
server.port=8080
########################################################
### 配置连接池数据库访问配置
########################################################
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/redistest?characterEncoding=utf-8&&useSSL=false
spring.datasource.username=root
spring.datasource.password=jjy18535155985
spring.data.redis.host=192.168.66.100
spring.data.redis.port=6379

创建表

DROP TABLE IF EXISTS `user`;CREATE TABLE `user`
(id BIGINT NOT NULL COMMENT '主键ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',age INT NULL DEFAULT NULL COMMENT '年龄',email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (id)
);
DELETE FROM `user`;INSERT INTO `user` (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

编写实体类 User.java

@Data
@TableName("`user`")
public class User {private Long id;private String name;private Integer age;private String email;
}

编写 Mapper 包下的 UserMapper接口

public interface UserMapper extends BaseMapper<User> {}

编写业务层

@Service
public class UserService {@AutowiredUserMapper userMapper;public User getUser(Long id){return userMapper.selectById(id);}}

编写控制层

@RestController
public class UserController {@AutowiredUserService userService;/*** 根据id查询用户* @param id 用户id* @return*/@GetMapping("/getById")public User getUser(Long id){return userService.getUser(id);}}

redis_247">redis的优点

下载压测工具
登录官网Jmeter下载
https://jmeter.apache.org/

启动Jmeter工具
D:\apache-jmeter-5.4.3\bin\jmeter.bat文件双击运行。

修改语言
在这里插入图片描述

创建压测任务
在这里插入图片描述

添加HTTP请求
image-2021122716432061

配置HTT请求
在这里插入图片描述

添加压测结果报告
image-20211227164556998

没有加缓存的吞吐量
image-20211227164730666
添加redis缓存

  /**** 根据用户id查询用户* @param id* @return*/@Overridepublic User getById(Long id) {// 1、判断用户id等于1 有没有缓存  user:1User user = (User) template.opsForValue().get("user:" + id);if (user != null){return user;}// 2、如果没有缓存从数据库查User u = userMapper.selectById(id);// 3、加入缓存template.opsForValue().set("user:" + id,u);return u;}

继续压力测试
在这里插入图片描述

引入本地缓存

为什么引入本地缓存
本地缓存因为少了网络传输环节,所以读取速度比分布式缓存要快一些。

本地缓存的优点

  • 减少了网络调用的开销
  • 减少了数据请求的序列化和反序列化

Redis结合本地缓存

微服务场景下,多个微服务使用一个大缓存,流数据业务下,高频读取缓存对Redis压力很大,我们使用本地缓存结合Redis缓存使用,降低Redis压力,同时本地缓存没有连接开销,性能更优。

****image-20240130102506995****

本地方案选择

本地缓存为什么不使用hashMap或者concurrentHashMap?
原因:
HashMap、ConcurrentHashMap也能用作本地缓存,但是因为缺少必要的过期机制、容量限制、数据淘汰策略,不太合适。

Google 开源工具Guava

Maven引入依赖

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.2-jre</version>
</dependency>

字符串(Strings)
Strings是Guava提供的一组字符串工具,它提供了许多有用的方法来处理字符串。

Strings的主要方法
isNullOrEmpty(String string):判断字符串是否为空或null。
padEnd(String string, int minLength, char padChar):在字符串末尾填充指定字符,直到字符串达到指定长度。
padStart(String string, int minLength, char padChar):在字符串开头填充指定字符,直到字符串达到指定长度。
repeat(String string, int count):重复指定字符串指定次数。

Strings的使用示例:

public class StringsDemo {public static void main(String[] args) {// 判断字符串是否为空或nullString str1 = null;String str2 = "";System.out.println(Strings.isNullOrEmpty(str1));System.out.println(Strings.isNullOrEmpty(str2));// 在字符串末尾填充指定字符,直到字符串达到指定长度String str3 = "abc";String paddedStr1 = Strings.padEnd(str3, 6, '*');System.out.println(paddedStr1);// 在字符串开头填充指定字符,直到字符串达到指定长度String str4 = "abc";String paddedStr2 = Strings.padStart(str4, 6, '*');System.out.println(paddedStr2);// 重复指定字符串指定次数String str5 = "abc";String repeatedStr = Strings.repeat(str5, 3);System.out.println(repeatedStr);
}

集合操作(Collections)
Guava提供了一些非常有用的集合操作API。

ImmutableList
不可变集合是Guava的一个重要特性,它可以确保集合不被修改,从而避免并发访问的问题。ImmutabelList是不可变List的实现,下面是一个示例代码:

List<String> list = Lists.newArrayList("a", "b", "c");
ImmutableList<String> immutableList = ImmutableList.copyOf(list);
Iterables
Iterables类提供了一些有用的方法来操作集合,如下所示:Iterable<String> iterable = Lists.newArrayList("a", "b", "c");// 判断集合是否为空
boolean isEmpty = Iterables.isEmpty(iterable);// 获取第一个元素,如果集合为空返回null
String first = Iterables.getFirst(iterable, null);// 获取最后一个元素,如果集合为空返回null
String last = Iterables.getLast(iterable, null);// 获取所有符合条件的元素
Iterable<String> filtered = Iterables.filter(iterable, new Predicate<String>() {@Overridepublic boolean apply(String input) {return input.startsWith("a");}
});

Multimaps
Multimaps提供了一个非常有用的数据结构,它允许一个键对应多个值,下面是一个示例代码:

ListMultimap<Integer, String> map = ArrayListMultimap.create();
map.put(1, "a");
map.put(1, "b");
map.put(2, "c");
List<String> values = map.get(1); // 返回[a, b]

4.Maps
Maps提供了一些有用的方法来操作Map,如下所示:

Map<Integer, String> map = ImmutableMap.of(1, "a", 2, "b", 3, "c");// 判断Map是否为空
boolean isEmpty = Maps.isEmpty(map);// 获取Map中的所有键
Set<Integer> keys = map.keySet();// 获取Map中的所有值
Collection<String> values = map.values();// 获取Map中的所有键值对
Set<Map.Entry<Integer, String>> entries = map.entrySet();// 根据键获取值,如果不存在则返回null
String value = Maps.getIfPresent(map, 1);

条件检查(Preconditions)
Preconditions是Guava提供的一组前置条件检查工具,它提供了一些检查参数是否符合预期的方法。

Preconditions的主要方法:

checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs):检查参数是否符合预期,并抛出IllegalArgumentException异常,可以包含错误信息模板和占位符。
checkNotNull(T reference, String errorMessageTemplate, Object... errorMessageArgs):检查参数是否为null,并抛出NullPointerException异常,可以包含错误信息模板和占位符。
Preconditions的使用示例:

public class PreconditionsDemo {public static void main(String[] args) {// 检查参数是否符合预期,并抛出IllegalArgumentException异常,可以包含错误信息模板和占位符String str1 = "abc";Preconditions.checkArgument(str1.length() < 3, "字符串长度必须小于3");// 检查参数是否为null,并抛出NullPointerException异常,可以包含错误信息模板和占位符String str2 = null;Preconditions.checkNotNull(str2, "字符串不能为空");
}

Guava实现本地缓存

本地缓存(CacheBuilder)
Cache是Guava提供的一个缓存工具类,它可以帮助我们在内存中缓存数据,提高程序的性能。

Cache的主要方法:

  • get(K key, Callable<? extends V> valueLoader):获取指定key的缓存值,如果缓存中没有,则调用valueLoader加载数据并存入缓存。
  • getIfPresent(Object key):获取指定key的缓存值,如果缓存中没有,则返回null。
  • getAllPresent(Iterable<?> keys):获取指定keys的缓存值,如果缓存中没有,则返回null。
  • put(K key, V value):将指定key的缓存值存入缓存。
  • putAll(Map<? extends K, ? extends V> m):将指定Map的缓存值存入缓存。
  • invalidate(Object key):将指定key的缓存值从缓存中删除。
  • invalidateAll(Iterable<?> keys):将指定keys的缓存值从缓存中删除。
  • invalidateAll():将所有缓存值从缓存中删除。
  • size():获取缓存中缓存值的数量。
  • asMap():将缓存转换成Map。
package com.jjy.springdataredisdemo.service.impl;import com.google.common.cache.*;
import com.jjy.springdataredisdemo.entity.User;
import com.jjy.springdataredisdemo.mapper.UserMapper;
import com.jjy.springdataredisdemo.service.IUserService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RedisTemplate<String,Object> template;/*** 本地缓存*/private LoadingCache<String, User> localCache = CacheBuilder.newBuilder()//设置并发级别为16,并发级别是指可以同时写缓存的线程数.concurrencyLevel(16)//设置缓存容器的初始容量为1000.initialCapacity(1000)//设置缓存最大容量为10000,超过10000之后就会按照LRU最近虽少使用算法来移除缓存项.maximumSize(10000)//设缓存1小时没被使用就过期.expireAfterAccess(1, TimeUnit.HOURS)//设置要统计缓存的命中率.recordStats()//设置缓存的移除通知.removalListener(new RemovalListener<Object, Object>() {@Overridepublic void onRemoval(RemovalNotification<Object, Object> notification) {System.out.println(notification.getKey() + " 被移除了,原因: " + notification.getCause());}}).build(new CacheLoader<String, User>() {@Overridepublic User load(String key) throws Exception {// 1、判断用户id等于1 有没有缓存  user:1User user = (User) template.opsForValue().get("user:" + key);if (user != null){return user;}// 2、查询数据库User users = userMapper.selectById(key);// 4、加入redis分布式缓存template.opsForValue().set("user:" + key,users);return users;}});/**** 根据用户id查询用户* @param id* @return*/@SneakyThrows@Overridepublic User getById(Long id) {// 1、从本地缓存获取User o = localCache.get(id+"");return o;}

能够高效的读取的同时,提供了大量api方便我们控制本地缓存的数据量及冷数据淘汰;我们充分的学习这些特性能够帮助我们在业务开发中更加轻松灵活,在空间与时间上找到一个平衡点。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力
在这里插入图片描述


http://www.ppmy.cn/ops/29232.html

相关文章

【ARM Cache 系列文章 11 -- ARM Cache 直接映射 详细介绍】

请阅读【ARM Cache 系列文章专栏导读】 文章目录 ARM Cache组织形式直接映射(Direct Mapped)直接映射示例直接映射原理Cache颠簸(cache thrashing)原因文章:【ARM Cache 系列文章 11.1 – ARM Cache 全相连 详细介绍】 文章:【ARM Cache 系列文章 11.2 – ARM Cache 组相…

深入了解 Spring Boot 的加载过程

Spring Boot 的加载过程可以大致分为以下几个阶段&#xff1a; 类加载&#xff1a;首先&#xff0c;Java 虚拟机会加载必要的类&#xff0c;包括 Spring Boot 的核心类和应用程序的相关类。配置解析&#xff1a;Spring Boot 会解析各种配置&#xff0c;如 application.properti…

Linux系统编程--信号与管道

1、信号与管道是什么&#xff1f; 首先了解信号与管道的意义&#xff0c;我们需要了解Linux系统中进程之间是如何通信的。Linux操作系统下&#xff0c;以进程为单位来分配或者管理资源&#xff0c;进程之间不能直接访问资源&#xff0c;因此&#xff0c;要求进程间的资源和信息…

初识Vue-组件化开发(详解各个组件)

目录 一、组件介绍 1.概念 2.特点 3.作用 4.应用 5.分类 二、组件语法 1.定义挂载vue应用 2.注册全局组件 实例 1.自定义组件 2.计数器 3.组件的复用 4.局部组件 实例 5.Prop 6.动态Prop 7.Prop 验证 三、创建组件的关键概念和语法 1. 组件定义 2. 组件选…

在Vue中使用v-viewer插件实现点击图片预览

v-viewer是一款基于 viewer.js 封装的Vue版插件&#xff0c;可用于图像查看&#xff0c;以及图片的旋转、缩放等功能预览。 使用步骤&#xff1a; 第一步&#xff1a;安装插件 yarn add v-viewernext viewerjs 第二步&#xff1a;引入v-viewer及必需的css样式&#xff0c;并…

SpringBoot日志管理

一.Logback SpringBoot默认使用Logback组件作为日志管理。 Logback是log4j创始人设计的一个开源日志组件。在SpringBoot中已经整合了Logback的依赖&#xff0c;所以我们不需要额外的添加其他依赖,这些日志格式在我们开发过程中是不需要开发人员自己写的&#xff0c;直接cv拿过来…

全志ARM-修改开发板内核启动日志

修改开发板内核日志输出级别&#xff1a; 默认输出级别为1&#xff0c;需要用超级用户权限修改 sudo vi /boot/orangepiEvn.txt 把第一行内核启动输出权限改为7&#xff0c;第二行把输出方式该为“serial”串口输出

WPS文字页面横向

要将WPS文字页面设置为横向&#xff0c;可以按照以下步骤操作&#xff1a;12 打开WPS文字文档&#xff0c;点击“页面布局”选项卡。在“页面布局”中找到“纸张方向”选项。选择“横向”&#xff0c;这样整篇文档的页面方向就会变为横向。 如果只需要将文档中的特定页面设置…