您将学习存储和检索数据的两种技术。当选择要在应用程序中使用的方法时,请根据数据访问模式选择可简化架构的方法。

但首先要确保您可以连接到 Redis。

完成模块所需时间:60 分钟



步骤 4.1

(单击可放大)

步骤 4.1
步骤 4.2

(单击可放大)

步骤 4.2

在示例中,每次提到终端节点时,都应使用配置终端节点的主机名。

步骤 4.3

(单击可放大)

步骤 4.3

syntax: shell

$ python

如果命令挂起,请参阅示例后面的说明。 

syntax: python

syntax: python
>>> import redis
>>> client = redis.Redis.from_url('redis://endpoint:6379')
>>> client.ping()

True

注意:如果挂起,说明您被安全组设置阻止。验证 EC2 实例是否可以访问分配给 ElastiCache 实例的安全组。例如,假设您的 EC2 实例已分配给默认安全组。现在,您可以修改 Amazon ElastiCache 实例的安全组,并添加一个自定义 TCP 规则,以允许来自默认安全组中任何实例的端口 6379 上的连接:

在“源”中,可以开始键入安全组的名称,并能够单击“安全组 ID”。如需了解有关安全组的更多信息,可以查看文档安全组规则引用

步骤 4.5

(单击可放大)

步骤 4.5

存储库中,您将找到一些可以在 EC2 实例中运行的 Python 代码。但首先,需要配置一些环境变量:

syntax: shell

$ export REDIS_URL=redis://your_redis_endpoint:6379/
$ export DB_HOST=your_mysql_endpoint
$ export DB_USER=admin
$ export DB_PASS=your_admin_password
$ export DB_NAME=tutorial

请注意,mysql_endpoint、redis_endpoint 和 password 的值是您在前面步骤中保存的值。


代码示例中实施的两种方法中的第一种方法会缓存 SQL 查询结果的序列化表示。以下 Python 代码段展示了此逻辑:

syntax: python

def fetch(sql):

  result = cache.get(sql)
  if result:
    return deserialize(result)
  else:
    result = db.query(sql)
    cache.setex(sql, ttl, serialize(result))
    return result

首先,在 Redis 中将 SQL 语句用作键,然后检查缓存以查看是否存在值。如果值不存在,则使用 SQL 语句查询数据库。数据库查询结果存储在 Redis 中。必须根据应用程序的性质,将 ttl 变量设置为合理的值。当 ttl 过期时,Redis 将移出键并释放相关内存。这段代码可以在教程存储库中找到,您可以按原样运行,但是如果希望在某个时间点查看某个变量的值,可以随意在各处添加 print 语句。

从策略角度看,此方法的缺点是,当数据库中的数据被修改时,如果先前的结果已缓存,且其 ttl 还没有过期,则这些更改不会自动反映给用户。

如何使用 fetch 函数的示例:

syntax: python

print(fetch("SELECT * FROM planet"))

结果将为:

syntax: python

[{'id': 10, 'name': 'Mercury'},
 {'id': 11, 'name': 'Venus'},
 {'id': 12, 'name': 'Earth'},
 {'id': 13, 'name': 'Mars'},
 {'id': 14, 'name': 'Jupiter'},
 {'id': 15, 'name': 'Saturn'},
 {'id': 16, 'name': 'Uranus'},
 {'id': 17, 'name': 'Neptune'}]

当然,这是一个非常基本的示例,但是您的应用程序可以通过实施这种缓存模式而获益颇丰,在这种模式中,来自缓存的结果与直接来自数据库的结果没有差别。


您将实施的第二个示例将数据库记录映射到 Redis 哈希:

syntax: python

def planet(id):

  key = "planet:" + str(id)
  result = cache.hgetall(key)

  if result:
      return result

  else:
      sql = "SELECT `id`, `name` FROM `planet` WHERE `id`=%s"
      result = db_record(sql, (id,))

      if result:
          cache.hmset(key, result)
          cache.expire(key, ttl)
      return result

Redis 中的键空间为平面,但是有一个惯例是通过使用冒号分隔的字符串来模拟结构。在本例中,ID 为 1 的记录的键采用“planet:1”。虽然此代码段足以展示一个通用模式,但是可以进一步抽象:一个模块负责生成键,另一个模块负责构建 SQL 字符串等等。此外,在您所使用的编程语言中也可能存在为此目的而构建的工具。
该示例从缓存或数据库检索记录,同样,可以有一个函数负责将对象持久存储到数据库。


在这两个示例中,您使用了生存时间 (ttl),该时间过后,Redis 将移出键。虽然这在大多数情况下已足以满足要求,但是您可能希望尽快从缓存中删除陈旧数据。如果确实需要如此,请确保检查其他选项,如直写缓存策略。本教程末尾提供了更多信息的链接。为满足您的好奇心,需要值得一提的是:虽然示例使用了 EXPIRE 命令,但 Redis 也提供了 EXPIREAT,用于指定应移出键的确切日期和时间。它使用的参数是一个绝对 Unix 时间戳(即,从 1970 年 1 月 1 日开始的秒数)。


当数据量超过配置的 maxmemory 设置时,Redis 将根据选择的移出策略采用不同的方法做出响应。默认情况下,ElastiCache for Redis 配置为从内存中删除设置了 ttl 且最近最少使用的键。移出策略参数称为 maxmemory-policy,ElastiCache 中的默认值为 volatile-lru。此使用案例的另一个有趣选项是 volatile-ttl 策略,它指示 Redis 通过删除那些 ttl 最短的键来回收内存。


实施此策略后,请确保对您的应用程序进行测试,以确定最佳 ttl 值和最佳移出策略。使用空缓存和满缓存检查应用程序的性能。