前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot实战之nosql整合(redis篇)

springboot实战之nosql整合(redis篇)

作者头像
lyb-geek
发布2019-10-10 11:14:46
8050
发布2019-10-10 11:14:46
举报
文章被收录于专栏:Linyb极客之路Linyb极客之路
前言

关于redis的内容,我之前已经分享过了很多了,今天这篇算是为了springboot nosql整合中的凑数篇吧,哈哈,虽然这么说,但如果点进来了,蛮看下,说不定会有一些新发现

什么是redis

Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份

redis的优点

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

redis常见性能问题和解决方案:

  • Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
  • 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
  • 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
  • 尽量避免在压力很大的主库上增加从库
  • 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3…这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做M

redis 常用应用场景

1.在主页中显示最新的项目列表。

Redis使用的是常驻内存的缓存,速度非常快。LPUSH用来插入一个内容ID,作为关键字存储在列表头部。LTRIM用来限制列表中的项目数最多为5000。如果用户需要的检索的数据量超越这个缓存容量,这时才需要把请求发送到数据库。

2.删除和过滤。

如果一篇文章被删除,可以使用LREM从缓存中彻底清除掉。

3.排行榜及相关问题。

排行榜(leader board)按照得分进行排序。ZADD命令可以直接实现这个功能,而ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。

4.按照用户投票和时间排序。

这就像Reddit的排行榜,得分会随着时间变化。LPUSH和LTRIM命令结合运用,把文章添加到一个列表中。一项后台任务用来获取列表,并重新计算列表的排序,ZADD命令用来按照新的顺序填充生成列表。列表可以实现非常快速的检索,即使是负载很重的站点。

5.过期项目处理。

使用unix时间作为关键字,用来保持列表能够按时间排序。对currenttime和timeto_live进行检索,完成查找过期项目的艰巨任务。另一项后台任务使用ZRANGE...WITHSCORES进行查询,删除过期的条目。

6.计数。

进行各种数据统计的用途是非常广泛的,比如想知道什么时候封锁一个IP地址。INCRBY命令让这些变得很容易,通过原子递增保持计数;GETSET用来重置计数器;过期属性用来确认一个关键字什么时候应该删除。

7.特定时间内的特定项目。

这是特定访问者的问题,可以通过给每次页面浏览使用SADD命令来解决。SADD不会将已经存在的成员添加到一个集合。

8.实时分析正在发生的情况,用于数据统计与防止垃圾邮件等。

使用Redis原语命令,更容易实施垃圾邮件过滤系统或其他实时跟踪系统。

9.Pub/Sub。

在更新中保持用户对数据的映射是系统中的一个普遍任务。Redis的pub/sub功能使用了SUBSCRIBE、UNSUBSCRIBE和PUBLISH命令,让这个变得更加容易。

10.队列。

在当前的编程中队列随处可见。除了push和pop类型的命令之外,Redis还有阻塞队列的命令,能够让一个程序在执行时被另一个程序添加到队列。你也可以做些更有趣的事情,比如一个旋转更新的RSS feed队列。

11.缓存。

Redis缓存使用的方式与memcache相同。

网络应用不能无休止地进行模型的战争,看看这些Redis的原语命令,尽管简单但功能强大,把它们加以组合,所能完成的就更无法想象。当然,你可以专门编写代码来完成所有这些操作,但Redis实现起来显然更为轻松。

12.分布式会话

集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。

13.分布式锁

springboot与redis整合

例子整合的内容,主要为如下:

a、分布式缓存

1、方案一:通过与spring cache集成,配合@Cacheable、@CachePut 和 @CacheEvict注解

  • pom.xml引入
代码语言:javascript
复制
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
  • application.yml 配置
代码语言:javascript
复制
spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 20
        max-idle: 20
        min-idle: 10
  cache:
    redis:
      cache-null-values: false
      time-to-live: 30m #redis缓存过期统一配置的时间,但实际情况,我们要按不同业务配置不同的过期时间,因此可以在RedisCacheManager中实现
  • CacheManager配置
代码语言:javascript
复制
@Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(om);

        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(timeToLive)
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
            .disableCachingNullValues();

//        // 设置一个初始化的缓存空间set集合
//        Set<String> cacheNames =  new HashSet<>();
//        cacheNames.add("book");

        // 对每个缓存空间应用不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        RedisCacheConfiguration bookCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofSeconds(180))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
            .disableCachingNullValues();
        configMap.put("book",bookCacheConfig);

        RedisCacheManager cacheManager = RedisCacheManager.builder(RedisCacheWriter.lockingRedisCacheWriter
            (redisConnectionFactory)).cacheDefaults(defaultConfig).withInitialCacheConfigurations(configMap)
            .transactionAware().build();



        return cacheManager;
    }
  • 启动类上加上@EnableCaching
  • 在需要进行缓存的方法上按需加上@Cacheable、@CachePut 或@CacheEvict注解,形如下
代码语言:javascript
复制
@Cacheable(cacheNames = "book",key="'add_'+#bookDTO.bookName")
  public BookDTO addBook(BookDTO bookDTO) {
    Book book = dozerMapper.map(bookDTO,Book.class);
    boolean isExitBookByName = ObjectUtils.isNotEmpty(getBookByName(bookDTO.getBookName()));
    if(isExitBookByName){
      throw new BizException("书名已经存在");
    }
    book.setCreateDate(new Date());
    book.setUpdateDate(new Date());
    baseMapper.insert(book);

    bookDTO = dozerMapper.map(book,BookDTO.class);

    return bookDTO;
  }

2、方案二:自定义缓存,通过AOP和自定义注解RedisCache搭配实现。

具体实现方法,可以查看如下链接

https://github.com/lyb-geek/springboot-learning/blob/master/springboot-redis/src/main/java/com/github/lybgeek/redis/aspect/RedisCacheAspect.java

b、分布式锁

1、方案一 通过org.springframework.integration.redis.util.RedisLockRegistry进行实现

  • pom.xml引入
代码语言:javascript
复制
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-integration</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-redis</artifactId>
    </dependency>
  • RedisLockRegistry配置
代码语言:javascript
复制
@Bean
  public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
    return new RedisLockRegistry(redisConnectionFactory, "bookLock");
  }
  • 在需要分布式锁的地方,写入形如下内容
代码语言:javascript
复制
Lock lock = redisLockRegistry.obtain("bookStock");
    if(lock.tryLock()) {
      try {
        log.info("updateStockById走db");
        num = bookMapper.updateStockById(id, count);
      } catch (Exception e) {
        log.error("updateStockById error:" + e.getMessage(), e);
      } finally {
        lock.unlock();
      }
    }

利用RedisLockRegistry来实现redis分布式锁的相关内容介绍,可以查看

  • spring 分布式锁-RedisLockRegistry和ZookeeperLockRegistry

https://blog.csdn.net/l18767118724/article/details/85261092

  • Spring Boot 2实现分布式锁——这才是实现分布式锁的正确姿势!

http://www.itmuch.com/spring-boot/global-lock/

2、方案二,通过lua脚本配合redis来实现分布式锁

由于篇幅原因,我就把相关实现的代码的链接贴在下方

https://github.com/lyb-geek/springboot-learning/blob/master/springboot-redis/src/main/java/com/github/lybgeek/redis/util/RedisLockUtils.java

总结

redis之前已经介绍很多,所以这篇可以算是一篇水文吧。在使用redis做缓存时,还要关注下Redis可能引起缓存穿透、缓存雪崩和缓存击穿的问题。其解决方案可以查看之前的文章 缓存三大问题及解决方案

参考文档

redis能干啥?细看11种Web应用场景

https://blog.csdn.net/u014386474/article/details/51838190

redis教程

https://www.runoob.com/redis/redis-intro.html

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-redis

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是redis
  • redis的优点
  • redis常见性能问题和解决方案:
  • redis 常用应用场景
  • springboot与redis整合
    • a、分布式缓存
      • b、分布式锁
      • 总结
      • 参考文档
      • demo链接
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档