当前位置: 首页 > news >正文

商务网站建设与维护流程重庆响应式网站建设公司

商务网站建设与维护流程,重庆响应式网站建设公司,营销型网站建设需要有什么功能,网站建设展滔科技大厦前提 要实现,使用Redis存储登录状态 需要一个完整的前端后端的项目 前端项目搭建 解压脚手架 安装依赖 配置请求代理 选做: 禁用EsLint语法检查 Vue Admin Template关闭eslint校验#xff0c;lintOnSave#xff1a;false设置无效解决办法_lintonsave: false-CSDN博客 …前提 要实现,使用Redis存储登录状态 需要一个完整的前端后端的项目 前端项目搭建 解压脚手架 安装依赖 配置请求代理 选做: 禁用EsLint语法检查 Vue Admin Template关闭eslint校验lintOnSavefalse设置无效解决办法_lintonsave: false-CSDN博客 后端项目搭建 创建springboot项目 从其他项目中拷贝需要的依赖 从其他项目拷贝所需的yml配置 创建所需的entity,Controller,service,mapper,util 写一个登录测试即可 七、与SpringBoot整合 7.1 RedisTemplate了解 spring-data-redis的jar中提供在srping应用中通过简单的配置访问redis服务的功能它对reids底层开发包进行了高度封装。 针对reids的操作包中提供了RedisTemplate类和StringRedisTemplate类其中StringRedisTemplate是RedisTemplate的子类该类只支持key和value为String的操作 RedisTemplate针对不同数据类型的操作进行封装将同一类型操作封装为Operation接口 ValueOperations简单K-V操作获取方式 redisTemplate.opsForValue(); SetOperationsset类型数据操作获取方式 redisTemplate.opsForSet(); ZSetOperationszset类型数据操作获取方式 redisTemplate.opsForZSet(); HashOperations针对hash类型的数据操作 获取方式 redisTemplate.opsForHash(); ListOperations针对list类型的数据操作获取方式 redisTemplate.opsForList(); 序列化策略 StringRedisTemplate默认采用的是String的序列化策略保存的key和value都是采用此策略序列化保存的。 RedisTemplate默认采用的是JDK的序列化策略保存的key和value都是采用此策略序列化保存的。 GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化 Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer实际上是一样的 JacksonJsonRedisSerializer: 序列化object对象为json字符串 JdkSerializationRedisSerializer: 序列化java对象被序列化的对象必须实现Serializable接口 StringRedisSerializer: 简单的字符串序列化 GenericToStringSerializer:类似StringRedisSerializer的字符串序列化 GenericJackson2JsonRedisSerializer:类似Jackson2JsonRedisSerializer但使用时构造函数不用特定的类 7.2 整合 7.2.1 依赖 !-- redis --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency ​!-- pool 对象池 --dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId/dependency 7.2.2 yml配置 spring:datasource:# 这里是之前mysql的....redis:# 地址host: 127.0.0.1# 端口默认为6379port: 6379# 数据库索引database: 0# 连接超时时间timeout: 10slettuce:pool:# 连接池中的最小空闲连接min-idle: 0# 连接池中的最大空闲连接max-idle: 8# 连接池的最大数据库连接数max-active: 8# #连接池最大阻塞等待时间使用负值表示没有限制max-wait: -1ms 7.2.3 redis配置类 SpringBoot自动在容器中创建了RedisTemplate对象和StringRedisTemplate对象。但是RedisTemplate的泛型是Object,Object进行数据处理时比价麻烦我们需要自定义一个RedisTemplate对象 ps: [了解]在SpringBoot 1.5.x版本默认的Redis客户端是Jedis实现的SpringBoot 2.x版本默认客户端是用lettuce实现的 package com.qf.config; ​ import org.springframework.beans.factory.annotation.Autowired; 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; import org.springframework.stereotype.Component; ​ /*** --- 天道酬勤 ---** author QiuShiju* desc* 针对redis的配置类* 主要目的设置RedisTemplate的序列化策略*/ Configuration public class RedisConfig { ​Autowiredprivate LettuceConnectionFactory lettuceConnectionFactory; ​// 容器中默认的对象名是方法名Beanpublic RedisTemplateString, Object redisTemplate() {RedisTemplateString, Object redisTemplate new RedisTemplate();StringRedisSerializer stringRedisSerializer new StringRedisSerializer();GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer new GenericJackson2JsonRedisSerializer(); ​//key采用String的序列化方式redisTemplate.setKeySerializer(stringRedisSerializer);// value序列化方式采用jacksonredisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的key也采用String的序列化方式redisTemplate.setHashKeySerializer(stringRedisSerializer);// hash的value序列化方式采用jacksonredisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setConnectionFactory(lettuceConnectionFactory);return redisTemplate;} } 7.3 测试 记得测试依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactId/dependency 测试代码 package com.qf.test; ​ import com.qf.entity.StudentTb; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.*; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; ​ /*** 所有springboot 相关单元测试类 都必须在启动类所在包及其子包下*/ SpringBootTest // 作用就是标记当前类 一个springboot测试 可以启动springboot应用 并从容器中获取 容器中的bean public class RedisTest { ​/*** 从容器中获取 redisTemplate*   redisTemplate 使用了模板设计模式作用提供了统一的api 操作*/Autowiredprivate RedisTemplate redisTemplate ; ​/*** Test 表示当前方法是一个测试方法* 测试方法要求 1.必须是public void*               2.无参* 测试value 为String 类型*/Testpublic void stringTest(){ ​// valueOperations 就是一个专门用于操作 值为String 类型的redis工具// 相当于 redis 命令的 set   getValueOperations valueOperations redisTemplate.opsForValue();// set a1 1000valueOperations.set(a1,1000h);valueOperations.set(a2,哈哈哈);// get a1Object result valueOperations.get(a1);Object result2 valueOperations.get(a2);System.out.println(result result);System.out.println(result2 result2);} ​/*** 操作list 数据** Data* public class StudentTb {**     private int id;*     private String name;*     private int age;* }*/Testpublic void listTest(){ ​StudentTb studentTb1 new StudentTb();studentTb1.setId(1000);studentTb1.setName(xiaoming);studentTb1.setAge(18); ​StudentTb studentTb2 new StudentTb();studentTb2.setId(1001);studentTb2.setName(lisi);studentTb2.setAge(28); ​// listOperations 专门用于操作redis中 的List 数据结构ListOperations listOperations redisTemplate.opsForList(); ​// 在redis key studentList 中添加数据 studentTb1对象listOperations.leftPush(studentList,studentTb1);listOperations.leftPush(studentList,studentTb2); ​// 从list 集合中读取数据 studentListListStudentTb studentList listOperations.range(studentList, 0, -1);System.out.println(studentList studentList); ​} ​/*** 操作 hash类型的数据*   存储对象*/Testpublic void hashTest(){// hashOperations 操作数据类型为 hash的数据HashOperations hashOperations redisTemplate.opsForHash(); ​hashOperations.put(stu1,id,1000);hashOperations.put(stu1,name,xiaoming);hashOperations.put(stu1,age,18); ​// 读取hash 类型中的数据String name (String) hashOperations.get(stu1, name);System.out.println(name name); ​} ​/*** 测试 Set 类型数据*/Testpublic void setTest(){ ​StudentTb studentTb1 new StudentTb();studentTb1.setId(1000);studentTb1.setName(xiaoming);studentTb1.setAge(18); ​StudentTb studentTb2 new StudentTb();studentTb2.setId(1001);studentTb2.setName(lisi);studentTb2.setAge(28); ​// setOperations 用于操作set 类型数据SetOperations setOperations redisTemplate.opsForSet();setOperations.add(studentSet1,studentTb1,studentTb2); ​// 读取到studentSet1 对应的内容SetStudentTb studentSet1 setOperations.members(studentSet1); ​System.out.println(studentSet1 studentSet1);} ​/*** 测试 zset 数据类型*/Testpublic void  zSetTest(){StudentTb studentTb1 new StudentTb();studentTb1.setId(1000);studentTb1.setName(xiaoming);studentTb1.setAge(18); ​StudentTb studentTb2 new StudentTb();studentTb2.setId(1001);studentTb2.setName(lisi);studentTb2.setAge(28); ​// zSetOperations 专门用于操作zsetZSetOperations zSetOperations redisTemplate.opsForZSet();zSetOperations.add(zset1,studentTb1,88);zSetOperations.add(zset1,studentTb2,78); ​// 从zset中读取数据SetStudentTb zset1 zSetOperations.range(zset1, 0, -1);System.out.println(zset1 zset1);} ​/*** 操作key 相关命令*/Testpublic void  keyTest(){ ​// 删除对应的keyBoolean result redisTemplate.delete(a2);System.out.println(result result); ​// 设置a1 最多存活 10sredisTemplate.expire(a1,10, TimeUnit.MICROSECONDS);} } 7.4 工具类 一般在开发的时候,不会直接使用RedisTemplate操作Redis 都会再封装一个工具类RedisUtil,类似下面这种(CV Ruoyi项目的) package com.qf.util; ​ import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; ​ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; ​ ​ /*** --- 天道酬勤 ---** author QiuShiju* desc Redis工具类*/ Component public class RedisUtil { ​Autowiredpublic RedisTemplate redisTemplate; ​/*** 缓存基本的对象Integer、String、实体类等** param key   缓存的键值* param value 缓存的值*/public T void setCacheObject(final String key, final T value) {redisTemplate.opsForValue( ).set(key, value);} ​/*** 缓存基本的对象Integer、String、实体类等** param key     缓存的键值* param value   缓存的值* param timeout 时间* param timeUnit 时间颗粒度*/public T void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {redisTemplate.opsForValue( ).set(key, value, timeout, timeUnit);} ​/*** 设置有效时间** param key     Redis键* param timeout 超时时间* return true设置成功false设置失败*/public boolean expire(final String key, final long timeout) {return expire(key, timeout, TimeUnit.SECONDS);} ​/*** 设置有效时间** param key     Redis键* param timeout 超时时间* param unit   时间单位* return true设置成功false设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit) {return redisTemplate.expire(key, timeout, unit);} ​/*** 获得缓存的基本对象。** param key 缓存键值* return 缓存键值对应的数据*/public T T getCacheObject(final String key) {ValueOperationsString, T operation redisTemplate.opsForValue( );return operation.get(key);} ​/*** 删除单个对象** param key*/public boolean deleteObject(final String key) {return redisTemplate.delete(key);} ​/*** 删除集合对象** param collection 多个对象* return*/public long deleteObject(final Collection collection) {return redisTemplate.delete(collection);} ​/*** 缓存List数据** param key     缓存的键值* param dataList 待缓存的List数据* return 缓存的对象*/public T long setCacheList(final String key, final ListT dataList) {Long count redisTemplate.opsForList( ).rightPushAll(key, dataList);return count null ? 0 : count;} ​/*** 获得缓存的list对象** param key 缓存的键值* return 缓存键值对应的数据*/public T ListT getCacheList(final String key) {return redisTemplate.opsForList( ).range(key, 0, -1);} ​/*** 缓存Set** param key     缓存键值* param dataSet 缓存的数据* return 缓存数据的对象*/public T BoundSetOperationsString, T setCacheSet(final String key, final SetT dataSet) {BoundSetOperationsString, T setOperation redisTemplate.boundSetOps(key);IteratorT it dataSet.iterator( );while (it.hasNext( )) {setOperation.add(it.next( ));}return setOperation;} ​/*** 获得缓存的set** param key* return*/public T SetT getCacheSet(final String key) {return redisTemplate.opsForSet( ).members(key);} ​/*** 缓存Map** param key* param dataMap*/public T void setCacheMap(final String key, final MapString, T dataMap) {if (dataMap ! null) {redisTemplate.opsForHash( ).putAll(key, dataMap);}} ​/*** 获得缓存的Map** param key* return*/public T MapString, T getCacheMap(final String key) {return redisTemplate.opsForHash( ).entries(key);} ​/*** 往Hash中存入数据** param key   Redis键* param hKey Hash键* param value 值*/public T void setCacheMapValue(final String key, final String hKey, final T value) {redisTemplate.opsForHash( ).put(key, hKey, value);} ​/*** 获取Hash中的数据** param key Redis键* param hKey Hash键* return Hash中的对象*/public T T getCacheMapValue(final String key, final String hKey) {HashOperationsString, String, T opsForHash redisTemplate.opsForHash( );return opsForHash.get(key, hKey);} ​/*** 删除Hash中的数据** param key* param hKey*/public void delCacheMapValue(final String key, final String hKey) {HashOperations hashOperations redisTemplate.opsForHash( );hashOperations.delete(key, hKey);} ​/*** 获取多个Hash中的数据** param key   Redis键* param hKeys Hash键集合* return Hash对象集合*/public T ListT getMultiCacheMapValue(final String key, final CollectionObject hKeys) {return redisTemplate.opsForHash( ).multiGet(key, hKeys);} ​/*** 获得缓存的基本对象列表** param pattern 字符串前缀* return 对象列表*/public CollectionString keys(final String pattern) {return redisTemplate.keys(pattern);} } 演示使用即可: // 这里只是演示了取值动作.. SpringBootTest public class RedisTest { ​Autowiredprivate RedisUtil redisUtil ; ​Testpublic void stringTestByUtil(){Object a1 redisUtil.getCacheObject(a1);System.out.println(a1 a1); ​MapString, Object stu1 redisUtil.getCacheMap(stu1);System.out.println(stu1 stu1); ​ListObject studentList redisUtil.getCacheList(studentList);System.out.println(studentList studentList); ​SetObject studentSet1 redisUtil.getCacheSet(studentSet1);System.out.println(studentSet1 studentSet1); ​} } 八、Redis应用 8.1 存储登录状态 8.1.1 分析 需求: 实现用户没有登录时不可访问以及每1小时登录一次 思路: 用户登录成功后,将用户信息存储到Redis中 生成一个token当做key,用户信息当做value,并设置过期时间1小时 并将这个token返回给前端 前端登录成功后,从返回数据中取出token,存储到Vuex和Cookie中(Vue-admin-template架子是这么做的) 后续前端每次发请求时,都会在请求头中携带这个token到后端 后端设置拦截器,对接收的每个请求判断有无token 无token说明没有登录,响应回前端让其重新登录 有token,但是通过token从Redis中取不出数据,说明过期了,响应回前端让其重新登录 至此: 思考一下,如何响应给前端让其重新登录? 前端后端要统一使用JSON交互(即统一返回对象R)的,拦截器中如何返回R? 方案: 使用自定义异常类全局异常处理 思路: 拦截器中返回指定异常类,然后全局异常处理类中捕获这些异常,统一返回指定的状态码即可 状态码多少? Vue-admin-template架子中设置了50008,50012,50014状态码 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; 有token,通过token从Redis中取出数据,则放行 总结: 整体思路就是: 登录时生成令牌,给到前端,前端每次携带令牌,后端对请求拦截实现鉴权 8.1.2 设置自定义异常类 设置一个没有登录异常类即可 package com.qf.ex; ​ /*** --- 天道酬勤 ---** author QiuShiju* desc 未登录异常*/ public class NoLoginException extends RuntimeException{ ​// 为了接收状态码private int code; ​public int getCode() {return code;} ​public void setCode(int code) {this.code code;} ​public NoLoginException(int code,String message){super(message);this.code code;} } 8.1.3 设置全局异常处理 package com.qf.util;import com.qf.ex.NoLoginException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;/*** --- 天道酬勤 ---** author QiuShiju* desc 自定义全局异常处理类*/ RestControllerAdvice public class GlobalHandleException {ExceptionHandler(NoLoginException.class)public R handlerException(Exception ex){System.out.println(出错啦! ex.getMessage());NoLoginException noLoginException (NoLoginException) ex;// 返回状态码和错误信息return R.fail(noLoginException.getCode(),noLoginException.getMessage());} }8.1.4 登录时存储token Autowiredprivate RedisUtil redisUtil;PostMapping(/login)public R login(RequestBody SysUser sysUser) {SysUser user service.login(sysUser);if (user ! null) {// 1 登录成功,生成令牌String token UUID.randomUUID( ).toString( ).replace(-, );// 2 已令牌为key,对象信息为value存储到redis// key形如: user:34j34h53j4hj36// key形如: user:56j747b65756lk// value是对象,已经配置value使用jackson2Json将对象转成JSON字符串redisUtil.setCacheObject(user:token,user,1, TimeUnit.MINUTES);HashMapString, String map new HashMap( );// 3 将令牌返回前端map.put(token, token);return R.ok(map);}return R.fail( );}8.1.5 设置拦截器 Component public class AuthorizationInterceptor implements HandlerInterceptor {Autowiredprivate RedisUtil redisUtil;// 登录成功后将token发送给前端// 前端发送请求时需要将token放到请求头中发送给后台// 本例从Authorization这个请求头中获取token值// 注意,需要将前端的请求头改变为AuthorizationOverridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token request.getHeader(Authorization);if (token null || .equals(token)) {throw new NoLoginException(50008,无效令牌,重新登录);}SysUser sysUser redisUtil.getCacheObject(user: token);if (sysUser null) {throw new NoLoginException(50014,身份信息失效,重新登录);}return true;} }别忘了配置拦截器 package com.qf.config;import com.qf.interceptor.LoginInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; 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; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** --- 天道酬勤 ---** author QiuShiju* desc*/ Configuration // 这个注解,让springboot框架知道,以下的这个类是提供配置 public class MyWebMvcInterceptorConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**).excludePathPatterns(/sys/user/login);// 登录放行} }8.1.6 退出时销毁 /*** 退出登录*/ PostMapping(/logout) public R logout(HttpServletRequest request) {request.getSession().invalidate();String token request.getHeader(Authorization);// 销毁redis中的tokenredisUtil.deleteObject(user:token);return R.ok( ); }// 或者如下也行,不过得改前端 GetMapping(/logout) public R logout(String token) {redisUtil.deleteObject(user:token);return R.ok( ); }8.1.7 请求测试 需要将请求头中的key修改为Authorization 使用接口工具和网页测试即可 8.2 存储手机验证码 略。。。 前端设置输入框,按钮绑定事件,点击发请求到后端 后端接收请求后,调用工具类(短信工具类),生成验证码,存Redis一份(设置过期时间5分钟),短信发一份 收到短信后,输入验证码 发请求,输入的验证码要和后端Redis中的验证码比较 输入的验证码与Redis中的验证码不一致,验证码错了 输入的验证码,Redis中没有验证码,说明过期了 如果正常,返回 8.3 如何保证数据在数据库和redis缓存的一致性 方案1先删除缓存再处理数据库 [不推荐] 1 a用户 执行删除数据操作先删除缓存还没有执行删除数据库时 2 b用户 执行查询操作发现缓存中没有数据查询数据库中老的数据将数据放入缓存 3 a用户 执行删除数据库的操作这时缓存和数据库数据不一致了 而且只要缓存没有过期只要没有其他的修改数据库的操作缓存和数据库会长时间不一致 方案2先操作数据库再删除缓存 [推荐] 1 a用户删除数据库还没有删除缓存前 2 b用户查询数据从缓存中获取老的数据这时候缓存和数据库不一致 3 a用户删除缓存 4 c用户请求数据发现缓存中数据不存在查询数据库新数据将数据写入缓存这时缓存中是最新数据 实现缓存和数据库的数据短时间不一致只有b出现一次不一致的情况影响小 其他方案延迟双删等 a先删除缓存操作数据库间隔一定的时间a再删除一次缓存 九、Redis缓存的面试问题 【Redis】什么是Redis缓存 雪崩、穿透、击穿一篇文章就够了_redis 雪崩-CSDN博客 缓存穿透: 查询一个根本就不存在的数据 缓存击穿: 查询一个之前存在,但是现在过期了的数据 缓存雪崩: Redis中大量时间过期销毁 缓存倾斜 缓存穿透问题 缓存穿透 问题查询一个不存在的数据由于缓存中没有该数据导致每次请求都会去数据库查询数据库压力增大。 解决方案 布隆过滤器在缓存之前先通过布隆过滤器判断数据是否存在如果不存在则直接返回避免访问数据库。 什么是布隆过滤器如何使用-腾讯云开发者社区-腾讯云 (tencent.com) 利用布隆过滤器我们可以预先把数据查询的主键比如用户 ID 或文章 ID 缓存到过滤器中。当根据 ID 进行数据查询的时候我们先判断该 ID 是否存在若存在的话则进行下一步处理。若不存在的话直接返回这样就不会触发后续的数据库查询。需要注意的是缓存穿透不能完全解决我们只能将其控制在一个可以容忍的范围内。缓存空值或默认值对于不存在的数据也在缓存中保存一个空值或默认值并设置较短的过期时间减少数据库查询压力。 引入风控系统对于频繁查询不存在的数据的请求进行限制或封禁。 缓存击穿问题 缓存击穿 本来缓存中有对应的数据但是缓存的数据 因为到期需要去数据库中再次查询数据 问题当某个热点数据在缓存中过期或者不存在时大量请求会直接访问数据库导致数据库压力骤增。 解决方案 使用互斥锁如分布式锁来控制只有一个请求去数据库加载数据其他请求等待。 逻辑过期不直接设置过期时间而是用程序逻辑判断数据是否“过期”减少因过期导致缓存击穿的情况。 预先加载对于热点数据在其过期前主动进行加载避免过期时刻的并发访问。 缓存雪崩问题 缓存雪崩问题:当缓存中大量的key 同时失效此时大量的请求就会 穿过缓存层到达数据库此时就会对数据库造成很大压力数据库压力过大也会崩溃 此时就是缓存雪崩由于缓存的失效 造成一系列的崩溃 缓存雪崩 问题当大量缓存数据同时过期或被删除时大量请求会直接访问数据库导致数据库压力骤增。 解决方案 添加随机过期时间在设置缓存过期时间时添加一定的随机时间避免大量数据同时过期。 使用分布式锁在查询数据库时使用分布式锁来避免并发查询导致的数据库压力增大。 延迟双删策略在更新数据时先删除缓存中的数据然后更新数据库。在更新数据库成功后再次删除缓存中的数据确保数据一致性。 监控和告警对Redis缓存系统进行监控和告警及时发现和解决数据一致性问题。 缓存雪崩 缓存倾斜问题 缓存倾斜 问题某个热点数据被大量请求访问导致该数据所在的Redis节点压力过大甚至可能引发宕机。 解决方案 热点数据分散将热点数据分散到多个Redis节点中避免单一节点压力过大。 使用多级缓存除了Redis缓存外还可以引入其他缓存层如本地缓存、CDN等将热点数据缓存到离用户更近的地方减少Redis的访问压力。 热点数据预处理对于热点数据可以提前进行预处理和计算减少实时计算的压力。 监控和告警对热点数据的访问进行监控和告警及时发现并解决潜在问题。
http://www.yayakq.cn/news/5255/

相关文章:

  • 怎么查看网站是否备案基于php技术的个人网站设计
  • 网站建设规划大纲常州制作网站公司
  • 北京手机app开发湖南有实力seo优化哪家好
  • 知名商城网站建设公司个人网站可以做论坛么
  • php网站开发教程网网站开发手机验证码
  • 自媒体还是做网站wordpress首页等待画面
  • 有人拉我做彩票网站阿里云网站建设方案书模板
  • 端州网站建设公司公寓注册公司需要什么条件
  • 咸宁网站建设价格成都网站建设公司官网
  • 网站编程 mysql百度收录排名好的网站
  • 做网站PAAS系统网站主机方案
  • 网站开发大体流程图云校网站建设
  • 个人作品网站链接怎么做wordpress 主题课堂
  • 公司微网站建设价格岳麓区营销型网站建设定制
  • 网站建设需要什么硬件制作网站报价单
  • 手机网站使用微信支付苏州吴江城乡和住房建设局网站
  • php 怎么做 网站吗网页制作三合一案例教程
  • 如何做网站公证怎样查网站备案
  • python不用框架做网站做加油机公司网站
  • 商城网站建设专业公司如何从零开始学室内设计
  • 给女生做网站新网站建设运营年计划书
  • 哪个网站可以做司考题网站开发专业介绍
  • 营销型网站三要素国际公司英语翻译
  • 京美建站官网浙江建设
  • 淄博网站优化服务石家庄58同城
  • 主域名进入网站wordpress 画廊 插件
  • 商业型网站长兴县建设局网站
  • 上海市城乡建设管理局网站郑州专业网站设计公司
  • 做网站win7好用么江津集团网站建设
  • 网站建设结课总结网页微博登录