因收到Google相关通知,网站将会择期关闭。相关通知内容
10 如何高效读取计费规则等热数据——分布式缓存
前几章节主要聚集于会员与积分模块的业务功能,引领大家尝试了服务维护、配置中心、断路器、服务调用等常见的功能点,本章节开始进入核心业务模块——停车计费,有两块数据曝光率特别高:进场前的可用车位数和计费规则,几乎每辆车都进出场都用到,这部分俗称为热数据:经常会用到。读关系库很明显不是最优解,引入缓存才是王道。
分布式缓存
这里仅讨论软件服务端的缓存,不涉及硬件部分。缓存作为互联网分布式开发两大杀器之一(另一个是消息队列),应用场景相当广泛,遇到高并发、高性能的案例,几乎都能看到缓存的身影。
从应用与缓存的结合角度来区分可以分为本地缓存和分布式缓存。
我们经常用 Tomcat 作为应用服务,用户的 session 会话存储,其实就是缓存,只不过是本地缓存,如果需要实现跨 Tomcat 的会话应用,还需要其它组件的配合。Java 中我们应经用到的 HashMap 或者 ConcurrentHashMap 两个对象存储,也是本地缓存的一种形式。Ehcache 和 Google Guava Cache 这两个组件也都能实现本地缓存。单体应用中应用的比较多,优势很明显,访问速度极快;劣势也很明显,不能跨实例,容量有限制。
分布式场景下,本地缓存的劣势表现的更为突出,与之对应的分布式缓存则更能胜任这个角色。软件应用与缓存分离,多个应用间可以共享缓存,容量扩充相对简便。有两个开源分布式缓存产品:memcached 和 Redis。简单介绍下这两个产品。
memcached 出现比较早的缓存产品,只支持基础的 key-value 键值存储,数据结构类型比较单一,不提供持久化功能,发生故障重启后无法恢复,它本身没有成功的分布式解决方案,需要借助于其它组件来完成。Redis 的出现,直接碾压 memcached ,市场占有率节节攀升。
Redis 在高效提供缓存的同时,也支持持久化,在故障恢复时数据得已保留恢复。支持的数据类型更为丰富,如 string , list , set , sorted set , hash 等,Redis 自身提供集群方案,也可以通过第三方组件实现,比如 Twemproxy 或者 Codis 等等,在实际的产品应用中占有很大的比重。另外 Redis 的客户端资源相当丰富,支持近 50 种开发语言。
本案例中的热数据采用 Redis 来进行存储,在更复杂的业务功能时,可以采用本地缓存与分布式缓存进行混合使用。
Redis 应用
Redis 安装配置
官网地址:https://redis.io/,当前最新版已到 5.0.7,Redis 提供了丰富了数据类型、功能特性,基本能够覆盖日常开发运维使用,简单的命令行使学习曲线极低,可以快速上手实践。提供了丰富语言客户端,供使用者快速的集成到项目中。
(图片来源于 redis 官网,https://redis.io/clients)
下面来介绍如何安装 redis:
下载编译过的二进制安装包,本案例中使用的版本是 4.0.11。
$ wget http://download.redis.io/releases/redis-4.0.11.tar.gz
$ tar xzf redis-4.0.11.tar.gz
$ cd redis-4.0.11
$ make
配置,默认情况下 redis 的的配置安全性较弱,无密码配置的,端口易扫描。若要修改默认配置,可修改 redis.conf 文件。
可以修改默认端口 6379
port 16479
redis 默认情况下不是以后台程序的形式运行,需要将开关打开
daemonize yes
打开需要密码开发,设置密码
requirepass zxcvbnm,./
启动 redis
启动时,加载配置文件
appledeMacBook-Air:redis-4.0.11 apple$ src/redis-server redis.conf 59464:C 07 Mar 10:38:15.284 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 59464:C 07 Mar 10:38:15.285 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=59464, just started 59464:C 07 Mar 10:38:15.285 # Configuration loaded
命令行测试
appledeMacBook-Air:redis-4.0.11 apple$ src/redis-cli -p 16479
必须执行 auth 命令,输入密码,否则无法正常使用命令
127.0.0.1:16479> auth zxcvbnm,./ OK 127.0.0.1:16479> dbsize (integer) 51 127.0.0.1:16479>
至此,redis 服务安装完成,下面就可以将缓存功能集成到项目中去。有小伙伴可能会说通过命令方式操作 redis 远不如图形化管理界面直观,活跃的同学们早已提供对应的工具供大家使用,比如 Redis Manager 等。
集成 Spring Data Redis
此次实践采用 Spring Data 项目家族中的 Spring Data Redis 组件与 Redis Server 进行交互通信,与 Spring Boot 项目集成时,采用 starter 的方式进行。
Spring Boot Data Redis 依赖于 Jedis 或 lettuce 客户端,基于 Spring Boot 提供一套与客户端无关的 API ,可以轻松将一个 redis 切换到另一个客户端,而不需要修改业务代码。
计费业务对应的项目模块是 parking-charging,在 pom.xml 文件中引入对应的 jar,这里为什么没有 version 呢,其实已经在 spring-boot-dependencies 配置中约定,此处无须再特殊配置。
org.springframework.boot
spring-boot-starter-data-redis
可以通过编写 Java 代码,进行 [@Configuration] 注解配置,也可以使用配置文件进行。这里使用配置文件的方式。在 application.properties 中配置 redis 连接,这里特殊指定了 database ,Redis 默认有 16 个数据库,从 0 到 15 ,可以提供有效的数据隔离,防止相互污染。
#redis config
spring.redis.database=1
spring.redis.host=localhost
spring.redis.port=16479
#default redis password is empty
spring.redis.password=zxcvbnm,./
spring.redis.timeout=60000
spring.redis.pool.max-active=1000
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=10
spring.redis.pool.min-idle=5
基于 Spring Boot 的约定优于配置的原则,按如下方式配置后,redis 已经可以正常的集成在项目中。
编写服务类 RedisServiceImpl.java ,基于 Spring Boot Data Redis 项目中封装的 RedisTemplate 就可以与 redis 进行通信交互,本示例仅以简单的基于 string 数据格式的 key-value 方式进行。
@Slf4j
@Service
public class RedisServiceImpl implements RedisService {
@Autowired
RedisTemplate