Java必知必会系列:缓存技术与Memcached

发布于:2023-10-25 ⋅ 阅读:(96) ⋅ 点赞:(0)

作者:禅与计算机程序设计艺术

1.背景介绍

概述

Java作为目前主流的高级编程语言,在开发中不可避免地涉及到对大量数据的缓存和提升性能。而最流行的缓存方案则是Memcached。Memcached是一种分布式缓存系统,用来减少数据库负载并加速应用程序的速度。它支持多种缓存策略、数据过期设置等功能,能够处理庞大的数据集,并且可用于许多不同的编程环境。由于其开源特性,Memcached也被广泛应用于各种互联网服务和后台系统。本文将通过对Memcached的介绍、相关技术基础知识的回顾以及实际案例分析,带领读者了解缓存技术、Memcached缓存解决方案,以及如何应用该解决方案提升应用性能。

Memcached简介

Memcached是一个高性能的分布式内存对象缓存系统,用于动态WEB应用中减轻数据库负载。其主要功能包括:

  • 存储小块数据(如键值对)到内存中,可以达到高速访问;
  • 支持缓存失效机制,保证缓存命中率;
  • 支持分布式集群,有效解决单点故障问题;
  • 提供简单的接口,客户端方便调用; Memcached是一个基于内存的高速缓存技术,最初由David McCandless设计实现,并于2003年开源。它使用简单的协议来存储、查找数据,memcached服务器只需要知道数据的key,然后通过hash取模的方式计算出存放到哪个节点上。这样可以在一定程度上避免缓存雪崩的问题。在缓存集群中的多个节点之间也可以进行负载均衡。

为什么要用Memcached?

随着互联网web业务的发展,网站访问量呈爆发式增长。为了应对这种信息推送的快速性,网站需要不断优化网站的访问速度,提高用户体验。而网站的动态资源,如图片、视频、Flash动画等静态资源通常都比较大,所以无法直接放在浏览器端缓存起来,因此需要利用缓存技术来减少数据库的请求压力。

Memcached是目前最流行的开源分布式缓存系统,它的优势主要有以下几点:

  • 高性能:Memcached采用了内存缓存方式,内存的访问速度非常快,能支持大量的并发连接;
  • 可扩展性:Memcached支持分布式缓存,可以很好地扩展缓存服务器,缓解单点瓶颈;
  • 持久化存储:Memcached可以配置到本地文件或远程服务器,提供持久化存储,适合缓存敏感的业务;
  • 自动过期机制:Memcached提供了自动过期机制,能够更及时地清除无效的缓存数据,有效节约内存空间;
  • 数据完整性:Memcached采用非阻塞I/O,确保数据安全性;

综上所述,Memcached是一个非常好的缓存技术,应用场景很多,比如缓存页面、图片、视频等静态资源,降低数据库查询压力,提升网站响应速度,有效防止DDOS攻击等。本文将以此引导读者了解Memcached的相关知识和实际应用。

2.核心概念与联系

Memcached的概念简单易懂,就是一个内存中缓存的存储结构。主要有三种数据类型:

  • Value(值):Memcached里的每个数据项都是由一个key和一个value组成。value存储着用户所需的数据,可以是任意形式的,比如数字、字符串、二进制数据等;
  • Flags(标记):Memcached里的每条记录除了value外还有一个标识符flags。它是一个数字,用来表示数据的状态和生命周期,比如0代表永不过期,1代表临时数据,2代表永久数据等;
  • Expiration Time(过期时间):Memcached中的数据项还有自己的过期时间属性,它用来指定数据项何时从缓存中删除。默认情况下,Memcached不会自动删除数据项,只有当过期时间到了才会被自动删除。

通过这三个概念,Memcached就可以做如下几个核心工作:

  • 缓存数据:Memcached采用的是先进先出算法,当内存容量不足时,系统会自动踢出旧的数据。缓存的数据需要制定过期时间,过期时间到了后就会自动清掉,使得缓存中的数据总是最新的;
  • 分布式缓存:Memcached支持分布式部署,允许多个节点共同存储相同的数据,实现缓存共享和冗余;
  • 数据一致性:Memcached支持自动同步,保证不同节点上的缓存数据一致性;
  • 原子性操作:Memcached的所有操作都是原子性的,可以保证缓存数据的完整性;

图:Memcached相关核心概念示意图

3.核心算法原理和具体操作步骤以及数学模型公式详细讲解

缓存置换算法

首先,Memcached要解决的问题是缓存的置换算法。

缓存的置换算法决定了当内存中已缓存数据项的数量超过限额时,如何选择删除的数据项。常用的算法有两种:

  • FIFO(First In First Out)算法:先进先出,也就是最早进入缓存的数据项,最先被删除;
  • LRU(Least Recently Used)算法:最近最少使用,也就是最长时间内没有被访问或使用的数据项,将其删除;

其中LRU算法虽然会导致缓存命中率下降,但是它对时间的敏感度低,即如果某些数据项长时间不被访问,但其被频繁访问,依然会一直存在在缓存中,而导致缓存的占用率过高;因此,一般LRU算法仅用于缓存淘汰数据项,而不用于缓存命中判断。FIFO算法的缺点是新的数据项可能会因旧的数据项长期驻留而导致新的数据项被淘汰,缓存的效率较差。

Memcached工作流程概览

Memcached工作流程主要包括下面几个步骤:

  • 客户端向Memcached发送请求:客户端可以向Memcached发起读、写或者删除请求,这些请求都会先经过负载均衡器,分配到相应的服务器节点上;
  • 请求路由:每台Memcached服务器都保存着整个缓存数据表的内容,当客户端向某个服务器发送请求的时候,服务器会根据请求的key检索缓存中是否有相应的值,如果有就返回,如果没有,就继续执行后续操作;
  • 查询缓存:如果缓存中有相应的值,就直接返回给客户端;
  • 更新缓存:如果缓存中没有相应的值,服务器会执行一次查询数据库操作,获取最新的数据,然后把数据更新到缓存中,同时更新缓存中对应的过期时间;

淘汰策略

缓存数据淘汰策略可以分为两种:

  • 时效性淘汰策略:当缓存数据项的时间戳比当前时间戳晚时,就认为该数据项已经过期,应当将其删除;
  • 大小淘汰策略:当缓存数据项的大小超出限制时,就应该淘汰一些数据项,以保持内存中缓存的总大小相对较小;

Memcached通过下面几个参数控制淘汰策略:

  • max_items:最大缓存项数目;
  • max_age:缓存项的过期时间;
  • max_bytes:缓存项的最大字节数;

分布式缓存

Memcached支持分布式部署,可以把缓存数据存放在多台服务器上,从而实现缓存的共享和冗余。分布式缓存服务器之间通过互相通信来同步数据,确保缓存数据一致性。

Memcached的分布式部署架构分为两层:

  • 一组前端服务器:提供接收客户端请求、分配请求给后端节点、响应客户端的请求等功能;
  • 一组后端服务器:保存真实的缓存数据和状态信息,包括数据项、标记、过期时间等;

Memcached的每个节点都维护着一份完整的缓存数据表,可以直接响应客户端的请求。

对象压缩

Memcached支持对象压缩功能,可以减少网络传输开销,改善客户端和服务器之间的性能。对象压缩通过GZIP、Snappy等压缩算法实现,具体压缩过程如下:

  1. 服务端收到客户端发送的数据后,对数据进行压缩;
  2. 服务端将压缩后的数据返回给客户端;
  3. 客户端接收到服务端返回的数据后,对数据进行解压缩;
  4. 客户端向服务端发送数据时,仍然先将数据压缩后再发送,以减少网络传输的数据量;

4.具体代码实例和详细解释说明

操作Java API

Memcached的Java客户端API可以通过Apache的JCS(Java Cache Service)组件进行操作。下面是一个简单的例子:

import org.apache.jcs.JCS;
import java.util.Map;
public class Test {
    public static void main(String[] args) throws Exception{
        // 初始化缓存名称
        String cacheName = "test";

        // 添加一条缓存数据
        JCS.getInstance(cacheName).put("key", "value");

        // 获取一条缓存数据
        Object value = JCS.getInstance(cacheName).get("key");

        System.out.println(value);
    }
}

首先,初始化缓存名称和创建缓存对象。然后,添加一条缓存数据,再次获取该数据并打印出来。

Spring Boot集成

Spring Boot对Memcached的集成也十分便利。只需在配置文件application.yml中添加如下配置即可:

spring:
  cache:
    type: memcached
    config:
      servers: localhost:11211 # 配置Memcached服务器地址

然后,可以使用注解@Cacheable或@CachePut来缓存方法的返回结果:

@Service
public class UserService {
    @Cacheable(value="user")
    public User findUserById(Long id){
        return userDao.findById(id);
    }

    @CachePut(value="user")
    public User saveUser(User user){
        return userDao.saveAndFlush(user);
    }
}

其中,“user”是缓存名称。在第一次调用findUserById()方法时,会先查询缓存中是否有相应的数据;如果有,则直接返回;如果没有,则调用DAO的方法从数据库中查询数据,然后将查询结果写入缓存。在第二次调用saveUser()方法时,不会再去查询数据库,而是直接从缓存中读取之前保存的数据,并更新缓存中的数据。这样,既能提高效率,又能提高系统的鲁棒性。

负载均衡

Memcached官方推荐使用Nginx+Twemproxy组合实现负载均衡。TwememProxy是一个轻量级的代理服务器,它能智能识别客户端的操作系统、屏幕分辨率、IP地址等特征信息,将相同客户端的请求分配到同一台服务器上。

缓存穿透与缓存击穿

缓存穿透是指查询一个一定不存在的数据,由于缓存中没有对应的数据,所以每次查询都要去数据库中查询。这会导致缓存和数据库的短时间内大量请求,造成系统的承受能力跟不上,甚至可能宕机。解决办法是首先排查数据库查询语句是否有错,如where条件中条件值不匹配导致的数据缺失等;然后考虑使用缓存预热(将缓存中重要的数据先加载到缓存),避免在缓存中查询不到数据。

缓存击穿是指一个热点数据过期期间,大量的请求都集中落在这个过期的缓存上,而没有访问过期缓存的数据。这样会给数据库造成巨大的压力。解决办法是尽量降低缓存过期时间,让缓存数据不过期,并且设置比较短的过期时间;另外,可以设计统计模块来收集缓存命中率、缓存失效次数等信息,对异常热点数据进行监控和管理。

5.未来发展趋势与挑战

Memcached作为一款开源且具有广泛应用前景的分布式缓存技术,其存在的一些问题也是值得注意的。比如在并发场景下的线程安全问题、高可用问题、持久化存储问题、数据一致性问题、故障转移问题等。

Memcached的容量有限,无法完全满足大规模数据的缓存需求。因此,更加成熟的缓存系统如Redis等正在逐渐崛起,它们通过一些优化手段来解决这些问题。例如,Redis在内存上使用一个哈希表来存储数据,支持数据的备份和主从复制,还支持数据持久化功能,可以实现灾难恢复能力;另外,Redis支持多种数据结构,如String、List、Set、SortedSet等,使得缓存功能更加丰富;

Memcached由于采用纯文本协议,无法对数据加密,这对于一些敏感的数据来说,会带来安全风险。为解决这一问题,业界正在研究更加安全的分布式缓存系统,如Redis、Memcached+Envoy等。

6.附录常见问题与解答

  • Q: Memcached基于内存,有什么缺陷?

  • A: 缓存是任何技术的重要组成部分,它的优势之一就是快速访问,如果出现数据被频繁访问,那么缓存命中率就会变得很低,因此Memcached的设计目的就是为了提高缓存命中率,减少数据库的访问。但是Memcached也有自己的一些缺陷:

    1. 内存容量有限:在分布式缓存架构中,每个节点都会缓存整个数据,因此缓存容量有限,只能缓存少量热点数据;
    2. 不支持数据过期:由于所有数据都保存在内存中,如果发生故障需要重启,或者程序意外退出,那么所有缓存数据将会消失,失去其缓存的意义;
    3. 不支持自动删除:虽然Memcached提供了手动淘汰策略,但不能自动删除过期缓存数据,因此如果数据暂时不再热门,又过期了,则依然会留在缓存中;
  • Q: Redis、Memcached等技术的比较和选型?

  • A: 在工程实践中,应该优先选择更加成熟、稳定的缓存技术。

    1. Redis:Redis是完全开源免费的,使用ANSI C编写,是个高性能的键-值存储系统。它支持数据持久化,支持主从同步,支持事务,支持数据备份。其特点包括速度快、支持丰富数据结构、支持发布订阅模式、支持Lua脚本、支持过期数据删除、支持Linux操作系统等。
    2. Memcached:Memcached是一个高性能的分布式内存对象缓存系统,用纯内存存储数据,具有高速访问能力。Memcached支持多种缓存策略,包括内存分配、LRU淘汰策略、失效策略等。它的分布式部署架构支持横向扩展,具备良好的容错性和可靠性。
    3. Apache Cassandra:Apache Cassandra是一个分布式 NoSQL 数据库,支持自动数据分片、数据复制和节点故障转移等。它的主要特点包括自动并行处理、数据可用性和一致性、水平可伸缩性等。
    4. MongoDB:MongoDB是一个基于分布式文档数据库。它的文档数据模型是JSON格式,具有灵活的数据结构。支持查询语言,具备索引功能,支持全文搜索。
    5. Couchbase:Couchbase是一个NoSQL文档数据库,支持分布式架构,提供高性能的全文索引和搜索功能。
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到