在本课程中,我们将探讨如何在示例应用程序的背景下使用 Redis 作为数据存储和缓存。假设我们正在构建一个类似社交网络的应用程序,用户可以在不同的地点“签到”并对其进行星级评定……从 0 表示糟糕的体验到 5 表示他们在那儿度过了最美好的时光!
在设计应用程序时,我们确定需要管理三个主要实体的数据
让我们看看我们存储了关于每个实体的信息。由于我们使用 Redis 作为唯一的数据存储,我们还会考虑它们如何映射到 Redis 数据类型……
我们将每个用户表示为一个扁平的名称/值对映射,没有嵌套对象。正如我们稍后将看到的,这很好地映射到 Redis 哈希。以下是我们将用来表示每个用户的模式的 JSON 表示
{
"id": 99,
"firstName": "Isabella",
"lastName": "Pedersen",
"email": "isabella.pedersen@example.com",
"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 和一个类别——我们将在以后使用类别按类型搜索地点。“地点”字段存储经度、纬度格式的坐标……这与通常的纬度、经度格式相反。在查看 Redis 搜索时,我们将看到如何使用它执行地理空间搜索。
对于每个地点,我们还存储了我们所有用户在那里记录的签到总数、这些签到给该地点的星级总数以及该地点每次签到的平均星级评定。
我们希望为每个地点维护的第二种类型的数据是我们将称为“地点详细信息”。它们采用具有嵌套对象和数组的结构化 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,让我们能够检索所有或部分这些额外的详细信息,并保持文档的整体结构。为此,我们将需要 Redis 支持 JSON,正如我们稍后将看到的那样。
签到与用户和地点不同,它们不是我们需要永远存储的实体。在我们的应用程序中,签到包含用户 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 服务器,并加载示例数据。