缓存技术简介
1,客户端缓存
客户端缓存主要包含如客户使用的PC上的浏览器、手机App、微信小程序等。客户端缓存的原则就是尽量减少或消灭请求,以达到降低服务器压力和提升用户体验的效果。静态文件,例如Js、html、css、图片等内容,它们的很多可以只请求1次,然后缓存在本地,之后就优先从本地缓存中获取,这样就减少了对Web服务器的频繁请求。
如常见的浏览器缓存,可以通过Http的头信息控制缓存是通过Expires(强缓存)、Cache-control(强缓存)、Last-Modified/If-Modified-Since(协商缓存)、Etag/If-None-Match(协商缓存)实现。具体使用方法和区别,这里就不赘叙了哈。
客户端缓存的优缺点:
优点:减少网络传输,加快页面内容展示速度,提升用户体验。
成本:占用客户端的部分内存和磁盘,影响实时性。
2,文件缓及网络加速 除了前面说的前端缓存,针对一些静态资源,我们可以一次加载,实现本地缓存。那如果同时有一万、十万甚至更多的用户初次使用呢,这就使得大量的请求同时请求web服务器,势必给服务器带来很大的压力。基于这种情况,我们又如何来解决应对呢?这就是要说的新的内容--网络加速。目前流行的网络加速解决方案主要是CDN技术,那什么又是CDN呢,我这里做简单介绍。 CDN(Content Delivery Network)是指内容分发网络,也称为内容传送网络,为了能在传统IP网上发布丰富的宽带媒体内容,在现有互联网基础上建立一个内容分发平台专门为网站提供服务。CDN网络是在用户和服务器之间增加了一层缓存层,将用户的请求引导到最优的缓存节点而不是服务器源站,从而加块访问速度。CDN的一般使用场景:
加速静态资源; 网站中有大量的html、js、css、图片等文件,可以将这些静态内容推送到CDN。
大文件的下载;软件下载,视频点播等存储网站。
部分与用户无关的高频接口加速,在高并发情况下提升接口响应时间。
关于CDN的接入使用,使用云服务器的可以直接通过域名去云服务厂商去买就行,这里不在多说。
3,数据缓存
这是整个整个项目中最重要的,也就是我们所说的服务端缓存。服务端缓存有服务自身的Session,也有第三方的缓存技术。在分布式微服务的环境下,几乎没人使用Session作为服务端缓存,基本都采用了第三方的Nosql缓存技术。
常用的Nosql缓存有:Memcached、Redis、mongoDB。那么我们到底选用那个呢,先来看看他们的优缺点。
1)Memcached
优点:可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key、value的字节大小以及服务器硬件性能,日常环境中QPS高峰大约在4-6w左右)。适用于最大程度扛量。
缺点:只支持简单的key/value数据结构,不像Redis可以支持丰富的数据类型。无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失。无法进行数据同步,不能将MC中的数据迁移到其他MC实例中。
2)Redis 优点:支持多种数据结构,支持持久化操作,可以进行aof及rdb数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段。支持通过Replication进行数据复制,通过master-slave机制,可以实时进行数据同步复制,支持多级复制和增量复制,master-slave机制是Redis进行HA的重要手段。缺点:只能使用单线程,性能受限于CPU性能,故单实例CPU最高才可能达到5-6wQPS每秒。支持简单的事务需求,但业界使用场景很少,并不成熟,既是优点也是缺点。Redis在string类型上会消耗较多内存,可以使用dict(hash表)压缩存储以降低内存耗用。MC和Redis都是Key-Value类型,不适合在不同数据集之间建立关系,也不适合进行查询搜索。
3)mongoDB
mongoDB 是一种文档性的数据库。先解释一下文档的数据库,即可以存放xml、json、bson类型系那个的数据。这些数据具备自述性(self-describing),呈现分层的树状数据结构。
mongoDB 存放json格式的数据。适合场景如:事件记录、内容管理或者博客平台,比如评论系统。
mongodb与MC和Redis不同的是,它可以使用语句进行CRUD操作,处理和获取文档数据。操作语句如下:
查询:db.col.find().pretty();
添加:db.col.insert({name:'Lily',sex:'female',age:'18'});
删除:db.col.remove(...);
更新:db.col.update(...);
mongodb与mysql不同,mysql的每一次更新操作都会直接写入硬盘,但是mongo不会,做为内存型数据库,数据操作会先写入内存,然后再会持久化到硬盘中去。
服务端缓存选取接入
经过上面的介绍说明,考虑到服务端接口数据类型已经持久化等,Redis似乎是我们的首选,当然你也可以选择Memcached,这个完全取决与自己的项目。这里我介绍下Redis在Springboot+SpringCloud微服务项目的接入。
1,首先在pom.xml里引入Redis依赖 org.springframework.boot spring-boot-starter-data-redis ${springboot-redis.version}
2,配置Redis连接属性(application.yml)
spring: redis: # Redis库索引(默认为0) database: 0 # Redis服务器地址 host: 192.168.1.1 # Redis服务端口 port: 6379 # Redis连接密码(默认为空) password: lettuce: pool: # 连接池最大连接数(默认为8) max-active: 8 # 连接池最大空闲连接(默认为8) max-idle: 8 # 连接池最小空闲连接(默认为0) min-idle: 0 # 连接池最大阻塞等待时间 max-wait: -1ms
3,创建RedisConfig
@Configurationpublic class RedisConfig implements RedisSerializer { private Converter serializer = new SerializingConverter(); private Converter deserializer = new DeserializingConverter(); static final byte[] EMPTY_ARRAY = new byte[0]; @Autowired RedisConnectionFactory redisConnectionFactory; @Bean public RedisTemplate functionDomainRedisTemplate() { RedisTemplate redisTemplate = new RedisTemplate<>(); initDomainRedisTemplate(redisTemplate, redisConnectionFactory); return redisTemplate; } /** * 设置数据存入 redis 的序列化方式 * @param redisTemplate * @param factory */ private void initDomainRedisTemplate(RedisTemplate redisTemplate, RedisConnectionFactory factory) { redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.setConnectionFactory(factory); } @Bean public HashOperations hashOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForHash(); } @Bean public ValueOperations valueOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForValue(); } @Bean public ListOperations listOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForList(); } @Bean public SetOperations setOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForSet(); } @Bean public ZSetOperations zSetOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForZSet(); } @Override public Object deserialize(byte[] bytes) { if (bytes == null || bytes.length == 0) { return null; } try { return deserializer.convert(bytes); } catch (Exception ex) { throw new SerializationException("Cannot deserialize", ex); } } @Override public byte[] serialize(Object object) { if (object == null) { return EMPTY_ARRAY; } try { return serializer.convert(object); } catch (Exception ex) { return EMPTY_ARRAY; } }}
4,缓存操作接口及实现
public interface CacheService { boolean hasKey(String key); boolean delete(String key); Object get(String key); void set(String key, Object value); void set(String key, Object value, long timeout);}
@Componentpublic class CacheServiceImpl implements CacheService { @Autowired private ValueOperations valueOperation; @Autowired private RedisTemplate redisTemplate; @Override public boolean hasKey(String key) { return redisTemplate.hasKey(key); } @Override public boolean delete(String keys) { return redisTemplate.delete(keys); } @Override public void set(String key, Object value) { valueOperation.set(key, value); } @Override public Object get(String key) { return valueOperation.get(key); } @Override public void set(String key, Object value, long timeout) { valueOperation.set(key,value,timeout,TimeUnit.SECONDS); }}
5,编写测试实战
@RestController@RequestMapping(value = "/customer/")public class CustomerController { @Autowired private CustomerService customerService; @Autowired private CacheService cacheService; @GetMapping("/id") public Object findCustomerById(Integer customerId) { Object obj = null; if ((obj = cacheService.getCacheByKey(CustomerConstant.CUSTOMER_CACHE_PREFIX+customerId)) != null) { return ResultData.ok((CustomerInfo) obj); } else { // 从数据库获取 CustomerInfo customerInfo = customerService.findById(customerId); if(customerInfo != null) { cacheService.setCacheToRedis(CustomerConstant.CUSTOMER_CACHE_PREFIX+customerId,customerInfo,3600); } return ResultData.ok(customerInfo); } }}
今天就说到这里,下一篇继续说说缓存使用中的注意事项,以及面试时经常问到的缓存使用的相关问题。
推荐阅读: SpringCloud微服务项目实战 - 限流、熔断、降级处理 SpringCloud微服务项目实战 - API网关Gateway详解实现 SpringCloud微服务项目实战 - 网关zuul详解及搭建SpringCloud微服务项目实战 - 微服务调用详解(附面试题)
SpringCloud微服务项目实战,服务注册与发现(附面试题)
扫码关注公众号,发送关键词获取相关资料:
发“Springboot”领取电商项目实战源码;
发“SpringCloud”领取学习实战资料;