在本课程中,我们将结合一个示例应用程序,了解如何使用 Redis 作为数据存储和缓存。想象一下,我们正在构建一个社交网络应用程序,用户可以在不同的地点“签到”,并给这些地点打星级评分……从 0 分(糟糕的体验)到 5 分(有史以来最好的时光)!
在设计应用程序时,我们确定需要管理关于三个主要实体的数据
让我们看看我们存储的关于这些实体的数据。由于我们将 Redis 作为唯一的数据存储,我们还将考虑如何将它们映射到 Redis 数据类型……
我们将把每个用户表示为一个不包含嵌套对象的键值对平面映射。正如稍后将看到的那样,这很好地映射到了 Redis 哈希。以下是我们用于表示每个用户的模式的 JSON 表示形式
{
"id": 99,
"firstName": "Isabella",
"lastName": "Pedersen",
"email": "[email protected]",
"password": "xxxxxx1",
"numCheckins": 8073,
"lastCheckin": 1544372326893,
"lastSeenAt": 138
}
我们为每个用户分配了一个 ID,并存储了他们的基本信息。此外,在将示例数据加载到 Redis 中时,我们将使用 bcrypt 加密他们的密码。
对于每个用户,我们将跟踪他们向系统提交的签到总数,以及他们最近一次签到的时间戳和地点 ID,以便我们知道他们最后一次使用系统的时间和地点。
对于用户可以签到的每个地点,我们将维护两种类型的数据。第一种也是键值对的平面映射,包含关于该地点的摘要信息
{
"id": 138,
"name": "Stacey's Country Bakehouse",
"category": "restaurant",
"location": "-122.195447,37.774636",
"numCheckins": 170,
"numStars": 724,
"averageStars": 4
}
我们为每个地点分配了一个 ID 和一个类别——稍后我们将使用该类别按类型搜索地点。“location”字段以经度、纬度格式存储坐标……这与通常的纬度、经度格式相反。稍后在查看 Redis Search 时,我们将看到如何使用它进行地理空间搜索。
对于每个地点,我们还存储了所有用户在该地点记录的签到总数、这些签到给该地点的总星数,以及该地点每次签到的平均星级评分。
我们希望为每个地点维护的第二种类型的数据是我们称之为“地点详情”的数据。这些数据以更结构化的 JSON 文档形式存在,包含嵌套对象和数组。以下是地点 138,Stacey's Country Bakehouse 的一个示例
{
"id": 138,
"hours": [
{ "day": "Monday", "hours": "8-7" },
{ "day": "Tuesday", "hours": "9-7" },
{ "day": "Wednesday", "hours": "6-8" },
{ "day": "Thursday", "hours": "6-6" },
{ "day": "Friday", "hours": "9-5" },
{ "day": "Saturday", "hours": "8-9" },
{ "day": "Sunday", "hours": "7-7" }
],
"socials": [
{
"instagram": "staceyscountrybakehouse",
"facebook": "staceyscountrybakehouse",
"twitter": "staceyscountrybakehouse"
}
],
"website": "www.staceyscountrybakehouse.com",
"description": "Lorem ipsum....",
"phone": "(316) 157-8620"
}
我们希望构建一个 API,允许我们检索所有或部分这些额外详细信息,并保持文档的整体结构完整。为此,我们需要支持 JSON 的 Redis,这将在稍后看到。
签到与用户和地点不同,它们不是我们需要永久存储的实体。在我们的应用程序中,签到包含用户 ID、地点 ID、星级评分和时间戳——我们将使用这些值来更新用户和地点的属性。
每个签到可以被视为一个键值对平面映射,例如
{
"userId": 789,
"locationId": 171,
"starRating": 5
}
在这里,我们看到用户 789 访问了地点 171(“Hair by Parvinder”),并且对服务非常满意。
我们需要一种方法来存储签到足够长的时间以便处理它们,但不是永久存储。我们还需要为每个签到关联一个时间戳,因为在处理数据时需要用到它。
Redis 提供了一种非常适合此用途的 Stream 数据类型——使用 Redis Streams,我们可以存储键值对的映射,并让 Redis 服务器为我们打上时间戳。Streams 也非常适合我们想要对这些数据进行的异步处理。当用户向我们的 API 发布新的签到时,我们希望尽快存储该数据并响应用户已收到。稍后,系统中的一个或多个其他部分可以对其进行进一步处理。此类处理可能包括更新用户的签到总数和最后访问字段,或者计算该地点新的平均星级评分。
我们决定使用 Node.js 以及 Express 框架和 ioredis 客户端来构建应用程序。该应用程序没有采用单体代码库,而是被拆分为四个组件或服务。它们是
这些组件的组合方式如下所示
还有一个数据加载器组件,我们将用它向系统中加载一些初始示例数据。
随着课程的进展,我们将依次查看这些组件。在下一个模块中,您将进行实践操作,克隆应用程序仓库,使用 Docker 启动 Redis 服务器,并加载示例数据。