Hướng dẫn thiết kế hệ thống (Phần 1)
Trong các bạn có lẽ ai cũng đã và sẽ từng được đặt câu hỏi về thiết kế hệ thống cho một dự án nào đó. Theo cách thông thường mà mọi người hay làm đó là sẽ xem hệ thống này cần chạy những service gì sau đó thì lắp ghép chúng lại với nhau. Ở đây tôi không nói cụ thể cách làm trên là nên hay không ...
Trong các bạn có lẽ ai cũng đã và sẽ từng được đặt câu hỏi về thiết kế hệ thống cho một dự án nào đó. Theo cách thông thường mà mọi người hay làm đó là sẽ xem hệ thống này cần chạy những service gì sau đó thì lắp ghép chúng lại với nhau. Ở đây tôi không nói cụ thể cách làm trên là nên hay không nên. Hãy cùng nhìn vào mô hình phía dưới, nếu thoáng nhìn qua có vẻ nó rất phức tạp, nhưng qua bài việc này sẽ giúp các bạn chính tay design được hệ thống của chính mình.
Học cách thiết kế hệ thống lớn
-
Học cách thiết kế các hệ thống có thể mở rộng sẽ giúp bạn trở thành một kỹ sư giỏi hơn.
-
Thiết kế hệ thống là một chủ đề rộng. Có rất nhiều tài liệu chia sẻ trên các khắp trang web về các nguyên tắc thiết kế hệ thống. Chuỗi bài viết này là tập hợp các tài liệu giúp bạn học cách xây dựng hệ thống 1 cách quy mô.
Tự tay thiết kế được hệ thống
- Ngoài code, thiết kế hệ thống là một thành phần bắt buộc tại nhiều công ty kỹ thuật.
- Việc practive các vấn đề, câu hỏi trong thiết kế hệ thống chung. Sau đó so sánh với kết quả của bạn với các giải pháp mẫu. Tiếp theo thảo luận trao đổi và vẽ ra các sơ đồ.
Q: Bạn có cần biết mọi thứ ở đây không ? A: Không, bạn không cần phải biết mọi thứ ở đây. Bạn sẽ phụ thuộc vào những điều như sau:
- Bạn có bao nhiêu kinh nghiệm
- Nền tảng kỹ thuật của bạn là gì ?
- Bạn đang làm việc tại vị trí nào ?
- Công ty bạn đang làm, họ đang làm lĩnh vực gì ?
Bắt đầu chúng ta nên tìm hiểu rộng và đi sâu hơn ở từng thành phần. Nó sẽ giúp ta biết một chút về các chủ đề thiết kế hệ thống quan trọng khác nhau. Điều chỉnh lại dựa trên thời gian và kinh nghiệm sau khi có đủ specs về dự án mà bạn tham gia.
Làm sao để tiếp cận
Bước 1 : Phác thảo các trường hợp sử dụng, ràng buộc và giả định Thu thập các yêu cầu và phạm vi vấn đề. Hỏi các câu hỏi để làm rõ các trường hợp sử dụng và các ràng buộc. Sau đó thảo luận về các giả định.
- Ai là người sử dụng ?
- Họ sẽ sử dụng nó như thế nào ?
- Có bao nhiêu người sử dụng hệ thống đó ?
- Hệ thống đó làm những gì ?
- Đầu ra và đầu vào của hệ thống đó là gì ?
- Bạn mong muốn xử lý được bao nhiêu dữ liệu
- Bao nhiêu request/s
- Tỷ lệ đọc/ghi dự kiến
Bước 2 : Thiết kế ở mức cao hơn Phác thảo thiết kế với tất cả các thành phần quan trọng của hệ thống.
- Phác thảo các thành phần và kết nối chính
- Giải thích được các ý tưởng của chính bạn
Bước 3 : Thiết kế các thành phần core của hệ thống Đi sâu vào từng thành phần cốt lõi. Ví dụ : nếu bạn được yêu cầu thiết kế dịch vụ rút ngắn URL, hãy thảo luận những vấn đề kiểu như sau : Generate và lưu trữ hash của URL
- MD5 và Base62
- Hash
- SQL hay NoSQL
- Sơ đồ cơ sở dữ liệu
Dịch một URL đã được chuyển sang hash thành URL đầy đủ
- Tra cứu cơ sở dữ liệu
API và thiết kế hướng đối tượng
Bước 4 : Quy mô của hệ thống Xác định và giải quyết nút nghẽn cổ chai, đưa ra những hạn chế. Ví dụ: bạn cần những điều sau để giải quyết các vấn đề về khả năng mở rộng không?
- Load Balancer
- Scale theo chiều ngang
- Caching
- Bảo vệ được database, không để DB có thể kết nối từ ngoài
Thảo luận các giải pháp về nguy cơ tiềm tàng và businees. Tất cả mọi thứ đều vì hướng tới thương mại. Giải quyết các trở ngại trong sử dụng các nguyên tắc của thiết kế hệ thống khả năng mở rộng.
Tính toán
Có lẽ các bạn sẽ được yêu cầu thực hiện các ước tính bằng tay, cá nhân mình có 1 số chia sẻ nhỏ như dưới đây. Tuy nhiên mình ở các bài viết tiếp theo thì chia sẻ sâu hơn vấn đề này ở các bài toán ví dụ cụ thể.
- Back of the envelope : nghĩa đen là đăng sau lưng cái bao thư, và nghĩa bóng là tính toán một cách áng chừng. Sở dĩ có thành ngữ này là vi khi ta muốn làm toán một cách vội vã ta thường kiếm vội một mảnh giấy để viết các con số lên đó, và thường thường thì một cái bao thư là dễ tìm nhất để tìm nhất để viết lên đó. Thành ngữ Back of the Envelope đã được một nghị sĩ Mỹ dùng khi ông muốn tính phỏng chừng những tổn phí của chương trình chăm sóc sức khỏe mới của Hoa Kỳ. Trong đời sống hàng ngày, ta hãy nghe thí dụ sau đây về một người thợ mộc tính phỏng chừng giá cả của mấy cái tủ đựng chén dĩa trong nhà bếp mà bà Wood muốn ông ta làm.
- Power of two table : khái niệm được mượn từ toán học, có nghĩa là một số 2 mũ n với n là số nguyên, tức là luỹ thừa với cơ số 2 với n là số mũ. Vậy sẽ làm rõ hơn trong bài viết này ở phần tiếp theo của bài viết.
- Latency number : Độ trễ nên biết để lấy làm cơ sở để tính toán.
Back of the envelope Làm thế nào để bạn biết thế nào là thiết kế tốt nhật cho những vấn đế đã được đưa ra. Theo tôi thì chả có cách nào bạn phải làm 1 tính toán dựa trên con số cụ thể. Ở đây ví dụ bạn sẽ tạo một trang kết quả tìm kiếm hình ảnh của 30 hình ảnh. VẬY hình ảnh đó có được load liên tục, liên tiếp ko ? Thực hiện việc đó song song, đồng thời ? Bạn có bộ nhớ cache ? Bạn quyết định như thế nào ?
Sử dụng tính toán "Back-Of-The-Envelope" để đánh giá các thiết kế khác nhau
- Thiết kế thứ nhất : Load theo thứ tự. Đọc lần lượt -> tìm kiếm trên ổ đĩa -> Đọc một hình ảnh 256k và sau đó chuyển sang ảnh tiếp theo. Performance : (30 tìm kiếm) x 10 ms/tìm kiếm + 30 * 256K / 30MB/s = 560ms
- Thiết kế thứ hai : Load song song Performance : 10 ms/tìm kiếm + 256K read / 30 MB/s = 18ms
Vậy thiết kế nào tốt hơn ? Không có câu trả lời ở nào là chính xác hoàn toàn, nó phụ thuộc vào yêu cầu của bạn. Nhưng với cách tính toán này bạn có tính toán nhanh trong khi chưa cần phải thiết kế gì có đúng không nào ? Bây giờ bạn đã có một mẫu để tự hỏi bản thân mình những câu hỏi khác về thiết kế hệ thống and so sánh sự khác nhau trong từng trường hợp :
- Có nên Cache từng hình ảnh ?
- Có nên cache toàn bộ hình ảnh trong một mục không ?
- Có thể ước tính trước được hay không ?
Để làm các ước tính này có tính thực tế bạn phải biết được hiệu suất các dịch vụ vủa bạn. Nếu có 1 thông số biến thiên không rõ ràng thì có lẽ các mẫu tính toán nhanh chỉ là một phần để giải quyết các câu hỏi. Đơn giản để trả lời câu hỏi làm sao để biết bộ nhớ đệm là một sự lựa chọn tốt thì bạn phải trả lời được câu hỏi phải mất bao lâu để ghi vào bộ nhớ cache.
Bài học rút ra được
- Tính toán Back-of-the-envelope giúp bạn đưa ra được kết quả cho các trường hợp khác nhau.
- Khi bạn thiết kế hệ thống của bạn, loại tính toán này bạn nên làm liên tục lặp đi lặp lại
- Back-of-the-envelope xây dựng các phần, khối cho hệ thống của bạn nhưng nó ko đủ tốt vì nó chỉ là hệ số chung, bạn cần phải làm thêm các bài test cho các hệ thống con nhỏ hơn
- Bạn ko thể tính toán đúng nếu bạn ko biết những gì đang chạy, đang xảy ra trên hệ thống của bạn
- Monitor và đo lượng mọi phần của hệ thống của bạn để có thể thực hiện các loại dự báo này từ dữ liệu thực
Cá nhân tôi khá thích thú với cách tiếp cận này. Có vẻ sẽ có nhiều căn cứ hơn để tới các hệ thống cụ thể hơn là các hệ thống chung phổ biến mà bạn được share trên internet. Bài practive này chỉ là forcus và các tính toán, đây thực sự là một phần để đáng nghiên cứu và sử dụng để phân tích toàn diện hơn.
Powers of two table Như đã nói ở trên ở đây không có gì phức tạp chỉ là kinh nghiệm của tôi là nên nhớ 1 vài con số trong bảng sau sẽ giúp bạn có câu trả lời nhanh hơn, theo tôi là như vậy.
Power Exact Value Approx Value Bytes --------------------------------------------------------------- 7 128 8 256 10 1024 1 thousand 1 KB 16 65,536 64 KB 20 1,048,576 1 million 1 MB 30 1,073,741,824 1 billion 1 GB 32 4,294,967,296 4 GB 40 1,099,511,627,776 1 trillion 1 TB
Latency number Jeff Dean, thành viên cao cấp của nhóm hệ thống và cơ sở hạ tầng của Google - một trong những hệ thống chính của Google: phục vụ quảng cáo, BigTable; Tìm kiếm, MapReduce, ProtocolBuffers. Ông đã đưa ra danh sách sau :
Latency Comparison Numbers -------------------------- L1 cache reference 0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache Mutex lock/unlock 100 ns Main memory reference 100 ns 20x L2 cache, 200x L1 cache Compress 1K bytes with Zippy 10,000 ns 10 us Send 1 KB bytes over 1 Gbps network 10,000 ns 10 us Read 4 KB randomly from SSD* 150,000 ns 150 us ~1GB/sec SSD Read 1 MB sequentially from memory 250,000 ns 250 us Round trip within same datacenter 500,000 ns 500 us Read 1 MB sequentially from SSD* 1,000,000 ns 1,000 us 1 ms ~1GB/sec SSD, 4X memory Disk seek 10,000,000 ns 10,000 us 10 ms 20x datacenter roundtrip Read 1 MB sequentially from 1 Gbps 10,000,000 ns 10,000 us 10 ms 40x memory, 10X SSD Read 1 MB sequentially from disk 30,000,000 ns 30,000 us 30 ms 120x memory, 30X SSD Send packet CA->Netherlands->CA 150,000,000 ns 150,000 us 150 ms Notes ----- 1 ns = 10^-9 seconds 1 us = 10^-6 seconds = 1,000 ns 1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns
Như vậy tôi sẽ có sổ tay hữu ích dựa trên các dữ liệu trên :
- Tốc độ đọc tuần tự từ đĩa là 30 MB/s
- Đọc tuần tự từ 1Gbps Ethernet là 100 MB/s
- Đọc tuần tự từ SSD là 1GB/s
- Đọc tuần tự từ memory là 4GB/s
- 6-7 vòng quay mỗi giây
- 2000 vòng / phút
Bảng hiện thị thời gian trễ :
Trên đây chỉ là chia sẻ cũng như kinh nghiệm bản thân của tôi, bản thân tôi cũng hi vọng nhận được sự những chia sẻ cũng như thảo luận từ phía các bạn để hoàn thiện hơn. Trong phần sau tôi sẽ trình bày tiếp một ví dụ cụ thể về dịch vụ rút ngắn tên miền bao gốm bài tập và giải pháp. Rất mong sẽ nhận được sự góp ý từ phía các bạn.
Tham khảo :
The Back of the Napkin của Dan Roam A Physicist Explains Why Parallel Universes May Exist của Brian Green Latency numbers every programmer should know - 1 Latency numbers every programmer should know - 2 Designs, lessons, and advice from building large distributed systems Software Engineering Advice from Building Large-Scale Distributed Systems