Kiến trúc phần mềm cho dự án AI production
Trường ĐH Công nghệ – Đại học Quốc gia Hà Nội
| Góc nhìn | Model-centric | System-centric |
|---|---|---|
| Trọng tâm | accuracy model | mục tiêu hệ thống |
| Rủi ro | bỏ qua vận hành | quản trị trade-off rõ |
| Kết quả | demo tốt | sản phẩm chạy bền |
| Tiêu chí | Monolith | Microservices |
|---|---|---|
| Time-to-market ban đầu | Nhanh | Chậm hơn |
| Vận hành | Đơn giản | Phức tạp |
| Scale | Toàn khối | Từng service |
| Autonomy team | Thấp | Cao |
Triển khai: reverse proxy (NGINX, Envoy) hoặc cloud LB chấm dứt TLS; ứng dụng có thể chỉ nhận HTTP nội bộ sau TLS termination.
Luồng: định nghĩa .proto → chạy protoc → import code sinh ra trong project.
greeter.proto (định nghĩa service + message):
syntax = "proto3";
package demo;
// Service: compiler sẽ sinh GreeterStub (client) + GreeterServicer (server)
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Gợi ý lệnh (Python — cần grpcio-tools):
python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. greeter.proto
Go (plugin protoc-gen-go + protoc-gen-go-grpc):
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative greeter.proto
Sau khi chạy, project sẽ có các file *_pb2.py / *_pb2_grpc.py (Python) hoặc *.pb.go (Go) để implement server và gọi client.
| Tiêu chí | REST | gRPC |
|---|---|---|
| Client web/mobile | Rất tốt | Trung bình |
| Internal low latency | Khá | Rất tốt |
| Khả năng debug tay | Dễ | Khó hơn |
| Schema contract | Linh hoạt | Chặt chẽ |
Broker phổ biến: Mosquitto, EMQX, HiveMQ (managed/enterprise).
# demo nhanh với Mosquitto (broker) + CLI tools
mosquitto_sub -t "factory/line1/temperature"
mosquitto_pub -t "factory/line1/temperature" -m "28.5"
Bảo mật: chạy qua TLS + auth (username/password hoặc mTLS) khi đưa vào production.
# /etc/nginx/nginx.conf
stream {
upstream grpc_backends {
server 10.0.0.11:50051;
server 10.0.0.12:50051;
}
server {
listen 50051; # cân bằng kết nối TCP
proxy_pass grpc_backends;
}
}
Không nhìn thấy HTTP path/header; chỉ cân bằng theo connection.
# /etc/nginx/nginx.conf
http {
upstream api_backends {
server 10.0.0.21:8080;
server 10.0.0.22:8080;
}
server {
listen 80;
location /api/ {
proxy_pass http://api_backends;
}
}
}
Có thể route theo URL/host/header; hợp API/Web.
Hình dung: CDN/WAF → LB → API Gateway → services.
# Ví dụ ý tưởng: route /api/v1/* → user-service, có auth + rate-limit
route:
match: { path_prefix: "/api/v1/users" }
upstream: "http://user-service:8080"
plugins:
- jwt_auth: { issuer: "https://auth.example.com" }
- rate_limit: { per_minute: 100, by: "consumer" }
- request_id: true
- cors: { allow_origins: ["https://app.example.com"] }
| Load Balancer | API Gateway | |
|---|---|---|
| Mục tiêu | Phân tải | Quản trị API |
| Tầng | L4/L7 | L7 |
| Tính năng | route cơ bản | auth, quota, policy |
“There are only two hard things in Computer Science: cache invalidation…”
Mitigation: request coalescing / lock theo key, hoặc warm-up cache.
def get_user_profile(user_id: str):
key = f"user:{user_id}:profile"
cached = redis.get(key)
if cached is not None:
metrics.inc("cache_hit", 1)
return json.loads(cached)
metrics.inc("cache_miss", 1)
profile = db.query_user_profile(user_id) # chậm hơn cache
# TTL 300s (5 phút); có thể thêm jitter để tránh stampede
redis.setex(key, 300, json.dumps(profile))
return profile
Theo dõi hit-rate = hit/(hit+miss) theo từng endpoint/key để quyết định có đáng cache không.
# tạo key (Ed25519)
ssh-keygen -t ed25519 -C "admin@company"
# đăng nhập VPS
ssh -i ~/.ssh/id_ed25519 ubuntu@203.0.113.10
# local port 15432 → (bastion) → private-db:5432
ssh -N -L 15432:private-db.internal:5432 ubuntu@bastion.example.com
# sau đó app local có thể connect: localhost:15432
psql "postgresql://user:pass@localhost:15432/appdb"
Mô hình phổ biến: Internet → Bastion (SSH) → private subnet (DB/Redis/K8s control-plane).
| Ngôn ngữ / framework | ORM / layer | Ghi chú |
|---|---|---|
| Python + Django | Django ORM | Migration tích hợp |
| Python (FastAPI/Flask) | SQLAlchemy + Alembic | Linh hoạt, phổ biến backend hiện đại |
| Node.js | Prisma, TypeORM, Sequelize | Prisma: schema + generate type |
| Java | Hibernate / JPA | Enterprise |
| C# | Entity Framework | .NET |
ORM tiện khi prototype; production cần chủ động index và kiểm soát query.
[Vị trí ảnh: SQL vs NoSQL — use case]
[Vị trí ảnh: MinIO — bucket / kiến trúc]
| Khía cạnh | Milvus | Qdrant |
|---|---|---|
| Hệ sinh thái | LF AI, hướng cluster/partition | Rust, REST/gRPC, deploy nhẹ |
| Đặc điểm | Metadata filter, nhiều loại index (HNSW, IVF…) | Filter + payload JSON, hybrid search |
| Gợi ý chọn | Workload lớn, team quen vận hành distributed | Prototyping nhanh, self-host đơn giản |
Tích hợp thường gặp: LangChain, LlamaIndex… [Vị trí ảnh: luồng embedding → Milvus/Qdrant → top-k]
[Vị trí ảnh: kiến trúc online inference — CDN/LB/Gateway → inference → cache/DB]
Pattern chính: rate limiting + caching + stateless scaling + graceful degradation.
Pattern chính: decoupling + replay + exactly/at-least-once trade-off.
Pattern chính: “batch trước, online sau” (precompute) để giảm latency và cost.
Pattern chính: tách “index build” (offline/async) khỏi “retrieve” (online/low latency).
[Vị trí ảnh: device inference — model on device + sync + telemetry]
Pattern chính: tối ưu model + kiểm soát rollout + quan sát từ xa.
Bạn xây ứng dụng chatbot nội bộ cho 300 nhân viên:
Bạn có app gợi ý video tăng từ 5K lên 500K DAU: