AWS S3 là cái quái gì?

- Published on
- /6 mins read/
Tiếp nối chuỗi bài viết chia sẻ về kỹ năng Backend và System Design, hôm nay chúng ta sẽ cùng "mổ xẻ" một trong những dịch vụ xương sống và phổ biến nhất của hệ sinh thái đám mây: Amazon S3 (Simple Storage Service).
# hệ sinh thái aws
Amazon Web Services (AWS) là một nền tảng Cloud khổng lồ với hơn 200+ dịch vụ. Khi xây dựng kiến trúc Microservices, đây là những "gương mặt thân quen" mà ta thường xuyên làm việc nhất:
- Compute: EC2 (máy ảo), ECS/EKS (run Docker/K8s container), Lambda (run code không cần server).
- Database & Cache: RDS (MySQL, PostgreSQL...), ElastiCache (Redis/Memcached).
- Messaging: SQS (Message Queue), SNS (Pub/Sub Notifications).
- Network & Routing: VPC (mạng riêng ảo), ALB/NLB (cân bằng tải), Route 53 (DNS).
- Storage: Và tất nhiên, ngôi sao của bài viết hôm nay - S3 (lưu trữ đối tượng).
# bản chất của s3
Rất nhiều anh em mới làm quen thường nhầm lẫn S3 với một ổ cứng thông thường (File System). Thực tế, S3 là Object Storage (lưu trữ đối tượng).
Nó không có hệ thống thư mục phân cấp thật sự. Tất cả các file (được gọi là objects) đều được ném vào chung một cái "xô" (Bucket). Để tạo cảm giác có thư mục, S3 dùng các chuỗi đường dẫn dài gọi là Key.
S3 được thiết kế với độ bền dữ liệu (Durability) cực khủng: 99.999999999% (11 số 9).
Các khái niệm "nằm lòng"
- Bucket: Thùng chứa dữ liệu. Lưu ý: Tên
Bucketphải là duy nhất(globally unique). - Object:
Filecộng vớiMetadatađi kèm (kích thước tối đa lên đến 5TB/file). - Key: Chuỗi định danh duy nhất của object. Ví dụ:
users/avatars/user-123.jpg(Toàn bộ chuỗi này chính làKey). - Metadata: Các cặp
Key-Valuelưu thông tin về file (VD: Content-Type).
# storage classes: chiến lược lưu trữ tối ưu chi phí
Không phải dữ liệu nào cũng cần truy cập nhanh. Phân loại đúng dữ liệu giúp dự án tiết kiệm cả đống tiền cho công ty:
- Standard: Dữ liệu truy cập thường xuyên
(Hot data). Đắt nhất nhưng nhanh nhất. - Standard-IA (Infrequent Access): Dữ liệu ít truy cập (ví dụ: file đã tải lên quá 30 ngày) nhưng khi gọi là phải có ngay. Rẻ hơn
Standard. - One Zone-IA: Dữ liệu có thể tạo lại được (như thumbnail ảnh). Lưu ở 1 Zone duy nhất nên rẻ hơn nữa.
- Glacier (Instant / Flexible / Deep Archive): Dùng để "cất kho" (Archive) các file log, report cũ. Cực rẻ, nhưng để lấy lại dữ liệu có thể mất từ vài phút đến vài chục tiếng.
- Intelligent-Tiering: Không rành cách phân loại? Cứ bật tính năng này, AI của AWS sẽ tự động phân tích và luân chuyển dữ liệu sang tier tối ưu chi phí nhất.
👉 Mẹo: Kết hợp với Lifecycle Policies để tự động dọn rác. Ví dụ: Viết rule tự động chuyển file /documents sang Standard-IA sau 30 ngày, cho vào Glacier sau 90 ngày và tự động xóa luôn sau 1 năm.
# presigned urls
Thay vì luồng truyền thống: Client -> Backend -> S3 (làm Backend phải gánh băng thông và chịu tải nặng), hãy dùng Presigned URL.
Cơ chế hoạt động (Bypass Backend):
- Client gọi Backend: "Cho mình xin quyền upload file avatar.png".
- Backend gọi S3: "Tạo cho tôi một cái link tạm có quyền PUT, sống trong 15 phút".
- Backend ném cái link đó về cho Client.
- Client dùng link đó đẩy thẳng file lên S3 (Backend lúc này thảnh thơi nhâm nhi cafe).
- Upload xong, Client báo lại Backend để lưu tên file vào Database.
# demo với spring boot
Dưới đây là template code chuẩn chỉ để anh em tích hợp ngay vào dự án:
# khai báo thư viện
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
</dependency># cấu hình s3 client
@Configuration("s3Config")
public class S3Config {
@Bean("s3Client")
public S3Client s3Client(@Value("${aws.region}") String region) {
return S3Client.builder()
.region(Region.of(region))
// Lấy credentials tự động từ biến môi trường hoặc IAM Role
.credentialsProvider(DefaultCredentialsProvider.create())
.build();
}
@Bean("s3Presigner")
public S3Presigner s3Presigner(@Value("${aws.region}") String region) {
return S3Presigner.builder()
.region(Region.of(region))
.credentialsProvider(DefaultCredentialsProvider.create())
.build();
}
}# s3 service core
@Service
@Slf4j
@RequiredArgsConstructor
public class S3StorageService {
private final S3Client s3Client;
private final S3Presigner presigner;
@Value("${aws.s3.bucket}")
private String bucket;
// Upload file cơ bản
public void upload(String key, byte[] content, String contentType) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucket).key(key).contentType(contentType).build();
s3Client.putObject(request, RequestBody.fromBytes(content));
log.info("Uploaded thành công | bucket={} | key={}", bucket, key);
}
// Lấy Download Presigned URL cho Client
public String generateDownloadUrl(String key, Duration expiration) {
GetObjectRequest getReq = GetObjectRequest.builder()
.bucket(bucket).key(key).build();
GetObjectPresignRequest presignReq = GetObjectPresignRequest.builder()
.signatureDuration(expiration)
.getObjectRequest(getReq).build();
return presigner.presignGetObject(presignReq).url().toString();
}
// Multipart upload (Cho file lớn > 100MB)
public void uploadLargeFile(String key, Path filePath) {
S3TransferManager transferManager = S3TransferManager.builder()
.s3Client(S3AsyncClient.builder().region(Region.AP_SOUTHEAST_1).build())
.build();
FileUpload upload = transferManager.uploadFile(UploadFileRequest.builder()
.putObjectRequest(PutObjectRequest.builder().bucket(bucket).key(key).build())
.source(filePath).build());
upload.completionFuture().join(); // Chờ hoàn tất
}
}# bảo mật và phân quyền - iam & bucket policy
Đừng bao giờ hardcode AccessKey và SecretKey vào source code. Hãy dùng:
- IAM Role: Gắn quyền trực tiếp vào con
EC2/EKSđang chạy ứng dụng. - Bucket Policy: Chặn ở tầng Bucket.
Ví dụ, muốn chặn không cho ai đẩy file lên nếu file đó chưa được mã hóa bằng AES256:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-production-bucket/*",
"Condition": {
"StringNotEquals": { "s3:x-amz-server-side-encryption": "AES256" }
}
}
]
}# checklist lên production
Trước khi release, anh em nhớ check qua các mục này để kê cao gối ngủ:
- Đã bật
Block Public Accessđể tránh lộ lọt dữ liệu ra Internet. - Đã cấu hình
Server-Side Encryptionđể bảo vệ data at rest. - Đã bật
Versioningđể lỡ có xóa/ghi đè nhầm thì vẫn khôi phục được. - Đã cấu hình
Lifecycle Rulexóa rácAbortIncompleteMultipartUpload. - API cấp
Presigned URLđểTTLngắn gọn (Max 15 phút). - Cấu hình
CORSkĩ càng nếu cho Browser tải file trực tiếp quaPresigned URL. - Dùng chung 1 instance của
S3Client(vì nóThread-safe) thay vì khởi tạo liên tục.
Bài viết mang tính chất "ghi chú - chia sẻ và phi lợi nhuận". Nếu thấy hữu ích, hãy chia sẻ nó tới bạn bè và đồng nghiệp của bạn nhé!
Happy coding 😎 👍🏻 🚀 🔥.