Django Channels 2026: WebSockets, Real-Time và Câu hỏi Phỏng vấn
Làm chủ Django Channels 4.x với WebSocket consumers, Redis channel layers, và các câu hỏi phỏng vấn thường gặp. Ví dụ code sẵn sàng cho production với triển khai ASGI.

Django Channels 4.x mở rộng Django vượt qua HTTP để xử lý WebSockets, cho phép các tính năng real-time như chat, thông báo, và live dashboard. Hướng dẫn này bao gồm các mẫu consumer, channel layers với Redis, và các câu hỏi phỏng vấn phân biệt ứng viên mid-level với senior.
Cài đặt với pip install channels channels-redis, chuyển ASGI_APPLICATION trỏ đến cấu hình routing, và chạy với Uvicorn thay vì Gunicorn. Redis bắt buộc cho mọi triển khai multi-process.
Tại sao Django Cần Channels cho WebSockets
Kiến trúc Django được xây dựng trên WSGI, một giao thức request-response đồng bộ. WSGI không có khái niệm về kết nối lâu dài. Django 4.1 đã thêm async views, nhưng async views vẫn tuân theo mẫu request-response, đóng kết nối sau mỗi response.
Hỗ trợ WebSocket yêu cầu ASGI, xử lý các kết nối lâu dài và giao tiếp hai chiều. Django Channels 4.x cung cấp lớp ASGI này, bọc hỗ trợ async native của Django với routing và các abstraction consumer.
# asgi.py
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import chat.routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})ProtocolTypeRouter phân phối các kết nối đến dựa trên loại giao thức. Các request HTTP đi đến handler ASGI chuẩn của Django, trong khi các kết nối WebSocket được định tuyến qua URLRouter đến consumer phù hợp.
AsyncWebsocketConsumer: Thành phần Cơ bản
Consumers là tương đương WebSocket của Django views. Lớp AsyncWebsocketConsumer cung cấp ba hook: connect, disconnect, và receive. Mỗi hook chạy như một coroutine, cho phép các thao tác I/O non-blocking.
# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class NotificationConsumer(AsyncWebsocketConsumer):
async def connect(self):
# Extract user from session via AuthMiddlewareStack
self.user = self.scope["user"]
if self.user.is_anonymous:
await self.close()
return
# Create user-specific channel group
self.group_name = f"notifications_{self.user.id}"
await self.channel_layer.group_add(
self.group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Clean up group membership
await self.channel_layer.group_discard(
self.group_name,
self.channel_name
)
async def receive(self, text_data):
# Handle incoming messages from client
data = json.loads(text_data)
await self.send(text_data=json.dumps({
"type": "ack",
"id": data.get("id")
}))
async def notification_message(self, event):
# Handler for messages sent via channel layer
await self.send(text_data=json.dumps({
"type": "notification",
"payload": event["payload"]
}))Dictionary scope chứa metadata kết nối, bao gồm user đã xác thực khi sử dụng AuthMiddlewareStack. channel_name là định danh duy nhất cho kết nối cụ thể này, trong khi groups cho phép broadcast đến nhiều kết nối.
Định tuyến Kết nối WebSocket
Routing ánh xạ URL paths đến consumers, tương tự như cấu hình URL của Django. Phương thức as_asgi() trả về instance ứng dụng ASGI cho mỗi lớp consumer.
# routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(
r"ws/notifications/$",
consumers.NotificationConsumer.as_asgi()
),
re_path(
r"ws/chat/(?P<room_name>\w+)/$",
consumers.ChatConsumer.as_asgi()
),
]Các tham số URL được bắt bởi regex groups xuất hiện trong self.scope["url_route"]["kwargs"]. Điều này cho phép định tuyến động, như tham gia các phòng chat khác nhau dựa trên URL path.
Redis Channel Layer cho Production
In-memory channel layer hoạt động cho development nhưng thất bại trong production. Mỗi process duy trì layer riêng, ngăn chặn giao tiếp giữa các process. Package channels-redis cung cấp giải pháp production-grade.
# settings.py
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("redis", 6379)],
"capacity": 1500,
"expiry": 10,
},
},
}Thiết lập capacity giới hạn message queue cho mỗi channel (mặc định: 100). Thiết lập expiry kiểm soát thời gian tin nhắn chờ trước khi bị loại bỏ (mặc định: 60 giây). Đối với các ứng dụng high-throughput, tăng capacity và giảm expiry để ngăn chặn tích tụ bộ nhớ.
Gửi Tin nhắn từ Django Views
Channel layers cho phép gửi tin nhắn WebSocket từ bất kỳ đâu trong ứng dụng, bao gồm Django views đồng bộ và Celery tasks.
# views.py
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def create_order(request):
order = Order.objects.create(user=request.user, **form.cleaned_data)
# Send notification to user's WebSocket connection
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
f"notifications_{request.user.id}",
{
"type": "notification_message",
"payload": {
"title": "Order Created",
"order_id": order.id
}
}
)
return redirect("order_detail", pk=order.id)Trường type ánh xạ đến phương thức handler trên consumer. notification_message trở thành notification_message() sau khi thay dấu chấm bằng underscore.
Sẵn sàng chinh phục phỏng vấn Django?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Truy cập Cơ sở dữ liệu trong Async Consumers
ORM Django mặc định là đồng bộ. Gọi các phương thức ORM đồng bộ từ async consumer sẽ chặn event loop, làm giảm hiệu suất. Có hai giải pháp: database_sync_to_async và các phương thức ORM async native của Django.
# consumers.py
from channels.db import database_sync_to_async
from .models import Message
class ChatConsumer(AsyncWebsocketConsumer):
@database_sync_to_async
def save_message(self, content):
return Message.objects.create(
room=self.room,
user=self.user,
content=content
)
async def receive(self, text_data):
data = json.loads(text_data)
message = await self.save_message(data["content"])
await self.channel_layer.group_send(
self.room_group_name,
{
"type": "chat_message",
"content": data["content"],
"user_id": self.user.id,
"message_id": message.id
}
)Django 4.1+ cung cấp các phương thức ORM async với tiền tố a: aget(), acreate(), afilter(). Điều này loại bỏ nhu cầu database_sync_to_async trong nhiều trường hợp.
# Using Django's native async ORM (Django 4.1+)
async def receive(self, text_data):
data = json.loads(text_data)
message = await Message.objects.acreate(
room=self.room,
user=self.user,
content=data["content"]
)Triển khai với Uvicorn và Nginx
Daphne là server ASGI ban đầu cho Channels. Uvicorn với uvloop mang lại hiệu suất tốt hơn cho các workloads WebSocket và có cộng đồng lớn hơn.
# Production deployment
uvicorn project.asgi:application \
--host 0.0.0.0 \
--port 8000 \
--workers 4 \
--ws websockets \
--loop uvloopNginx yêu cầu cấu hình đặc biệt cho WebSocket proxying. Các header Upgrade và Connection phải được chuyển tiếp để kích hoạt chuyển đổi giao thức từ HTTP sang WebSocket.
# nginx.conf
upstream channels {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name example.com;
location /ws/ {
proxy_pass http://channels;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
location / {
proxy_pass http://channels;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Thiết lập proxy_read_timeout ngăn Nginx đóng các kết nối WebSocket không hoạt động. Đặt giá trị phù hợp với thời gian kết nối dự kiến của ứng dụng.
Câu hỏi Phỏng vấn: Django Channels
Các câu hỏi này thường xuất hiện trong phỏng vấn senior Python developer. Câu trả lời được mong đợi vượt qua các định nghĩa cơ bản.
Tại sao Django không thể xử lý WebSockets native?
Django sử dụng WSGI, một giao thức đồng bộ trong đó mỗi request nhận được response và kết nối đóng lại. WebSockets yêu cầu kết nối lâu dài và hai chiều. WSGI không có đặc tả cho điều này. Async views của Django (thêm vào từ 4.1) vẫn tuân theo ngữ nghĩa request-response. Channels thêm hỗ trợ ASGI, xử lý các kết nối lâu dài và giao tiếp dựa trên sự kiện.
Sự khác biệt giữa channel và channel layer là gì?
Channel là một named queue nơi tin nhắn chờ consumer. Mỗi kết nối WebSocket nhận được một channel name duy nhất. Channel layer là transport backend (Redis, in-memory) định tuyến tin nhắn giữa các channels. Layer xử lý giao tiếp giữa các process, group membership, và serialization tin nhắn.
Khi nào sử dụng database_sync_to_async so với async ORM của Django?
Sử dụng các phương thức async ORM của Django (aget, acreate, afilter) cho các thao tác đơn giản, vì chúng tích hợp tốt với code async. Sử dụng database_sync_to_async khi gọi code đồng bộ không thể dễ dàng chuyển đổi, như các thư viện bên thứ ba, các QuerySet chains phức tạp, hoặc các phương thức kích hoạt các thao tác đồng bộ bổ sung như signals.
Làm thế nào để scale kết nối WebSocket theo chiều ngang?
Redis channel layer cho phép horizontal scaling. Tất cả các Uvicorn workers và tất cả các server instances giao tiếp thông qua Redis. Channel name của mỗi kết nối là duy nhất, và Redis theo dõi group membership. Sticky sessions không cần thiết vì channel layer, không phải server, duy trì connection state. Consumer chỉ cần channel name để gửi tin nhắn.
Điều gì xảy ra nếu Redis bị sập?
Các kết nối mới thành công vì connect() chạy trước group membership. Các kết nối hiện có vẫn mở nhưng mất group messaging. group_send ném exception hoặc thất bại im lặng tùy thuộc vào cấu hình. Đối với các ứng dụng quan trọng, triển khai kiểm tra tình trạng kết nối và kết nối lại linh hoạt ở phía client. Xem xét Redis Sentinel hoặc Redis Cluster để có sẵn cao.
Để chuẩn bị phỏng vấn Django thêm, xem module Django middleware và module Django signals trên SharpSkill.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Danh sách Kiểm tra Production cho Django Channels
- Sử dụng
channels-redisvới Redis 6+ cho channel layer. In-memory layer chỉ dành cho development. - Đặt
capacitydựa trên thông lượng tin nhắn dự kiến. 100 (mặc định) hoạt động cho hầu hết các ứng dụng. - Chạy Uvicorn với nhiều workers:
--workers 4cho server 4-core. - Cấu hình Nginx với
proxy_read_timeoutphù hợp với kết nối dự kiến dài nhất. - Triển khai logic kết nối lại ở phía client với exponential backoff.
- Giám sát sử dụng bộ nhớ Redis. Lượng tin nhắn cao với consumers chậm gây ra tăng trưởng bộ nhớ.
- Sử dụng các phương thức async ORM của Django khi có thể để tránh overhead thread pool.
- Kiểm tra với số lượng kết nối thực tế. Các kết nối WebSocket sử dụng nhiều tài nguyên hơn HTTP requests.
Bạn có tìm ra lỗi trong Django không?
Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Viết bởi
Anthony Fillion-MailletNgười sáng lập SharpSkill
Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.
Cập nhật ngày 23 tháng 8, 2026
Thẻ
Chia sẻ
Bài viết liên quan

Async View và ASGI trong Django 2026: Hiệu năng và câu hỏi phỏng vấn
Phân tích chuyên sâu về async view và ASGI trong Django 2026: cơ chế hoạt động bên dưới, server nên triển khai, async ORM cùng cái bẫy SynchronousOnlyOperation, kèm theo các câu hỏi phỏng vấn.

Tìm Hiểu Sâu Về Serializer Django REST Framework: Validation, Nested và Tối Ưu N+1
Hướng dẫn toàn diện về DRF serializers: pipeline validation, nested serializers, xử lý quan hệ phức tạp và các kỹ thuật tối ưu để tránh vấn đề N+1 queries.

Django và PostgreSQL năm 2026: Đánh chỉ mục, tìm kiếm toàn văn và câu hỏi phỏng vấn
Hướng dẫn thực hành tối ưu Django với PostgreSQL: chỉ mục B-tree, một phần và bao phủ, tìm kiếm toàn văn với SearchVector và GIN, cùng các câu hỏi phỏng vấn 2026.