实时聊天消息应用正在呈指数级流行。像 WhatsApp、Facebook、Telegram、Slack、Discord 这样的移动应用已成为我们生活中“不可或缺的一部分”。用户对这些实时聊天移动应用对话非常着迷,因为它们带来了个人化的感觉并提供了实时互动。
社交媒体应用的兴起带来了社交元素,使协作、消息传递、社交互动和评论等活动成为可能。这些活动需要实时能力才能自动向用户呈现更新的信息。越来越多的开发者正在利用 Redis 的强大功能,因为它速度极快,并支持各种丰富的数据结构,例如列表 (Lists)、集合 (Sets)、有序集合 (Sorted Sets)、哈希 (Hashes) 等。Redis 还带有 Pub/Sub 消息传递功能,允许开发者通过生成多个服务器实例来扩展后端。
在本教程中,我们将了解如何使用 Flask、Socket.IO 和运行在 Amazon Web Services 上的 Redis Cloud 构建实时聊天应用。本示例结合使用了 Pub/Sub 功能和 Web-sockets 来实现客户端和服务器之间的消息通信。
遵循本教程 注册一个免费的 Redis Cloud 账户。如果您已经拥有现有账户,那么您只需要您的登录凭据即可访问您的订阅。
创建新订阅时选择 AWS 作为云供应商。创建新数据库时,请确保设置自己的密码。在数据库创建过程结束时,您将获得 Redis Cloud 数据库端点和端口。请保存这些信息,稍后会用到。
您无需创建 AWS 账户即可设置您的 Redis 数据库。AWS 上的 Redis Cloud 是一个完全托管的数据库即服务,因其高性能、无限可扩展性、真正的高可用性和一流的支持而受到成千上万客户的信赖。
git clone https://github.com/redis-developer/basic-redis-chat-app-demo-python
cd client
yarn install
yarn start
You can now view client in the browser.
Local: http://localhost:3000
On Your Network: http://192.168.1.9:3000
cd ..
pip3 install -r requirements.txt
python3 -m venv venv/
source venv/bin/activate
python3 app.py
* Restarting with stat
* Debugger is active!
* Debugger PIN: 220-696-610
(8122) wsgi starting up on http://127.0.0.1:5000
聊天应用服务器作为一个基本的 REST API 工作,它负责维护会话和处理聊天室中的用户状态(除了 WebSocket/实时部分)。当服务器启动时,会执行初始化步骤。首先,建立一个新的 Redis 连接,并检查是否需要加载演示数据。
为简单起见,会检查键 total_users 的值:如果它不存在,我们就用初始数据填充 Redis 数据库。EXISTS total_users(检查键是否存在)演示数据初始化分多个步骤处理。
我们创建一个新的用户 ID:INCR total_users。然后我们按用户名设置一个用户 ID 查找键,例如:
SET username:nick user:1
最后,其余数据被写入哈希集合
HSET user:1 username "nick" password "bcrypt_hashed_password".
此外,每个用户都被添加到默认的“General”房间。为了处理每个用户的房间,我们有一个集合来保存房间 ID。下面是如何添加房间的示例命令:
SADD user:1:rooms "0"
首先,创建私聊房间:如果需要建立一个私聊房间,则为每个用户生成一个房间 ID,例如 room:1:2,其中数字对应于按升序排列的用户 ID。
例如:在 2 个用户之间创建私聊房间
SADD user:1:rooms 1:2 and SADD user:2:rooms 1:2
然后我们通过写入有序集合将每个对话的消息添加到此房间
ZADD room:1:2 1615480369 "{'from': 1, 'date': 1615480369, 'message': 'Hello', 'roomId': '1:2'}"
我们使用字符串化的 JSON 来保持消息结构,并简化此演示应用的实现细节。您可以选择使用哈希或 JSON。
消息被添加到 ID 为“General”房间的有序集合中:room:0
初始化后,会创建一个 Pub/Sub 订阅:SUBSCRIBE MESSAGES。同时,每个服务器实例都会在该通道上运行一个监听器来接收实时更新的消息。
同样,为简单起见,每条消息都被序列化为 JSON,我们对其进行解析,然后以与 WebSocket 消息相同的方式处理。
Pub/Sub 允许连接用不同平台编写的多个服务器,而无需考虑每个服务器的实现细节。
当建立 WebSocket 连接时,我们可以开始监听事件
使用带有 online_users 键的全局集合来维护每个用户的在线状态。因此,建立新连接时,用户 ID 会被写入该集合。
SADD online_users 1
这里我们将 ID 为 1 的用户添加到了 online_users 集合中
之后,会向客户端广播一条消息,通知他们有新用户加入了聊天。
PUBLISH message "{'serverId': 4132, 'type':'message', 'data': {'from': 1, 'date': 1615480369, 'message': 'Hello', 'roomId': '1:2'}}"
请注意,我们发送了与消息类型和服务器 ID 相关的附加数据。服务器 ID 用于发送消息的服务器实例丢弃消息,因为它连接到相同的 MESSAGES 通道。
序列化的 JSON 的 type 字段对应于我们用于实时通信的实时方法(连接/断开连接/消息)。
data 是方法特定的信息。在上面的示例中,它与新消息相关。
Redis 主要用作数据库来存储用户/消息数据以及在连接的服务器之间发送消息。
实时功能由 Socket.IO 处理服务器-客户端消息传递。此外,每个服务器实例都订阅 Pub/Sub 的 MESSAGES 通道并在消息到达时分发。请注意,服务器使用单独的事件流(由服务器发送事件处理)传输 Pub/Sub 消息,这是因为需要运行独立于 socket.io 信号的 Pub/Sub 消息循环。
聊天数据存储在各种键和各种数据类型中。用户数据存储在哈希集合中,其中每个用户条目包含以下值:
获取用户 HGETALL user:{id}。
HGETALL user:2
我们获取 ID 为 2 的用户数据。
SMEMBERS user:2:rooms
这将返回 ID 为 2 的用户的房间 ID
示例
ZREVRANGE room:1:2 0 50
这将返回用户 ID 为 1 和 2 之间的私聊房间的 50 条消息,偏移量为 0。