Câu hỏi phỏng vấn Python Senior

Một người bạn vừa đi phỏng vấn vị trí Python backend senior tại một trong những công ty outsourcing lớn nhất Việt Nam. Sau buổi phỏng vấn, họ kể lại toàn bộ những gì được hỏi — hai vòng, hai interviewer, từ "tại sao bạn muốn nghỉ việc?" cho đến database internals khá sâu.
Bài này breakdown từng câu với kiểu trả lời mà một senior engineer thực sự đưa ra — không phải định nghĩa trong sách giáo khoa, mà là reasoning thực tế đằng sau từng quyết định.
Section 1 — Non-Technical (Interviewer 1)
Những câu này nghe có vẻ "soft", nhưng thực ra tiết lộ rất nhiều về self-awareness và communication style của bạn. Đừng bịa đặt tại chỗ.
"Giới thiệu bản thân"
Đừng đọc lại resume. Kể một câu chuyện. Cần có:
- Bạn đã build gì và ở quy mô nào
- Những technical decision bạn tự chủ (và tại sao)
- Bạn đang optimize cho điều gì tiếp theo
Ví dụ: "Tôi đã dành 3 năm gần đây build backend service bằng Python — chủ yếu là FastAPI — phục vụ vài triệu request mỗi ngày. Việc lớn nhất tôi làm gần đây là rearchitect cái async job pipeline để giảm latency 40%. Tôi đang tìm một role để đi sâu hơn vào distributed systems design."
"Tại sao bạn muốn nghỉ công ty hiện tại?"
Thành thật, hướng về phía trước. Tránh nói xấu công ty cũ. Những câu trả lời tốt:
- "Tôi đã phát triển đến mức tối đa trong môi trường này và muốn challenge lớn hơn."
- "Định hướng công ty thay đổi — bây giờ ít technical hơn lúc tôi join."
- "Tôi muốn làm việc trên những problem ở scale lớn hơn."
"Tại sao bạn nghĩ mình phù hợp với công ty này?"
Nghiên cứu trước. Frame câu trả lời xung quanh business domain và tech stack của họ. Cho thấy bạn đã nghĩ về problem của họ, không chỉ resume của mình.
"Project nào bạn tự hào nhất?"
Đây là cơ hội để bạn cho thấy chiều sâu. Chọn một project và đi thật sâu — đừng liệt kê năm project nông cạn. Một câu trả lời mạnh cần có:
- Problem: Bạn đang giải quyết vấn đề gì thật sự? Tại sao nó quan trọng?
- Vai trò cụ thể của bạn: Bạn đưa ra quyết định gì, không phải cả team?
- Technical challenge: Cái gì khó, và bạn đã nghĩ qua nó như thế nào?
- Kết quả: Impact đo được — latency, throughput, chi phí, user growth
Ví dụ: "Project tôi tự hào nhất là một real-time data pipeline tôi redesign ở công ty trước. Chúng tôi có một batch job chạy mỗi 15 phút khiến analytics dashboard bị stale data đáng kể. Tôi thay thế nó bằng async event-driven pipeline dùng FastAPI background task và Redis Streams — giảm data lag từ 15 phút xuống dưới 5 giây, đồng thời giảm 30% chi phí infrastructure vì không cần scheduler VM nữa. Phần khó nhất là đảm bảo exactly-once delivery khi failover, tôi giải quyết bằng Redis consumer group với manual ACK."
Interviewer đang nghe gì:
- Bạn có thể giải thích một hệ thống phức tạp rõ ràng không?
- Bạn tự chủ problem hay chỉ execute plan của người khác?
- Bạn có hiểu trade-off mình đã làm, kể cả những gì bạn không làm không?
Section 2 — Technical Deep-Dive (Interviewer 2)
Data structure: tuple, list, set, dict khác nhau thế nào?
Nghe có vẻ basic, nhưng senior candidate phải đi xa hơn "list mutable, tuple không mutable."
| Structure | Có thứ tự | Mutable | Cho phép trùng | Use case |
|---|---|---|---|---|
list | ✅ | ✅ | ✅ | Dãy items cần modify |
tuple | ✅ | ❌ | ✅ | Record cố định, return value, dict key |
set | ❌ | ✅ | ❌ | Membership testing, dedup |
dict | ✅ (3.7+) | ✅ | Keys: ❌ | Key-value lookup, structured data |
Những điểm senior thêm vào:
listoperations nhưappend()là O(1) amortized, nhưnginsert(0, x)là O(n) — đừng dùng list như queue.setvàdictdùng hash table bên dưới — lookup O(1) average.frozensetlà immutable counterpart củaset, và nó hashable.tupleunpacking vànamedtuple/dataclasscho structured data.
Immutability là gì? Tại sao nó quan trọng?
Định nghĩa: Một immutable object không thể thay đổi sau khi tạo ra. Trong Python: int, float, str, tuple, frozenset, bytes.
Tại sao quan trọng trong thực tế:
- Thread safety: Immutable object có thể share an toàn giữa các thread mà không cần lock.
- Hashability: Chỉ immutable object mới có thể dùng làm
dictkey hoặcsetelement (cần hash ổn định). - Predictability: Function nhận immutable object không thể vô tình modify data của caller.
- Performance: Python intern small integer và interned string — check
iscó thể O(1).
Gotcha hay gặp:
# Trông như mutation nhưng thực ra không phải
x = "hello"
x += " world" # tạo string mới, x trỏ đến object mới
id_before = id(x)
# vs list (mutation thật)
lst = [1, 2, 3]
lst.append(4) # cùng object trong memoryAsyncIO, MultiThreading và MultiProcessing khác nhau như thế nào? Khi nào dùng cái nào?
Đây là một trong những câu hỏi senior Python quan trọng nhất. Cần hiểu đúng mental model.
Distinction cốt lõi là loại work:
I/O-bound work → AsyncIO hoặc Threading
CPU-bound work → MultiprocessingAsyncIO
- Single thread, cooperative multitasking qua event loop
async/awaitcho phép viết non-blocking code trông như synchronous- Zero overhead từ thread context switching
- Best for: network call, database query, file I/O — bất cứ thứ gì bạn phải đợi
import asyncio
import httpx
async def fetch(url: str) -> str:
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.text
async def main():
results = await asyncio.gather(
fetch("https://api.example.com/a"),
fetch("https://api.example.com/b"),
fetch("https://api.example.com/c"),
)
print(results)
asyncio.run(main())MultiThreading
- Multiple thread, GIL giới hạn true parallelism cho CPU work
- Hữu ích cho I/O-bound work khi dùng blocking library (ví dụ:
requests,psycopg2) - Thread share memory — cần lock cho shared state
from concurrent.futures import ThreadPoolExecutor
import requests
def fetch(url: str) -> str:
return requests.get(url).text
with ThreadPoolExecutor(max_workers=10) as executor:
results = list(executor.map(fetch, urls))MultiProcessing
- Multiple OS process, mỗi cái có GIL riêng
- True CPU parallelism
- Memory overhead cao hơn, giao tiếp qua queue/pipe
- Best for: data processing, ML inference, CPU-heavy transformation
from concurrent.futures import ProcessPoolExecutor
def compute(n: int) -> int:
return sum(i * i for i in range(n))
with ProcessPoolExecutor(max_workers=4) as executor:
results = list(executor.map(compute, [10**6, 10**6, 10**6, 10**6]))Decision matrix
| Scenario | Dùng |
|---|---|
| FastAPI endpoint gọi external API | AsyncIO |
| Blocking library cũ (requests, psycopg2) | ThreadPoolExecutor |
| Image resizing, data transformation | ProcessPoolExecutor |
| ML model inference mỗi request | ProcessPool hoặc dedicated worker |
| Mix async và sync code | asyncio.run_in_executor() |
I/O bound vs CPU bound tasks?
I/O bound: Task dành phần lớn thời gian chờ external resource — network, disk, database. CPU gần như nhàn rỗi.
CPU bound: Task dành phần lớn thời gian tính toán — số học, parse, compress, chạy ML model. CPU full load.
Cách biết mình đang có loại nào:
import time
# Profile nó
start = time.perf_counter()
do_the_work()
elapsed = time.perf_counter() - start
# Cũng check CPU usage với htop hoặc psutil khi đang chạyTại sao quan trọng với Python cụ thể: GIL có nghĩa là threading sẽ không giúp ích gì cho CPU-bound work. Bạn phải dùng multiprocessing (hoặc viết C extension, dùng NumPy, v.v.) để có true CPU parallelism.
Cách Python quản lý memory? CPython có gì khác với các interpreter khác?
CPython memory management:
- Reference counting: Mỗi object theo dõi số lượng reference trỏ đến nó. Khi count về 0, memory được giải phóng ngay lập tức.
import sys
x = [1, 2, 3]
print(sys.getrefcount(x)) # 2 (x + argument của getrefcount)
y = x
print(sys.getrefcount(x)) # 3
del y
print(sys.getrefcount(x)) # 2-
Cyclic garbage collector: Reference counting một mình không xử lý được circular reference (
a → b → a). CPython chạy cycle-detecting GC định kỳ cho những trường hợp này. -
Memory allocator: CPython dùng allocator riêng (
pymalloc) cho object ≤ 512 bytes, bypass system allocator để tăng tốc. -
Object pool: Small integer (-5 đến 256) và interned string được cache — Python tái sử dụng object có sẵn thay vì tạo mới.
CPython vs các interpreter khác:
| Interpreter | GIL | Memory model | Use case |
|---|---|---|---|
| CPython | ✅ (đang bị bỏ từ 3.13+) | Reference counting + GC | Default, compatible nhất |
| PyPy | ✅ | Tracing JIT, GC khác | Python code cần tốc độ |
| Jython | ❌ | JVM GC | Java interop |
| GraalPy | ❌ | GraalVM GC | Môi trường polyglot |
| MicroPython | N/A | Manual/simplified | Embedded, IoT |
Key point cho senior interview: Python 3.13 giới thiệu experimental support chạy CPython không có GIL (free-threaded mode, PEP 703). Điều này thay đổi đáng kể câu chuyện về threading trong Python tương lai.
Hashable là gì? Tại sao cần hashable? Làm thế nào cho một object hashable?
Hashable: Một object là hashable nếu nó có method __hash__() trả về integer, và method __eq__() — và quan trọng là, những object bằng nhau phải có cùng hash.
Tại sao cần: dict key và set element phải hashable. Hash được dùng để xác định bucket trong hash table bên dưới — O(1) lookup phụ thuộc vào điều này.
Hashability của built-in types:
hash(42) # ✅ int
hash("hello") # ✅ str
hash((1, 2, 3)) # ✅ tuple (nếu tất cả element hashable)
hash([1, 2, 3]) # ❌ TypeError: unhashable type: 'list'
hash({1: 2}) # ❌ TypeError: unhashable type: 'dict'Làm cho custom class hashable:
class Point:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def __eq__(self, other: object) -> bool:
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
def __hash__(self) -> int:
return hash((self.x, self.y)) # tuple của các immutable field
p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2) # True
print(p1 is p2) # False
print({p1, p2}) # {Point(1, 2)} — deduplicate đúng cáchThe contract: Nếu bạn define __eq__, Python set __hash__ thành None mặc định (làm class không hashable). Bạn phải explicitly define __hash__ nếu muốn cả equality lẫn hashability.
Với dataclasses:
from dataclasses import dataclass
@dataclass(frozen=True) # frozen=True làm nó immutable VÀ hashable
class Point:
x: float
y: floatCách tương tác với relational database? Connection pool setup khi scale nhiều instance?
Tương tác cơ bản với SQLAlchemy (async):
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/db",
pool_size=10, # base pool size
max_overflow=20, # connection thêm ngoài pool_size
pool_timeout=30, # giây chờ để lấy connection
pool_recycle=1800, # recycle connection mỗi 30 phút (tránh stale)
)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_db():
async with AsyncSessionLocal() as session:
yield sessionConnection pool sizing — câu hỏi cốt lõi:
Khi bạn scale lên nhiều service instance, mỗi instance có connection pool riêng. Tổng connection đến database là:
total_connections = instances × pool_sizeNếu có 10 service instance × pool_size=10 = 100 connection tới Postgres.
PostgreSQL có giới hạn cứng max_connections (mặc định 100). Bạn sẽ chạm giới hạn rất nhanh.
Giải pháp: PgBouncer (connection pooler):
[Service Instances] → [PgBouncer] → [PostgreSQL]
10 × 10 = 100 pool: 20 max: 100- Mỗi service connect đến PgBouncer, không kết nối trực tiếp Postgres
- PgBouncer duy trì pool nhỏ đến Postgres và multiplex
- Dùng transaction pooling mode cho stateless backend (phổ biến nhất)
- Session pooling nếu bạn dựa vào session-level feature (temporary table, SET statement)
Cài đặt thực tế cho FastAPI + Postgres:
# Per-instance pool (khi dùng PgBouncer)
engine = create_async_engine(
DATABASE_URL,
pool_size=5, # nhỏ thôi — PgBouncer lo phần pooling thật
max_overflow=5,
pool_pre_ping=True, # validate connection trước khi dùng
)SQL query optimization? How & Why?
Mindset: Đừng đoán, hãy đo. Bắt đầu với EXPLAIN ANALYZE.
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
GROUP BY u.id, u.name
ORDER BY order_count DESC
LIMIT 20;Những thứ cần tìm trong query plan:
Seq Scantrên table lớn → thiếu indexHash JoinvsNested Loop— Hash Join tốt hơn cho table lớn- Row estimate cao → statistics cũ, chạy
ANALYZE Sortnode với row count lớn → xem xét index trên column ORDER BY
Các kỹ thuật optimization:
1. Index — giải pháp 80%:
-- Composite index cho pattern filter + sort thường gặp
CREATE INDEX idx_users_created_name ON users(created_at, name);
-- Partial index chỉ cho active record
CREATE INDEX idx_active_orders ON orders(user_id) WHERE status = 'active';
-- Covering index — query được phục vụ từ index, không cần heap fetch
CREATE INDEX idx_orders_covering ON orders(user_id, created_at, status);2. Tránh N+1 query:
# Bad: 1 query cho users + N query cho orders
users = session.execute(select(User)).scalars().all()
for user in users:
orders = session.execute(select(Order).where(Order.user_id == user.id)).all()
# Good: JOIN hoặc eager load
users = session.execute(
select(User).options(selectinload(User.orders))
).scalars().all()3. Dùng pagination đúng cách:
-- Bad: OFFSET 10000 LIMIT 20 (scan 10020 row)
SELECT * FROM orders ORDER BY created_at DESC OFFSET 10000 LIMIT 20;
-- Good: keyset pagination
SELECT * FROM orders
WHERE created_at < :last_seen_date
ORDER BY created_at DESC
LIMIT 20;4. Analyze slow query thường xuyên:
-- Tìm slow query trong Postgres
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;Database scale — Cluster và ProxySQL
Khi single Postgres instance không còn đáp ứng được, bạn scale horizontally.
Read replica (bước đầu phổ biến nhất):
Primary (writes) ──→ Replica 1 (reads)
──→ Replica 2 (reads)Application của bạn route: SELECT → replica, INSERT/UPDATE/DELETE → primary.
ProxySQL (phổ biến trong môi trường MySQL/MariaDB):
- Ngồi giữa app và database cluster
- Tự động route query dựa trên rule (read/write splitting)
- Connection pooling
- Query rewriting và caching
- Failover handling
App → ProxySQL → Primary (writes)
→ Replica 1 (reads)
→ Replica 2 (reads)Với Postgres, các tool tương đương là:
- PgBouncer: Connection pooling
- Patroni + HAProxy: High availability + read/write splitting
- Citus: Horizontal sharding cho Postgres
Khi nào nghĩ đến sharding:
Sharding (chia data qua nhiều database theo key) là phương án cuối cùng. Trước khi sharding:
- Thêm index (win miễn phí)
- Thêm read replica (scale reads)
- Vertical scale (máy mạnh hơn)
- Caching layer (Redis)
- Archive data cũ
Sharding thêm operational complexity đáng kể — tránh cho đến khi thực sự cần.
Làm thế nào để đảm bảo code quality tốt? SonarQube?
Code quality là một system, không phải một tool đơn lẻ. Đây là cách tiếp cận theo layer:
Layer 1 — Static analysis (bắt bug trước runtime):
# Type checking
mypy app/
# Linting (code style + common bug)
ruff check app/
# Security vulnerability
bandit -r app/Layer 2 — Testing:
# pytest với coverage
pytest --cov=app --cov-report=term-missing --cov-fail-under=80- Unit test cho pure function và business logic
- Integration test cho database interaction và API endpoint
- Đừng mock database nếu tránh được — dùng test database
Layer 3 — Code review culture:
- PR review không phải để bắt bug — mà để share knowledge
- Giữ PR nhỏ (< 400 dòng) để thực sự review được
- Reviewer kiểm tra: readability, edge case, security, performance implication
Layer 4 — SonarQube / SonarCloud:
SonarQube scan codebase để tìm:
- Bug: Code có khả năng fail lúc runtime
- Vulnerability: Security issue (SQL injection, hardcoded secret)
- Code smell: Vấn đề maintainability (code trùng lặp, function quá phức tạp)
- Coverage gate: Fail build nếu test coverage giảm dưới threshold
# Ví dụ CI gate trong GitHub Actions
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
with:
args: >
-Dsonar.python.coverage.reportPaths=coverage.xml
-Dsonar.qualitygate.wait=true # Fail CI nếu quality gate failNhận xét thực tế: SonarQube có giá trị nhất như safety net trong CI/CD, không phải là replacement cho engineering practice tốt. Fix vấn đề từ gốc (code review culture, pair programming, coding standard rõ ràng) — tool là multiplier, không phải substitute.
CI/CD là gì? Jenkins?
CI (Continuous Integration): Mỗi thay đổi code được tự động build, test và verify. Mục tiêu là phát hiện integration problem sớm — trước khi chúng tích lũy thành vấn đề lớn hơn.
CD (Continuous Delivery / Deployment): Mỗi build pass được tự động sẵn sàng deploy (Delivery) hoặc thực sự deploy (Deployment) lên môi trường.
Code push → CI pipeline → CD pipeline → Production
↓ ↓
Tests pass Deploy to staging → Deploy to prodMột CI pipeline điển hình cho Python service:
# .github/workflows/ci.yml
jobs:
test:
steps:
- name: Install dependencies
run: pip install -e ".[dev]"
- name: Type check
run: mypy app/
- name: Lint
run: ruff check app/
- name: Test with coverage
run: pytest --cov=app --cov-fail-under=80
- name: Security scan
run: bandit -r app/
- name: SonarCloud
uses: SonarSource/sonarcloud-github-action@masterJenkins vs GitHub Actions vs GitLab CI:
| Tool | Hosting | Best for |
|---|---|---|
| Jenkins | Self-hosted | Full control, complex pipeline, on-prem |
| GitHub Actions | Cloud (GitHub) | OSS project, GitHub repo, setup đơn giản |
| GitLab CI | Cloud hoặc self-hosted | GitLab repo, container registry tích hợp |
Về Jenkins cụ thể: Jenkins dùng Jenkinsfile (Groovy DSL) và chạy trên infrastructure của bạn. Phổ biến ở enterprise với Jenkins setup sẵn hoặc môi trường air-gapped. Xu hướng với project mới là chuyển sang cloud-native CI thay vì Jenkins.
Bạn deploy lên staging/production như thế nào?
Deployment process phụ thuộc vào infrastructure, nhưng đây là flow điển hình cho Python service:
Container-based deployment (phổ biến nhất):
1. CI build Docker image
2. Image push lên registry (ECR, Docker Hub, GCR)
3. CD pull image mới và deployVí dụ với GitHub Actions + Docker:
- name: Build and push Docker image
run: |
docker build -t myapp:${{ github.sha }} .
docker push registry.example.com/myapp:${{ github.sha }}
- name: Deploy to staging
run: |
ssh deploy@staging "docker pull registry.example.com/myapp:${{ github.sha }} && \
docker-compose up -d --no-deps app"Các zero-downtime deployment strategy:
- Rolling update: Thay thế instance từng cái một — không downtime, dễ rollback
- Blue/green: Chạy hai môi trường giống hệt nhau, switch traffic — rollback tức thì
- Canary: Route một % nhỏ traffic đến version mới trước, monitor, rồi mới roll out toàn bộ
Với Kubernetes:
# k8s deployment với rolling update
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0Sự khác biệt staging vs production:
- Staging dùng data gần giống production (đã anonymize) và infrastructure giống hệt
- Feature flag cho phép deploy code lên production nhưng activate feature dần dần
- Luôn deploy lên staging trước, chạy smoke test, rồi mới promote lên production
Docker vs Kubernetes? Cloud vs On-Premises?
Docker vs Kubernetes — không phải alternative, chúng hoạt động cùng nhau:
| Docker | Kubernetes | |
|---|---|---|
| Làm gì | Package và chạy container | Orchestrate container ở scale lớn |
| Đơn vị | Container | Pod (1+ container) |
| Phạm vi | Một máy | Cluster nhiều máy |
| Dùng khi | Local dev, deploy server đơn | Multi-node, auto-scaling, cần HA |
Docker: [App] → [Container] → chạy trên một máy
Kubernetes: [App] → [Container] → [Pod] → [Node] → [Cluster]
↑ auto-scheduled, auto-healedVới Python backend service:
- Local dev:
docker compose up— spin up app + postgres + redis cùng nhau - Production nhỏ (< 5 service, 1-2 server):
docker composetrên VPS - Production lớn hơn (nhiều service, cần auto-scaling): Kubernetes (EKS, GKE, AKS)
Cloud vs On-Premises:
| Cloud | On-Premises | |
|---|---|---|
| Cost model | Pay-as-you-go (OpEx) | Phần cứng trả trước (CapEx) |
| Scaling | Elastic, tính bằng phút | Tính bằng tuần (chu kỳ mua sắm) |
| Maintenance | Provider lo | Team của bạn chịu trách nhiệm |
| Data control | Data center của provider | Data center của bạn |
| Compliance | Phụ thuộc region/certification | Toàn quyền kiểm soát |
Khi nào chọn on-premises:
- Yêu cầu data sovereignty nghiêm ngặt (chính phủ, ngân hàng, y tế)
- Đã có đầu tư infrastructure sẵn
- Workload ổn định, dự đoán được — cloud sẽ đắt hơn
Khi nào chọn cloud:
- Traffic biến động (chỉ trả cho những gì dùng)
- Time-to-market quan trọng
- Team ops nhỏ (không có infra specialist)
Hybrid rất phổ biến ở thị trường enterprise Việt Nam — data nhạy cảm ở on-prem, application layer trên cloud.
Background tasks — Cron vs Systemd vs Supervisor?
Background task là những job chạy ngoài request/response cycle. Cách bạn quản lý chúng ảnh hưởng trực tiếp đến reliability.
Ba tool này phục vụ mục đích khác nhau:
Cron — scheduled job vào giờ cố định:
# crontab -e
# Chạy cleanup mỗi ngày lúc 2 giờ sáng
0 2 * * * /usr/bin/python3 /app/scripts/cleanup.py >> /var/log/cleanup.log 2>&1
# Chạy mỗi 5 phút
*/5 * * * * /app/scripts/health_check.py- Best for: periodic task (report, cleanup, data sync)
- Điểm yếu: không retry khi fail, không tránh overlap, log cơ bản
Systemd — long-running service được OS quản lý:
# /etc/systemd/system/myapp-worker.service
[Unit]
Description=MyApp Background Worker
After=network.target
[Service]
User=appuser
WorkingDirectory=/app
ExecStart=/app/.venv/bin/python -m app.worker
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetsystemctl enable myapp-worker
systemctl start myapp-worker
systemctl status myapp-worker- Best for: worker phải chạy liên tục (queue consumer, WebSocket server)
- Tự restart, tích hợp với system boot, log qua
journalctl
Supervisor — process manager, phổ biến trong Python deployment:
# /etc/supervisor/conf.d/myapp.conf
[program:myapp-worker]
command=/app/.venv/bin/python -m app.worker
directory=/app
user=appuser
autostart=true
autorestart=true
stderr_logfile=/var/log/myapp-worker.err.log
stdout_logfile=/var/log/myapp-worker.out.log
numprocs=4 ; chạy 4 worker process
process_name=%(program_name)s_%(process_num)02d- Best for: chạy nhiều worker process, Python deployment cũ
- Tương tự systemd nhưng thân thiện hơn với Python ecosystem, config multi-process dễ hơn
Trong modern stack (Kubernetes / Docker):
- Cron job → Kubernetes CronJob hoặc cloud scheduler (AWS EventBridge, GCP Cloud Scheduler)
- Long-running worker → Kubernetes Deployment với
restartPolicy: Always - Task queue → Celery + Redis/RabbitMQ, hoặc cloud-native (AWS SQS, GCP Pub/Sub)
Bảng quyết định:
| Nhu cầu | Tool |
|---|---|
| Chạy script lúc 3 giờ sáng mỗi ngày | Cron |
| Giữ process chạy 24/7 trên Linux server | Systemd |
| Chạy 4 Python worker process, dễ restart | Supervisor |
| Scheduled job trong Kubernetes | K8s CronJob |
| Queue-based async task (retry, priority) | Celery + Redis |
Chuẩn bị cho phỏng vấn Python senior như thế nào?
Những câu hỏi này tiết lộ những gì một senior role thực sự yêu cầu:
- Hiểu sâu về Python internals — không chỉ biết dùng ngôn ngữ, mà tại sao nó hoạt động như vậy (GIL, memory model, hashability)
- Systems thinking — biết khi nào dùng async vs thread vs process, và quyết định đó thay đổi như thế nào khi scale lên
- Database fluency — query optimization, connection management, scaling strategy
- Engineering discipline — code quality như một system (testing + static analysis + review culture)
- DevOps awareness — CI/CD pipeline, container deployment, infrastructure trade-off
Interviewer không tìm kiếm câu trả lời thuộc lòng. Họ tìm ứng viên có thể reason qua trade-off và giải thích tại sao — không chỉ là gì.
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.