Thư Viện Câu Hỏi Phỏng Vấn

Tổng hợp các câu hỏi tuyển dụng thực tế theo nhiều cấp độ từ Entry đến Expert để bạn tự tin chinh phục nhà tuyển dụng.

01

Làm thế nào để thiết kế một hệ thống RESTful API hỗ trợ phiên bản (API Versioning) hiệu quả và tương thích ngược tốt?

Senior

Có 3 cách tiếp cận phổ biến để thiết kế API Versioning:

  1. URI Versioning: Ví dụ: /api/v1/users. Trực quan, dễ cấu hình định tuyến và cache tại CDN. Tuy nhiên làm thay đổi toàn bộ URI khi nâng cấp.
  2. Header Versioning (Custom Header): Ví dụ: X-API-Version: 1. URI được giữ nguyên, thông tin phiên bản truyền qua request header. Thích hợp cho thiết kế REST tinh khiết nhưng khó test trực tiếp qua trình duyệt.
  3. Content Negotiation (Accept Header): Ví dụ: Accept: application/vnd.myapi.v1+json. Kiểm soát phiên bản ở mức độ chi tiết nhất dựa trên tài nguyên trả về.
    • Best Practices: Luôn đảm bảo khả năng tương thích ngược (Backward Compatibility) bằng cách không xóa hoặc thay đổi kiểu dữ liệu của các trường cũ. Nếu bắt buộc thay đổi lớn (Breaking Change), hãy chuyển sang version mới và duy trì song song phiên bản cũ (Graceful Deprecation) trong một khoảng thời gian báo trước.
02

Giải thích cơ chế hoạt động của Sharding (Phân mảnh dữ liệu) và sự khác biệt so với Partitioning thông thường?

Senior

Cả hai đều dùng để phân tách các bảng dữ liệu quá lớn thành các phần nhỏ hơn để tăng hiệu năng truy vấn, nhưng phạm vi hoạt động khác nhau:

  • Partitioning (Phân vùng): Chia một bảng lớn thành nhiều phần nhỏ dựa trên các tiêu chí (Range, List, Hash) nhưng tất cả các phần này vẫn nằm trên cùng một cơ sở dữ liệu và cùng một server vật lý. Nó giúp tối ưu hóa việc quét dữ liệu nhờ loại bỏ các phân vùng không liên quan (Partition Pruning).
  • Sharding (Phân mảnh): Chia dữ liệu của một bảng lớn và lưu trữ chúng trên nhiều server vật lý độc lập (Database Nodes) khác nhau. Mỗi node được gọi là một shard.
  • Sự khác biệt: Sharding cho phép mở rộng hệ thống theo chiều ngang (Scale Out), vượt qua giới hạn lưu trữ và CPU của một server đơn lẻ. Tuy nhiên, Sharding làm tăng độ phức tạp khi thực hiện truy vấn kết hợp nhiều bảng (Cross-shard joins) và quản lý tính nhất quán của dữ liệu.
03

ACID là gì? Giải thích chi tiết cơ chế hoạt động của WAL (Write-Ahead Logging) giúp đảm bảo tính bền vững (Durability) trong các hệ quản trị CSDL?

Senior
  • ACID: Là 4 thuộc tính đảm bảo tính tin cậy của giao dịch CSDL: Atomicity (Tính nguyên tố), Consistency (Tính nhất quán), Isolation (Tính cô lập), Durability (Tính bền vững).
  • Write-Ahead Logging (WAL): Là kỹ thuật ghi log trước khi ghi đè dữ liệu thực tế xuống đĩa cứng.
  • Cơ chế hoạt động:
    1. Khi có yêu cầu thay đổi dữ liệu, thay vì ghi trực tiếp vào các file dữ liệu trên đĩa (rất chậm vì ghi ngẫu nhiên - random I/O), CSDL sẽ ghi các thay đổi này dưới dạng tuần tự vào file Log (WAL log) trên đĩa cứng (rất nhanh vì ghi tuần tự - sequential I/O).
    2. Sau khi WAL log được ghi thành công xuống đĩa cứng (flushed), giao dịch được coi là đã commit thành công và phản hồi cho client.
    3. Dữ liệu thực tế trên bộ nhớ RAM sẽ được ghi xuống đĩa cứng sau một khoảng thời gian (quá trình Checkpoint).
    4. Nếu hệ thống đột ngột mất điện, CSDL sẽ đọc lại file WAL log để khôi phục (Redo) các giao dịch đã commit nhưng chưa kịp ghi xuống đĩa, đảm bảo tính bền vững tuyệt đối.
  • 04

    Làm thế nào để tối ưu hóa kích thước Docker Image (Docker Image Size Optimization) khi viết Dockerfile cho ứng dụng chạy production?

    Senior

    Tối ưu kích thước Docker Image giúp tăng tốc độ build, push/pull image và tiết kiệm bộ nhớ cho hạ tầng. Các best practices bao gồm:

    1. Sử dụng Multi-stage Builds: Chia Dockerfile thành nhiều giai đoạn build độc lập. Chỉ sao chép các artifacts đã compile hoặc dependencies cần thiết từ stage build sang stage chạy production cuối cùng, bỏ lại toàn bộ SDK và source code gốc.
    2. Chọn Base Image nhỏ gọn: Thay vì dùng ubuntu hay node:latest, hãy sử dụng các phiên bản tối giản như Alpine Linux (node:alpine) hoặc Distroless Images.
    3. Hạn chế số lượng Layer: Mỗi câu lệnh RUN, COPY, ADD sẽ tạo ra một layer mới. Gộp các lệnh RUN apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/* thành một câu lệnh duy nhất để tránh lưu trữ các file tạm thừa trong các layer trung gian.
    4. Sử dụng file .dockerignore: Loại bỏ các thư mục phát triển như node_modules, .git, tests để không bị copy vô ích vào build context.
    05

    Mẫu thiết kế Saga (Saga Pattern) giải quyết bài toán giao dịch phân tán (Distributed Transactions) trong kiến trúc Microservices như thế nào?

    Senior

    Trong kiến trúc Microservices, mỗi service quản lý cơ sở dữ liệu riêng, nên ta không thể dùng giao dịch ACID của một CSDL đơn lẻ. Saga Pattern giải quyết vấn đề này bằng cách chia giao dịch lớn thành một chuỗi các giao dịch cục bộ (Local Transactions):

    1. Cơ chế hoạt động: Mỗi service thực hiện giao dịch cục bộ của mình và phát ra một sự kiện (Event). Service tiếp theo lắng nghe sự kiện đó và thực hiện giao dịch cục bộ của mình. Quá trình tiếp diễn cho đến khi hoàn thành.
    2. Giao dịch bù (Compensating Transactions): Nếu một bước trong chuỗi gặp lỗi (ví dụ: Thanh toán thất bại), Saga sẽ kích hoạt các giao dịch bù theo thứ tự ngược lại để hoàn tác (rollback) các thay đổi đã được thực hiện ở các bước trước (ví dụ: Hoàn trả lại số lượng hàng đã giữ trong kho).
    3. Cách thức triển khai:
      • Choreography (Phối hợp phi tập trung): Các services tự lắng nghe và phát sự kiện lẫn nhau thông qua Message Broker.
      • Orchestration (Phối hợp tập trung): Sử dụng một service điều phối trung tâm (Saga Orchestrator) để ra lệnh trực tiếp cho từng service thực thi.
    06

    Phân biệt sự khác nhau giữa StatefulSet và Deployment trong Kubernetes? Khi nào bắt buộc phải dùng StatefulSet?

    Senior

    Cả hai đều dùng để quản lý Pods trong Kubernetes nhưng hướng tới các loại ứng dụng khác nhau:

    • Deployment: Dành cho các ứng dụng không trạng thái (Stateless), ví dụ: Web API, Frontend. Các Pods là vô danh, có thể thay thế cho nhau. Khi scale, Pod mới được tạo ra với tên ngẫu nhiên và không giữ lại trạng thái hay dữ liệu của Pod cũ.
    • StatefulSet: Dành cho các ứng dụng có trạng thái (Stateful), ví dụ: Database (MySQL, PostgreSQL), Message Queue (Kafka). Các Pods có mã định danh duy nhất, cố định (ví dụ: pod-0, pod-1) và được khởi tạo theo thứ tự nghiêm ngặt.
    • Tính liên kết bộ nhớ: Mỗi Pod trong StatefulSet được liên kết chặt chẽ với một PersistentVolume (PV) riêng biệt. Khi một Pod bị crash và được tạo lại, K8s sẽ gắn đúng Persistent Volume cũ của Pod đó vào để đảm bảo dữ liệu không bị mất mát.
    07

    So sánh cơ chế hoạt động và tính bảo mật giữa Mã hóa đối xứng (Symmetric Encryption) và Mã hóa bất đối xứng (Asymmetric Encryption)?

    Senior
  • Mã hóa đối xứng: Sử dụng cùng một khóa duy nhất cho cả quá trình mã hóa và giải mã dữ liệu. Ví dụ: AES, DES. Tốc độ xử lý rất nhanh, thích hợp cho việc mã hóa lượng dữ liệu lớn. Tuy nhiên, thách thức lớn là việc phân phối và trao đổi khóa an toàn giữa các bên.
  • Mã hóa bất đối xứng: Sử dụng một cặp khóa gồm Khóa công khai (Public Key) và Khóa bí mật (Private Key). Dữ liệu được mã hóa bằng Public Key chỉ có thể giải mã bằng Private Key tương ứng và ngược lại. Ví dụ: RSA, ECC. Tính bảo mật cực cao vì Private Key không bao giờ cần phải gửi qua mạng. Tuy nhiên, tốc độ xử lý chậm hơn nhiều so với mã hóa đối xứng.
  • Ứng dụng thực tế (Hybrid Encryption): Giao thức HTTPS sử dụng mã hóa bất đối xứng để thiết lập kết nối ban đầu và trao đổi an toàn một "Khóa đối xứng tạm thời" (Session Key). Sau đó, toàn bộ dữ liệu truyền tải tiếp theo sẽ được mã hóa bằng Session Key này để tối ưu tốc độ.
  • 08

    Clean Architecture (Kiến trúc sạch) hoạt động theo nguyên lý nào và làm thế nào để đảm bảo Dependency Rule (Luật phụ thuộc)?

    Senior

    Clean Architecture do Robert C. Martin giới thiệu, chia hệ thống thành các vòng tròn đồng tâm với mục tiêu tách biệt mã nguồn nghiệp vụ khỏi các công cụ kỹ thuật (như Database, Web Framework, UI):

    1. Các tầng cốt lõi: Entities (Nghiệp vụ cốt lõi) -> Use Cases (Luồng nghiệp vụ ứng dụng) -> Interface Adapters (Controllers, Presenters) -> Frameworks & Drivers (Database, Web).
    2. Luật phụ thuộc (Dependency Rule): Mã nguồn ở vòng tròn bên trong không được phép biết hoặc chứa bất kỳ tham chiếu nào tới mã nguồn ở vòng tròn bên ngoài. Mọi sự phụ thuộc phải luôn hướng từ ngoài vào trong.
    3. Cách đảm bảo: Sử dụng kỹ thuật Dependency Inversion (DIP). Ví dụ, Use Case cần lưu dữ liệu sẽ không gọi trực tiếp class Database ở ngoài. Thay vào đó, nó định nghĩa một Interface (Port/Gateway) ở trong. Class Database ở ngoài sẽ implement interface đó. Khi chạy, IoC Container sẽ tiêm thực thể database vào Use Case.
    09

    Hiện tượng Cache Stampede (hoặc Cache Avalanche) là gì? Làm thế nào để phòng chống hiện tượng này trong các hệ thống chịu tải cao?

    Senior
  • Cache Stampede (Tháo chạy bộ nhớ đệm): Xảy ra khi một key cache cực kỳ phổ biến (hot key) đột ngột hết hạn (expire) dưới tải cao. Tại thời điểm đó, hàng nghìn request đồng thời cùng đọc cache, thấy rỗng, và cùng lúc truy cập trực tiếp vào CSDL để lấy dữ liệu ghi lại vào cache, khiến CSDL bị quá tải và sập.
  • Cách phòng chống Cache Stampede:
    1. Mutex Lock (Single Flight): Chỉ cho phép request đầu tiên truy cập CSDL để lấy dữ liệu mới và khóa các request khác lại bắt chúng chờ cho đến khi dữ liệu mới được cập nhật vào cache.
    2. Chạy Background Worker: Tự động cập nhật (refresh) dữ liệu trong cache bằng tác vụ ngầm trước khi key đó hết hạn thực tế.
    3. Xác suất tính toán sớm (Probabilistic Early Expiration): Cho phép một tỷ lệ nhỏ request tính toán lại giá trị cache trước khi key hết hạn.
  • 10

    Khái niệm Bounded Context trong Domain-Driven Design (DDD) là gì và tại sao nó là ranh giới quan trọng khi chia nhỏ Monolith thành Microservices?

    Senior
  • Bounded Context: Là ranh giới logic trong đó một mô hình domain cụ thể, ngôn ngữ thống nhất (Ubiquitous Language) và các thực thể chỉ có ý nghĩa và giá trị nhất quán. Bên ngoài ranh giới đó, cùng một từ ngữ hoặc thực thể có thể mang một ý nghĩa hoàn toàn khác.
  • Ví dụ: Thực thể Product trong Context "Bán hàng" (Sales) sẽ chứa thông tin về giá, khuyến mãi. Nhưng trong Context "Vận chuyển" (Shipping), Product lại chỉ quan tâm tới kích thước, cân nặng.
  • Tầm quan trọng khi chia Microservices: Việc ánh xạ trực tiếp mỗi Bounded Context thành một Microservice độc lập giúp tránh việc chia nhỏ hệ thống sai cách. Nó giúp giữ cho cơ sở dữ liệu và mã nguồn của mỗi service được cô lập, giảm thiểu sự phụ thuộc chéo (Coupling) giữa các nhóm phát triển và đảm bảo tính nhất quán dữ liệu nội bộ.
  • 11

    Định lý CAP là gì? Tại sao một hệ thống phân tán không thể đạt được đồng thời cả 3 yếu tố Consistency, Availability, và Partition Tolerance?

    Senior

    Định lý CAP chỉ ra rằng một hệ thống lưu trữ dữ liệu phân tán chỉ có thể chọn tối đa 2 trong số 3 yếu tố sau:

    1. Consistency (Tính nhất quán): Mọi node đều đọc được dữ liệu mới nhất cùng lúc.
    2. Availability (Tính sẵn sàng): Mọi request gửi đến hệ thống đều nhận được phản hồi thành công (không bị lỗi hoặc timeout) dù có node bị sập.
    3. Partition Tolerance (Tính chịu lỗi phân đoạn): Hệ thống vẫn hoạt động bình thường dù kết nối mạng giữa các node bị đứt quãng.
      • Tại sao không thể chọn cả 3: Trên môi trường mạng thực tế, lỗi đường truyền là không thể tránh khỏi (bắt buộc phải có P). Khi xảy ra đứt kết nối giữa Node A và Node B:
      • Nếu chọn C (Consistency): Để dữ liệu đồng bộ, Node A không được phép ghi dữ liệu mới khi chưa đồng bộ được sang Node B. Request ghi vào Node A sẽ bị từ chối hoặc treo -> Mất tính sẵn sàng (A).
      • Nếu chọn A (Availability): Node A vẫn nhận ghi dữ liệu để đảm bảo hệ thống luôn sẵn sàng phản hồi. Nhưng lúc này dữ liệu trên Node B bị cũ lệch -> Mất tính nhất quán (C).
    12

    Sự khác biệt giữa Load Balancer hoạt động ở Layer 4 (Transport Layer) và Layer 7 (Application Layer) is gì?

    Senior
  • L4 Load Balancer (Layer 4): Hoạt động ở tầng Giao vận (Transport Layer - TCP/UDP). Nó đưa ra quyết định điều phối lưu lượng chỉ dựa trên thông tin gói tin mạng cơ bản như IP nguồn, IP đích và Cổng (Port) mà không đọc nội dung bên trong gói tin. Tốc độ xử lý cực nhanh, tốn ít CPU vì không phải thực hiện giải mã SSL/TLS hay phân tích HTTP.
  • L7 Load Balancer (Layer 7): Hoạt động ở tầng Ứng dụng (Application Layer - HTTP/HTTPS). Nó có khả năng đọc và hiểu nội dung của request HTTP/HTTPS (như URI path, HTTP headers, Cookies, query parameters). Thích hợp cho việc điều hướng thông minh (ví dụ: gửi request /api/v1/users về service A, request /static/* về CDN/service B), hỗ trợ Sticky Sessions bằng Cookie và giải mã SSL (SSL Termination) trực tiếp.
  • 13

    So sánh sự khác nhau về trường hợp sử dụng (Use Cases) của các loại cơ sở dữ liệu NoSQL: Document, Key-Value, Column-family, và Graph Databases?

    Senior

    Mỗi loại CSDL NoSQL được tối ưu hóa cho các cấu trúc dữ liệu và mô hình truy cập khác nhau:

    1. Document Databases (như MongoDB, CouchDB): Lưu trữ dữ liệu dưới dạng JSON/BSON. Thích hợp cho các ứng dụng có cấu trúc dữ liệu linh hoạt, thường xuyên thay đổi (ví dụ: Thông tin sản phẩm thương mại điện tử, hệ thống quản lý nội dung CMS, User Profiles).
    2. Key-Value Stores (như Redis, Memcached): Lưu dữ liệu dạng cặp Khóa - Giá trị đơn giản. Tốc độ đọc/ghi cực nhanh (vài mili giây). Thích hợp cho việc Caching, quản lý Session, đếm số lượt xem (counters), làm hàng đợi tin nhắn (Message Queues).
    3. Column-family Stores (như Cassandra, ScyllaDB): Lưu dữ liệu theo cột thay vì theo dòng. Khả năng ghi cực kỳ tối ưu và scale tuyến tính trên hàng trăm server. Thích hợp cho lưu trữ dữ liệu chuỗi thời gian (Time-series), Log hệ thống khổng lồ, dữ liệu IoT từ các cảm biến.
    4. Graph Databases (như Neo4j): Lưu dữ liệu dưới dạng các Đỉnh (Nodes) và Cạnh (Edges - thể hiện mối quan hệ). Tối ưu cho các truy vấn quan hệ nhiều tầng phức tạp. Thích hợp cho Mạng xã hội (Social Networks), Hệ thống gợi ý (Recommendation Engines), Phát hiện gian lận tài chính (Fraud Detection).
    14

    Lỗ hổng Race Condition là gì? Phân biệt cơ chế khóa lạc quan (Optimistic Locking) và khóa bi quan (Pessimistic Locking) khi xử lý bất đồng bộ?

    Senior

    Race Condition xảy ra khi nhiều tiến trình/luồng đồng thời đọc và ghi vào một tài nguyên dùng chung mà không được đồng bộ hóa, dẫn đến kết quả cuối cùng phụ thuộc vào thứ tự thực thi ngẫu nhiên của các luồng.

    • Pessimistic Locking (Khóa bi quan): Giả định xung đột luôn xảy ra. Khi một luồng đọc dữ liệu, nó sẽ khóa ngay bản ghi đó lại (ví dụ: SELECT ... FOR UPDATE trong SQL). Các luồng khác muốn đọc/ghi bản ghi đó bắt buộc phải xếp hàng chờ cho đến khi khóa được giải phóng.
      • Ưu điểm: Đảm bảo tính nhất quán tuyệt đối, tránh hoàn toàn xung đột.
      • Nhược điểm: Dễ gây nghẽn hệ thống (lock contention), giảm hiệu năng và có nguy cơ xảy ra Deadlock.
    • Optimistic Locking (Khóa lạc quan): Giả định xung đột rất hiếm khi xảy ra. Khi đọc dữ liệu, không có khóa nào được thiết lập. Nhưng bản ghi sẽ lưu thêm một trường version hoặc timestamp. Khi ghi đè thay đổi, hệ thống kiểm tra xem version trong DB có còn giống lúc đọc hay không (UPDATE users SET balance = 50, version = version + 1 WHERE id = 1 AND version = 2). Nếu version đã thay đổi do luồng khác ghi trước đó, giao dịch sẽ bị từ chối và luồng hiện tại phải thử lại (retry).
      • Ưu điểm: Hiệu năng cực cao khi ít xung đột.
      • Nhược điểm: Tốn tài nguyên CPU để retry nếu tần suất xung đột lớn.
    15

    Service Mesh (như Istio, Linkerd) là gì? Tại sao nó giải quyết tốt các bài toán về Service-to-Service Communication trong Kubernetes?

    Senior

    Service Mesh là một tầng cơ sở hạ tầng chuyên dụng, độc lập được thêm vào hệ thống để quản lý việc giao tiếp an toàn, tin cậy và nhanh chóng giữa các microservices.

    • Cơ chế hoạt động (Sidecar Pattern): Service Mesh triển khai một proxy siêu nhẹ (như Envoy) chạy song song bên cạnh mỗi container ứng dụng (gọi là Sidecar Proxy). Mọi lưu lượng mạng đi vào và đi ra khỏi service đều được định tuyến qua sidecar này mà ứng dụng không hề hay biết.
    • Các bài toán giải quyết được:
      1. Traffic Management: Cấu hình định tuyến thông minh, Canary Deployments, A/B Testing, tự động Retry khi lỗi, Circuit Breaking.
      2. Security: Tự động mã hóa toàn bộ dữ liệu truyền tải giữa các services bằng giao thức mTLS (mutual TLS) và quản lý chứng chỉ số mà không cần sửa đổi mã nguồn ứng dụng.
      3. Observability: Thu thập số liệu chi tiết (Metrics, Distributed Tracing, Logs) về hiệu năng mạng, tỷ lệ lỗi giữa các cuộc gọi dịch vụ một cách tập trung.

    vừa nâng cấp PRO khóa 1 phút trước   Tìm hiểu khóa học