使用 Amazon ElastiCache 针对高容量工作负载进行缓存

简介

在上一节教程中,您创建了一个应用程序,用户可以通过它来评价餐厅,并浏览其他用户留下的评论。您使用了 Amazon DynamoDB 作为该应用程序的主数据库,因为它在应用程序规模较大时性能表现优异。

在本教程中,您将学习如何向餐厅评论应用程序中添加缓存。缓存可以帮助减轻主数据存储的压力或缩短常见工作流的延迟时间。

在本教程中,我们将使用 Amazon ElastiCache,这是 AWS 提供的全托管内存中缓存解决方案。首先,您将了解为什么要使用 ElastiCache。然后,您将分步创建和配置 ElastiCache 实例表并在应用程序中使用该实例。在本教程结束时,您应当知道何时以及如何在应用程序中使用 ElastiCache。

完成所需时间:30–45 分钟

专用数据库 - ElastiCache(17 分 5 秒)
为什么使用 ElastiCache?

应用程序通常需要一个功能强大的持久数据库作为其主要数据存储。这可能意味着使用关系数据库(如 Amazon Aurora),也可能意味着与 MongoDB 兼容的 NoSQL 数据库(如 DynamoDB 或 Amazon DocumentDB)。这些数据库提供强大的查询功能和强大的数据保证,非常适合您的主数据库。

但有时您需要比主数据存储更低的延迟时间。又或许您的应用程序中有一个常见的请求流,其读取次数明显多于写入次数。对于这些情况,您可能需要使用内存中缓存来提供帮助。您可以将频繁读取的查询的结果保存在缓存中,以缩短响应时间并减轻主数据库的压力。

ElastiCache 为以下两个开源的内存中缓存引擎提供支持:Redis 和 Memcached。通过 ElastiCache,您可以使用全托管的内存中缓存。您无需关心执行实例故障转移、备份和恢复或软件升级。这让您可以更专注于为客户创新。

教程内容

在本教程中,您将学习如何将 ElastiCache 用作现有应用程序的内存中缓存。本教程分为四个步骤。

  • 在本模块中,您将创建和准备 AWS Cloud9 环境。AWS Cloud9 是基于云的集成开发环境 (IDE)。它可以为您快速搭建一致的开发环境,让您在其中快速构建 AWS 应用程序。


    首先,请前往 AWS Cloud9 控制台。点击 Create environmen(创建环境)以启动 AWS Cloud9 环境创建向导。

    (单击进行缩放)

    在向导的第一页,为您的环境命名和提供描述。然后点击 Next step(下一步)。

    (单击进行缩放)

    在下一步中,您可以配置环境实例类型、平台和网络设置等环境设置。

    在本教程中保留默认设置,因此滚动到底部并点击 Next step(下一步)。

    (单击进行缩放)

    最后一步显示您的设置以供审查。滚动到底部并点击 Create environment(创建环境)。

    (单击进行缩放)

    预配 AWS Cloud9 环境应当需要几分钟时间。如果系统正在创建环境,则会显示以下屏幕。

    (单击进行缩放)

    几分钟后,您应当会看到 AWS Cloud9 环境。如以下屏幕截图所示,AWS Cloud9 控制台有三个区域需要了解:

    • 文件资源管理器:文件资源管理器位于 IDE 的左侧区域,会显示您目录中的文件列表。
    • 文件编辑器:文件编辑器位于 IDE 的右上区域,您可以在其中查看和编辑在文件资源管理器中选择的文件。
    • 终端:终端位于 IDE 的右下区域,您可以在其中运行用来执行代码示例的命令。
    (单击进行缩放)

    在本教程中,您将使用 Python 与 ElastiCache 数据库进行交互。在 AWS Cloud9 终端运行以下命令来下载并解压缩模块代码。

    cd ~/environment
    curl -sL https://s3.amazonaws.com/aws-data-labs/restaurant-cache.tar | tar -xv

    在 AWS Cloud9 终端运行以下命令来查看您的目录内容。

    ls

    在 AWS Cloud9 终端,您应当会看到以下文件:

    • cache.py
    • dynamodb.py
    • entities.py
    • fetch_restaurant_summary.py
    • items.json
    • README.md
    • requirements.txt
    • test_connection.py

    在终端运行以下命令来安装应用程序的依赖项。

    sudo pip install -r requirements.txt

    pip install redis


    在本模块中,您配置了一个用于开发的 AWS Cloud9 实例。在下一个模块中,您将使用 ElastiCache 创建 Redis 实例。

  • 在本模块中,您将使用 Redis 引擎预置 ElastiCache 实例。您还可以配置对 Redis 实例的访问并测试来自 AWS Cloud9 实例的连接。


    首先,前往 ElastiCache 控制台。点击 Create(创建)以启动数据库创建向导。

    (单击进行缩放)

     Cluster engine(集群引擎)设置中,选择 Redis。

    (单击进行缩放)

    在 Redis settings(Redis 设置)部分中,为 Redis 实例命名。然后将 Node type(节点类型)更改为 cache.t2.micro,将 Number of replicas(副本数量)更改为 0。在生产设置中,可以选择使用副本和更大的 Node type(节点类型)。

    (单击进行缩放)

     Advanced Redis settings(高级 Redis 设置)中,可以将前几个设置保留其默认选项。

    在 Security(安全)部分中,记下附加到 Redis 实例的安全组。您将在创建集群后编辑此内容,以允许从 AWS Cloud9 实例访问 Redis。

    系统将选择默认安全组,该组适合在本教程中使用。

    (单击进行缩放)

    其余部分保留默认设置即可。滚动到底部,然后点击 Create(创建)以创建 Redis 实例。

    (单击进行缩放)

    ElastiCache 开始创建您的 Redis 实例。实例在创建时,在 ElastiCache 中显示的 Status(状态)为 creating(正在创建)。

    当 ElastiCache 实例就绪时,它的 Status(状态)为 available(可用)。

    (单击进行缩放)

    接下来,您需要允许从 AWS Cloud9 环境对 Redis 实例的安全组进行入站访问。这允许您连接到 Redis 实例。

    前往 Amazon EC2 控制台上的 Security Groups(安全组)页面。您应当会看到用于 ElastiCache 实例的默认安全组,以及用于 AWS Cloud9 实例的安全组。

    选择默认安全组以查看更多详细信息。

    (单击进行缩放)

    选择默认安全组后,您应当会看到有关该组的详细信息和入站规则。点击 Edit inbound rules(编辑入站规则)以编辑规则。

    (单击进行缩放)

    添加一个入站规则,以允许从 AWS Cloud9 实例到 Redis 实例的通信。规则的 Type(类型)应当为 Custom TCP(自定义 TCP),Port range(端口范围)应当为 6379。对于 Source(源),选择用于 AWS Cloud9 实例的安全组。

    此时的操作界面应如下所示。

    (单击进行缩放)

    点击 Save rules(保存规则)保存新的入站安全组规则。

    最后,测试从 AWS Cloud9 环境到 Redis 实例的连接。在 ElastiCache 控制台中,找到您的实例并展开详细信息。找到 Primary endpoint(主要端点)的值,然后复制该值。

    通过在终端运行以下命令来设置 AWS Cloud9 环境中端点的值。

    export REDIS_HOSTNAME=<yourPrimaryEndpoint>

    请务必将 <yourPrimaryEndpoint> 替换为从 ElastiCache 控制台复制的主端点。

    使用名为 test_connection.py 的脚本来测试您是否可以连接到 Redis。该脚本的内容如下所示。

    import os
    
    import redis
    
    HOST = os.environ["REDIS_HOSTNAME"].replace(":6379", "")
    
    r = redis.Redis(host=HOST)
    
    r.ping()
    
    print("Connected to Redis!")

    该脚本使用 Python 的 Redis 库连接到 Redis。它在终端使用您为 REDIS_HOSTNAME 环境中设置的主机名来初始化与 Redis 的连接。随后,它将针对 Redis 服务器运行 PING 命令。如果连接成功,应当会在控制台上看到一个指示您可以连接的输出结果。如果您看到异常,请查看上述步骤,以确保正确设置环境变量并允许来自 AWS Cloud9 环境的入站访问。


    在本模块中,您通过使用 ElastiCache 创建了一个 Redis 实例。您还将 Redis 实例上的安全组配置为允许从 AWS Cloud9 环境传入的网络通信。最后,您在 AWS Cloud9 环境中运行了一个测试命令,以确保您的配置正确无误。

    在下一个模块中,您将在 Redis 实例中实施旁路缓存策略。

  • 在本模块中,您将学习如何使用 Redis 实例实施旁路缓存策略。使用此策略在 restaurant-ratings 服务中缓存来自提取餐厅摘要访问模式的结果。这有助于减少数据库负载并缩短对最终用户的响应时间。


    您可以通过许多不同的策略来在应用程序中实施缓存。两种流行的策略是旁路缓存(或惰性缓存)和预写缓存

    使用旁路缓存策略时,在首次提取结果后,结果将进行缓存。例如,假设您为特定网页实施旁路缓存策略。当用户首次请求页面时,应用程序会检查缓存中是否有缓存的数据。由于这是首次请求,因此缓存中不存在数据。应用程序将转到源数据库以获取数据,将结果存储在缓存中,然后再将结果返回给用户。在后续请求中,数据在缓存中可用,应用程序无需转到源数据库。

    当数据的读取频率远高于写入频率时,旁路缓存策略是不错的选择。通过缓存结果,可以防止数据库负载过重。采用旁路缓存策略时,需要仔细考虑如何淘汰缓存数据或设置缓存数据的过期时间,以免向用户显示过时的数据。

    第二种策略(预写缓存)是通过主动方式向缓存中添加数据。与其等待用户首次请求数据,不如在数据发生变化时即刻更新。当请求的数据来自其他数据源且在查询时难以实时计算,这种模式是一种不错的选择。如果您能够准确掌握底层数据变更何时会使缓存失效,则可以通过预写策略缩短响应时间,同时确保数据的实时性。

    在本模块中,您将使用旁路缓存策略。在餐厅评级应用程序中实施提取餐厅摘要访问模式时,需要从 DynamoDB 读取并返回六条数据。此数据可能会在相当长的一段时间内有效,因为餐馆页面的浏览次数往往远多于评论。因此,您可以缓存此数据以减少 DynamoDB 表的负载。

    您的 AWS Cloud9 环境中有一个名为 fetch_restaurant_summary.py 的文件。在文件编辑器中打开此文件。其内容应如下所示。

    from dynamodb import fetch_restaurant_summary_from_database
    from cache import fetch_restaurant_summary_from_cache, store_restaurant_summary_in_cache
    
    
    def fetch_restaurant_summary(restaurant_name):
        restaurant = fetch_restaurant_summary_from_cache(restaurant_name)
        if restaurant:
            print("Using cached result!")
            return restaurant
    
        restaurant = fetch_restaurant_summary_from_database(restaurant_name)
        store_restaurant_summary_in_cache(restaurant)
    
        print("Using uncached result!")
    
        return restaurant
    
    
    restaurant = fetch_restaurant_summary("The Vineyard")
    
    print(restaurant)
    for review in restaurant.reviews:
        print(review)

    此文件包括一个名为 fetch_restaurant_summary 的函数,该函数与应用程序中的函数相似。该函数提取餐厅名称并执行以下操作:

    1. 它检查 Redis 缓存中是否存在餐厅摘要。如果缓存中存在数据,则该函数会将此数据返回给用户。
    2. 如果缓存中不存在数据,则该函数会从 DynamoDB 检索餐厅摘要。此处使用的代码与 DynamoDB 课程中用来处理提取餐厅摘要访问模式的代码相似。
    3. 从 DynamoDB 收到结果后,该函数将结果缓存在 Redis 中以供将来的请求使用。
    4. 摘要将返回给用户。

    一个名为 cache.py 的文件,其中包含与 Redis 缓存进行交互的代码。在文件编辑器中打开此文件。其内容应如下所示。

    
    from entities import Restaurant, Review
    
    import json
    import os
    
    import redis
    
    HOST = os.environ["REDIS_HOSTNAME"].replace(":6379", "")
    
    r = redis.Redis(host=HOST)
    
    
    class ObjectEncoder(json.JSONEncoder):
        def default(self, o):
            return o.__dict__
    
    
    def store_restaurant_summary_in_cache(restaurant):
        key = restaurant.name
        r.set(key, json.dumps(restaurant, cls=ObjectEncoder), ex=900)
    
        return True
    
    
    def fetch_restaurant_summary_from_cache(restaurant_name):
        response = r.get(restaurant_name)
        if response:
            data = json.loads(response)
            restaurant = Restaurant(data)
            restaurant.reviews = [Review(review) for review in data["reviews"]]
            return restaurant
        return None

    这里有两个函数。第一个函数用来在 Redis 中存储餐厅摘要。它使用餐厅名称作为 Redis 中的键名称,并将餐厅摘要转换为 JSON 字符串。然后它使用 Redis SET 命令设置 Redis 中字符串键的值。执行此操作时,它使用生存时间 (TTL) 值 900,即该值会在 15 分钟后过期。这有助于确保您的数据不会变得过时。

    第二个函数负责从 Redis 检索餐厅摘要。它获取餐厅名称并执行 Redis GET 命令以检索餐厅评级值。然后它解析数据,将其重构为应用程序中的对象,并返回结果。

    您可以通过在终端运行以下命令来测试缓存的使用情况。

    python fetch_restaurant_summary.py

    第一次运行该命令时,您应当会看到以下输出结果。

    $ python fetch_restaurant_summary.py
    Using uncached result!
    Restaurant<The Vineyard -- Fine Dining>
    Review<The Vineyard -- markmartin (2020-05-24T11:59:44)>
    Review<The Vineyard -- kgraham (2020-05-14T15:01:52)>
    Review<The Vineyard -- ewilliams (2020-05-13T02:36:30)>
    Review<The Vineyard -- hannah21 (2020-05-04T03:44:26)>
    Review<The Vineyard -- john97 (2020-04-27T20:45:52)>

    请注意,该脚本指示它在列显餐厅和评论之前使用的是未缓存的结果。

    再次运行该脚本以测试缓存行为。

    python fetch_restaurant_summary.py

    这次您应当会看到以下输出结果。

    $ python fetch_restaurant_summary.py
    Using cached result!
    Restaurant<The Vineyard -- Fine Dining>
    Review<The Vineyard -- markmartin (2020-05-24T11:59:44)>
    Review<The Vineyard -- kgraham (2020-05-14T15:01:52)>
    Review<The Vineyard -- ewilliams (2020-05-13T02:36:30)>
    Review<The Vineyard -- hannah21 (2020-05-04T03:44:26)>
    Review<The Vineyard -- john97 (2020-04-27T20:45:52)>

    您可以看到脚本指示这次它使用的是缓存的结果。不过,输出结果仍然与最初从 DynamoDB 提取的内容相同。根据为密钥设置的 TTL(过期时间为 900 秒),在接下来的 15 分钟内,这些结果将保留在您的 Redis 实例中,以便快速提供缓存结果。


    在本模块中,您了解了两种流行的缓存策略:旁路缓存和预写缓存。然后您了解了如何在应用程序中实施旁路缓存策略。通过旁路缓存策略,可以轻松地提高应用程序性能和减少主数据库的负载。

    在下一个模块中,您将清除在本教程中创建的资源。

  • 在本教程中,您使用 ElastiCache 创建了一个内存中缓存实例。内存中缓存是在应用程序中缩短响应时间并减少负载的绝佳方法。当您使用 ElastiCache 时,您将获得全托管体验,让您能够专注于为用户提供价值。

    在本模块中,将清除在本教程中创建的资源,以免产生额外费用。


    首先,删除 ElastiCache 实例。前往 ElastiCache 控制台。找到您为该模块创建的 ElastiCache 实例,选中与该实例相对应的复选框。然后点击 Delete(删除)以删除该实例。

    (单击进行缩放)

    在确认窗口中,拒绝用来为 Redis 实例创建最终备份的选项,然后点击 Delete(删除)。

    (单击进行缩放)

    另外,您还需要删除 AWS Cloud9 开发环境。

    为此,请前往 AWS Cloud9 控制台。选择您为本教程创建的环境,然后点击 Delete(删除)。

    (单击进行缩放)

    在本模块中,您学习了如何清除在本教程中创建的 ElastiCache 实例和 AWS Cloud9 环境。

缓存是使应用程序保持高性能的重要工具。在本教程中,您了解了如何创建和使用缓存来加速应用程序中常用的访问模式。这将使您应当能够自如使用缓存。

此页内容对您是否有帮助?