#129 - Vận hành Docker Container thế nào cho hiệu quả?
Để nhóm biên tập có thể nhiều phản hồi trực tiếp từ bạn đọc, nhóm biên tập xin mời các bạn đọc cùng tham gia vào nhóm Facebook dành riêng cho Newsletter Subscriber: https://www.facebook.com/groups/300419931101401. Các bạn có thể đưa ra góp ý, ý tưởng cải thiện, phản hồi cho chất lượng newsletter ... trực tiếp cho nhóm biên tập. Hy vọng sẽ nhận được nhiều đóng góp từ các bạn đọc để chất lượng của Newsletter ngày càng hoàn thiện hơn.
- Nhóm biên tập Grokking Newsletter
Những bài viết hay
Deep dive CSS: font metrics, line-height and vertical-align - Vincent De Oliveira — iamvdo.me
Line-height và vertical-align là những thuộc tính CSS rất cơ bản nên nhiều người lầm tưởng rằng nó rất đơn giản, nhưng không phải thế. Chúng thật sự phức tạp và gây rối nếu ta không hiểu rõ.
Lấy ví dụ, line-height có thể được set là bằng một độ dài hoặc một vài đơn vị đo khác, nhưng mặc định là normal. Nhưng normal là bao nhiêu? Có vẻ như sẽ là 1 hoặc là 1.2 như mọi khi, ngay cả trong CSS specs cũng đề cập không rõ ràng về điều này. Chúng ta đều biết rằng line-height và font-size liên quan tới nhau, nhưng vấn đề là font-size: 100px có thể có hiển thị khác nhau tuỳ vào font-families, vậy thì line-height sẽ hiển thị giống hay khác ở trường hợp này? Có phải normal chỉ có giá trừ từ 1 hoặc 1.2? Và với vertical-align, nó có gì liên quan tới line-height không?
Bài viết sau đây sẽ cung cấp cho bạn một cái nhìn chi tiết hơn về một "CSS-không-hề-đơn-giản-như-bạn-nghĩ".
Use Binary Encoding Instead of JSON - Shilpi Gupta — medium.com
Trong RAM, dữ liệu được lưu ở dạng object, struct, array v.v. để tối ưu cho việc đọc và ghi được thực hiện bởi CPU. Tuy nhiên, để có thể truyền dữ liệu qua mạng internet, bạn cần mã hoá nó dưới dạng chuỗi bytes. Ở chiều ngược lại, khi nhận được chuỗi bytes, bạn muốn load nó vào bộ nhớ để chương trình có thể xử lý tiếp, bạn cần giải mã nó. Quá trình mã hoá được gọi là Encoding, còn quá trình giải mã được gọi là Decoding.
Có 2 định dạng khi mã hoá
Nguyên bản (Textual formats): con người có thể đọc hiểu (JSON, XML, CSV)
Nhị phân (Binary formats): ngôn ngữ máy, do đó chỉ máy hiểu (Thrift, Protocol Buffers hay Avro)
Hạn chế của textual format là cần nhiều dung lượng hơn so với binary format. Tại sao điều đó quan trọng? Ngày nay, với sự phát triển mạnh mẽ của IoT (kết nối vạn vật), dữ liệu được truyền qua internet tăng đáng kể, do đó việc giảm kích thước gói tin là điều cần được quan tâm. Với dữ liệu sau ở định dạng JSON thì cần 81 bytes (sau khi đã remove hết khoảng trắng)
{
"userName": "Martin",
"favoriteNumber": 1337,
"interests": ["daydreaming", "hacking"]
}
Nếu được mã hoá ở dạng nhị phân, số bytes cần thiết để chứa thông tin trên giảm đáng kể cụ thể như sau:
Thrift Binary Protocol: 59 (~27%)
Thrift Compact Protocol: 34 (~58%)
Protocol Buffers: 33 (~59%)
Avro: 32 (~60%)
Ở bài viết này, tác giả sẽ giải thích chi tiết về các định dạng mã hoá khác nhau cũng như tại sao nên dùng mã hoá nhị phân thay cho json.
Bootstrapping a multimodal project using MMF, a PyTorch powered MultiModal Framework - PyTorch — medium.com
Những mô hình trong lĩnh vực Thị giác máy tính (CV) và Xử lý ngôn ngữ tự nhiên (NLP) thường được phát triển riêng do tính chất khác biệt giữa hai lĩnh vực này. Tuy nhiên, có một dạng nghiên cứu mới nổi lên trong những năm gần đây đó là "reasoning across different modalities" cần sử dụng kết hợp các thuật toán từ cả CV và NLP.
Ví dụ: Trong bài toán "visual question answering", mô hình vừa phải nhận diện được hình ảnh và đồng thời phải trả lời những câu hỏi liên quan tới hình ảnh đó. Hay trong bài toán "image captioning", mô hình vừa phải hiểu hình ảnh vừa phải dùng thuật toán NLP để tạo ra "caption" cho những bức hình này.
Những nền tảng hay thư viện phổ biến như Pytorch hay Tensorflow không được xây dựng để giải quyết bài toán kết hợp này. Do đó, giới nghiên cứu muốn một "framework" giúp họ "prototype" và "replicate performance" của những mô hình "state of the art" (SOTA) không những chính xác mà còn nhanh chóng hơn nữa. "Framework" MMF của Facebook được ra đời để giải quyết nhu cầu bức thiết này.
MMF được xây dựng trên nền tảng của Pytorch 1.5 dưới dạng mô-đun để tăng tính linh hoạt khi thiết lập các loại mô hình khác nhau. Hiện tại, MMF có những tính năng chính sau:
Cung cấp "starter code" cho một số thử thách multimodal AI
Một số mô-đun cơ bản như "encoder", "decoder", lớp "embedding"...
Dùng thư viện OmegaConf để quản lý file "configuration"
Hỗ trợ "distributed training" và "slurm jobs"
Có 12+ "pretrained" mô hình SOTA, 20+ tập dữ liệu
MMF đã được dùng cho một số dự án tại Facebook và cho những kết quả bước đầu rất khả quan. Hy vọng trong thời gian tới, với hỗ trợ đến từ nguồn lực dồi dào từ Facebook, framework MMF sẽ phổ biến và giúp ích nhiều hơn cho sự phát triển của cộng đồng AI.
Best Practices for Operating Containers - Google Cloud — cloud.google.com
Trong số Newsletter trước, chúng ta đã cùng tìm hiểu cách thiết kế một docker image sao cho hiệu quả thông qua bài viết này của Google. Vậy sau khi đã build docker image, làm sao để chạy chúng một cách hiệu quả, chính xác và đáng tin cậy? Tiếp tục là một bài viết của Google, với những gợi ý hữu ích với mức độ quan trọng từ cao đến thấp, giúp chúng ta hiểu hơn về việc vận hành Docker Container một cách ổn định.
Một số gợi ý đến từ Google:
Sử dụng cơ chế logging của container: Log là một phần quan trọng trong việc quản lý các ứng dụng, giúp chúng ta nắm bắt chính xác những gì đang xảy ra. Trong một server truyển thống, chúng ta có thể cần viết logs ra một file nhất định và phải xử lý log rotation để tránh đầy ổ cứng. Với một thiết kế hệ thống logs phức tạp hơn, ta có thể gửi và tập trung logs đến một server. Với docker container, các developer có thể xử lý logs một cách dễ dàng bằng cách viết vào stdout hay stderr. Docker sẽ ghi lại những logs này và cho phép ta đọc chúng bằng câu lệnh “docker logs”. Để tập trung logs trong hệ thống và hỗ trợ các developer tìm kiếm chúng một cách dễ dàng, quản lý hệ thống cần sử dụng các giải pháp như fluentd hay EFK (ElasticSearchm Fuentd, Kibana). Trong môi trường Kubernetes, cách tối ưu khi thiết kế hệ thống này là sử dụng sidecar pattern với một logging agent container chạy song song với docker của ứng dụng trong cùng một pod và chia sẻ chung volume.
Đảm bảo rằng trạng thái của container là bất biến và không thay đổi: Đây là một điểm khác biệt lớn với các server truyển thống. Điều này có nghĩa tất cả các trạng thái của ứng dụng cần được lưu bên ngoài container, ví dụ như files, user session, lưu trữ cơ sở dữ liệu. Điều này giúp container có thể bị dừng hoạt động bất cứ lúc nào mà chúng ta không lo lắng việc bị mất dữ liệu. Ngoài ra, container không nên bị thay đổi trong vòng đời của nó: không cập nhật, không vá lỗi, không thay đổi config. Nếu cần thay đổi code của ứng dụng, ta nên build 1 image mới và deploy lại. Điều này giúp chúng ta quản lý các phiên bản của ứng dụng trong các môi trường khác nhau một cách dễ dàng hơn.
Không chạy container với thiết lập privileged: Với một máy ảo hay server truyền thống, chúng ta cần tránh chạy ứng dụng với root user với một lý do đơn giản: nếu ứng dụng bị tấn công, hacker sẽ không nắm toàn quyền truy cập đến server. Với lý do tương tự, ta cần trình sử dụng privileged container với chế độ này để cho phép container có thể tiếp cận toàn bộ host server và vượt qua toàn bộ các lớp an ninh của container.
Luôn đảm bảo có thể dễ dàng monitor ứng dụng: Một giải pháp hữu hiệu là sử dụng Prometheus. Chúng ta có thể thiết kế một đường dẫn HTTP (endpoint) chứa đựng toàn bộ các thông tin dưới dạng metrics của ứng dụng. Prometheus sẽ liên tục gọi đến các đường dẫn này để lưu lại trạng thái theo thời gian của ứng dụng. Từ đây, ta có thể thiết lập các alert cần thiết dựa vào các metrics thu thập được. Trong môi trường Kubernetes, thiết kế sidecar container tương tự hệ thống logging là một cách tối ưu để triển khai hệ thống monitoring.
Hiện thị tình trạng của ứng dụng một cách rõ ràng: Một ứng dụng cần cung cấp trạng thái của nó đến toàn bộ hệ thống để biết liệu ứng dụng có chạy không, có khoẻ mạnh không hay đã sẵn sàng nhận traffic chưa và nó sẽ xử lý tốt không. Trong môi trường Kubernetes, tính năng Liveness probe và Readiness probe sẽ giúp chúng ta đạt được những điều này một cách dễ dàng.
Tránh chạy container với root user: Dù container được thiết kế biệt lập nhưng container vẫn chia sẻ kernel với máy chủ. Chạy container với root user vẫn có khả năng khiến hacker tìm kiếm các lỗ hổng để tấn công hệ thống.
Lựa chọn phiên bản image một cách cẩn thận đặc biệt với các image được public.
Góc Database
Log-Structure Merge (LSM) Tree là một trong các kiểu cấu trúc dữ liệu được ứng dụng khá rộng rãi trong các hệ dữ liệu NoSQL phân tán được tối ưu cho thao tác “ghi”. LSM-tree có một số điểm đặc trưng như:
Thao tác insert và update được xem như nhau, hệ thống không cần kiểm tra xem một record đã tồn tại hay chưa trước khi thực hiện lệnh update, nhờ vậy mà thao tác insert/update diễn ra khá nhanh.
Quá trình đọc sẽ diễn ra chậm hơn vì hệ thống lưu nhiều phiên bản của cùng một dòng dữ liệu nên phải lọc ra hết các dòng tương ứng, từ đó tốn thêm thời gian so với các cách lưu trữ khác.
Do các đặc tính trên nên việc xây dựng một Secondary Index cho LSM-tree là một bài toán không đơn giản. Kiểu dữ liệu B-tree vốn thường được dùng để xây dựng các cây index tỏ ra kém hiệu quả trong tình huống này.
Trong bài báo này, các tác giả chia sẻ về kỹ thuật Diff-Index, một cơ chế quản lý Global Secondary Index phù hợp hơn với LSM thông qua 4 schemes: sync-full, sync-insert, async-simple và async-session.
Đọc bài báo gốc: link
Code & Tools
Quotes
Java is to JavaScript what car is to Carpet.
- Chris Heilmann