#231 - Gojek scale Geo-Search gấp 10 lần ra sao?
Dạo gần đây, team newsletter của Grokking hơi bận 1 chút xíu, nên thi thoảng các bạn sẽ thấy newsletter được gửi hơi trễ so với bình thường, hoặc là đôi khi miss hẳn 1 tuần. Ngoài ra team cũng muốn gửi những bài viết chất lượng nhất tới bạn đọc, quá trình chuẩn bị vì thế kéo dài hơn rất nhiều so với trước đây.
Team sẽ cố gắng và gửi đều đặn hơn vào 8h tối mỗi thứ 5 hàng tuần các bạn nhé. Xin cảm ơn các bạn đọc đã gửi những phản hồi cũng như quan tâm tới Grokking Newsletter 🙏
Trong số này, chúng ta cùng tìm hiểu về:
Quy trình Continuous Deployment (CD) tại Amazon
Cách Gojek scale dịch vụ tìm kiếm (Geo-Search) theo địa điểm 10 lần
Quá trình tìm kiếm Go issue trên ARM dẫn tới TiDB bị treo
Lời giải bài Find Root of N-Ary Tree
Ngoài ra các bạn vẫn có thể tiếp tục đặt mua ấn phẩm Dijkstra tập 2 tại đây.
Những bài viết hay
Automating safe, hands-off deployments
(by nghialuu)
Amazon áp dụng triển khai liên tục (continuous deployment) để giúp các kỹ sư deploy nhiều lần trong một ngày một cách nhanh chóng và an toàn. Với cách làm thủ công, sau khi push code lên nhánh “main”, một kỹ sư thường phải dành hàng giờ để build, deploy cẩn thận và từ từ đẩy lên môi trường production, sau đó họ phải theo dõi, kiểm tra log để xem code có chạy đúng không hay có cần rollback không. Với continuous deployment pipelines, code sau khi được push lên nhánh “main” sẽ được triển khai lên production một cách hoàn toàn tự động và an toàn, giúp kỹ sư có thể quên nó đi và chuyển sang làm việc khác. Một pipeline sẽ trải qua 4 khâu chính: từ source -> build -> test -> prod, có thể được tóm tắt như sau:
Mỗi microservice sẽ có từng pipeline riêng cho application code, infrastructure, configuration, đôi khi cả hệ điều hành. Việc tách pipeline này giúp cho việc deploy nhanh hơn, một pipeline bị chặn bởi lí do nào đó sẽ không ảnh hưởng đến pipeline khác.
Tất cả các thay đổi sau khi được review và approve sẽ được merge vào nhánh “main” và tự động bắt đầu pipeline.
Code sau đó sẽ được compile, chạy unit test, lint và có thể được kiểm tra bởi các tool phân tích tĩnh khác.
Pipeline triển khai bản build trên các môi trường pre-production theo tuần tự là Alpha, Beta, và Gamma để chạy các test và phép kiểm thử có quy mô rộng hơn (functional API test, integration test, one-box test với canary, …). Môi trường Gamma giống production nhất có thể với cùng config, cơ chế theo dõi và báo động, cơ chế canary testing và bao gồm nhiều AWS Regions.
Triển khai production sẽ được bắt đầu ở quy mô rất nhỏ và tăng dần dần lên với các cấp độ box, nhiều box, Zone, nhiều Zone, Region để giới hạn ảnh hưởng đến người dùng.
Hệ thống sẽ tự động theo dõi log, metrics, quản lý báo động, và xác định có cần rollback không. Các tiêu chí để báo động và rollback sẽ được thiết lập trước.
Việc triển khai một cách tự động và an toàn giúp tiết kiệm rất nhiều thời gian và tâm trí cho các kỹ sư ở Amazon. Tác giả miêu tả và đào sâu chi tiết trong bài viết, mời bạn đọc cùng tìm hiểu thêm nhé.
Scaling Our Geo-Search Service For 10x Load
(by sonnv)
Sự tăng trưởng và phát triển nhanh chóng của Gojek ở thị trường Đông Nam Á đòi hỏi các dịch vụ của họ phải ngày càng hoàn thiện và đáp ứng được khả năng mở rộng cao. Một dịch vụ quan trọng trong hệ thống của Gojek là Available Driver Service (ADS), có chức năng là hệ thống tìm kiếm theo khu vực địa lý (geo-search). Đội ngũ kỹ sư Gojek cần phải mở rộng quy mô của ADS để có thể đáp ứng nhu cầu ngày càng tăng lên của những dịch vụ đang gọi tới nó.
Những nguyên tắc mà họ đã áp dụng trong quá trình mở rộng hệ thống:
Read và Write riêng biệt giúp tách biệt nghiệp vụ và làm đơn giản hoá quá trình mở rộng hệ thống.
Mỗi truy vấn được giải quyết song song bởi nhiều node** giúp hệ thống có độ trễ thấp.
Một truy vấn tìm kiếm có thể đi đến nhiều node** và mỗi node phản hồi lại bằng một tập hợp danh sách các tài xế, trong khoảng thời gian định trước mà không cần phải đợi thêm những phản hồi từ các node chậm khác.
Cách tiếp cận mở rộng theo nhiều node đã cho thấy những tín hiệu tích cực hơn so với giải pháp mở rộng theo chiều dọc. Sau khi hoàn tất quá trình mở rộng ADS, hệ thống dễ dàng xử lý tới 600.000 lượt read/phút và 200.000 lượt write/phút trong thời gian cao điểm.
Mời bạn đọc cùng tìm hiểu chi tiết qua bài viết sau.
How I Found a Go Issue on ARM that Crashed the Database Server
(by lpv)
TiDB là một open-source NewSQL database hỗ trợ Hybrid Transactional và Analytical Processing (HTAP) workloads. Được thiết kế theo kiến trúc nhiều lớp, với storage layer implement bởi Rust, computing layer được implement bằng Go. TiDB là một project phức tạp và hiệu năng của nó phụ thuộc vào nhiều yếu tố như OS, hardware platform, compiling language ...
Trong bài viết này, tác giả chia sẻ về một lỗi "kỳ lạ" trong Go là nguyên nhân dẫn đến việc TiDB crash trên nền tảng Advanced RISC Machine (ARM).
Lỗi này đã lần đầu tiên được tìm thấy khi test cho TiDB 5.4. Trong quá trình test, một QA engineer đã báo cáo rằng database bị treo và không phản hồi. Tuy nhiên khi chạy test lại thì lỗi này đã không xuất hiện lại.
Sau đó trong quá trình test cho TiDB 6.0, lỗi này lại xuất hiện một lần nữa. Lần này họ đã có thể tái hiện lại được bug.
Khi issue này xảy ra, tidb-server process
không còn phản hồi các request. Tuy nhiên process không bị panic
và service port vẫn còn.
Quan sát từ các công cụ monitoring có thể thấy process vẫn sống tuy nhiên nó ko phản hồi các request, do đó không có dữ liệu log.
Khi quan sát trực tiếp trên machine, CPU usage của server là 100%, trên một machine multicore, tuy nhiên nó chỉ chiếm dụng duy nhất 1 core.
Để tìm ra chính xác điều gì đã xảy ra, tác giả đã kiểm tra goroutine stack
curl http://127.0.0.1:10080/debug/pprof/goroutine?debug=2 > goroutine.txt
Tuy nhiên, do port 10080 không thể phản hồi request, nên thao tác này không thể mang lại thông tin về goroutine stack.
Do CPU usage là 100%, nên có khả năng một dead loop đã xảy ra ở đâu đó. Do thực hiện trên môi trường test nên cho phép tác giả sử dụng Delv, một Go debugging tool để debug TiDB process.
dlv attach 4637
Dựa vào thông tin debug log có thể thấy một thread được active trong khi các thread khác đều ở trạng thái futex, hay nói cách khác là đã bị lock.
Call stack của thread trong trạng thái futex nằm trong runtime.stopm
function. Lệnh này sẽ thực hiện việc dừng thao tác để thực hiện garbage collection (GC), ở đó việc thực thi toàn bộ chương trình sẽ bị treo cho tới khi tất cả các object trong heap đã được xử lý. Thao tác này cần acquire lock nhưng lại thất bại.
Tại active thread, tác giả tìm thấy gentraceback
ở cuối của call stack.
Khi cố gắng chạy tiếp thì phát hiện ra chương trình stuck trong gentraceback
, một dead loop đã xảy ra tại đây.
Cuối cùng, toàn bộ process burn out CPU trên 1 thread, trong khi các thread khác đang chờ lock.
Tác giả đã thực hiện fix lại code Go tại đây. Lúc này dead loop đã không còn xảy ra nữa và TiDB hoạt động bình thường trở lại. Tuy nhiên để có được bản fix chính thức, tác giả đã liên lạc với Go team để tìm ra nguyên nhân thực sự. Một lỗi tương tự trên Go đã được tìm thấy ở đây và đã được fix trên Go 1.16 và 1.17. Tác giả đã mô tả lại issue mình tìm thấy tại Go Repository và sau đó đã được fix officially bởi team Go.
Các bạn có thể đọc kỹ hơn về bài viết này cũng như quá trình debug chi tiết tại bài viết sau.
Góc Lập Trình
Đề ra tuần này: Time Based Key-Value Store
(by ndaadn)
Thiết kế và cài đặt một cấu trúc dữ liệu key-value theo mốc thời gian (timestamp), có thể lưu trữ nhiều giá trị cho cùng một key tại các timestamp khác nhau và truy xuất giá trị của key tại một timestamp nhất định.
Cấu trúc dữ liệu có 2 hàm:
Hàm void set (String key, String value, int timestamp): Lưu trữ key với giá trị value tại mốc thời gian timestamp.
Hàm String get (String key, int timestamp): Trả về value của key. Nếu có nhiều giá trị của key ứng với các timestamp khác nhau, trả về giá trị ứng với mốc thời gian nhỏ hơn (hoặc bằng) gần nhất với tham số timestamp. Nếu không có giá trị nào, trả về chuỗi rỗng "".
Lời giải đề bài tuần trước: Find Root of N-Ary Tree
(by ndaadn)
Ta có thể nhận thấy rằng chỉ có nút gốc không là nút con của bất kì nút nào khác trong cây. Vì vậy, để tìm nút gốc của cây, chỉ cần tìm danh sách tất cả các nút con của cây, nút còn lại duy nhất không nằm trong danh sách này chính là nút gốc.
Ta có thể sử dụng cấu trúc dữ liệu HashSet để lưu danh sách các nút con của cây. Cài đặt bằng Java cho lời giải trên như sau:
Độ phức tạp thời gian của giải thuật là O(N), độ phức tạp không gian là O(N).
Ngoài ra vì mỗi nút trong cây mang một giá trị duy nhất, ta có thể tối ưu lời giải trên, giảm xuống độ phức tạp không gian xuống O(1) bằng cách không sử dụng HashSet để lưu danh sách các nút con, mà có thể tính tổng giá trị các nút con và tổng giá trị tất cả các nút trong cây. Cuối cùng giá trị của nút gốc sẽ bằng hiệu của 2 giá trị tên.
History
Có bao giờ bạn tự hỏi những mẫu tuyển dụng cách đây 20 năm sẽ trông như thế nào? Hãy xem Jeff Bezos tuyển dụng 1 Unix Developer vào tháng 8/1994 như thế nào nhé (source: twitter)
Code & Tools
Kafka Streams - Kafka Streams là một công cụ xử lý streaming được thiết kế với khả năng tích hợp chặt chẽ với Apache Kafka. Nhiều tính năng của Kafka Streams được xây dựng dựa trên những ưu điểm nổi trội về lưu trữ hay tầng message của Kafka như khả năng xử lý có trạng thái (stateful processing), khả năng chịu lỗi (fault tolerance)
Apache Superset - Apache Superset là một công cụ miễn phí giúp xây dựng các dashboards một cách nhanh, nhẹ, trực quan với rất nhiều tùy chọn giúp người dùng dễ dàng khám phá và hình dung dữ liệu của họ. Superset cung cấp rất nhiều các tùy chọn biểu đồ cho người dùng, từ dạng biểu đồ đường đơn giản (line charts) cho đến biểu đồ không gian địa lý chi tiết cao (geospatial charts).
Feedback
Bạn đánh giá nội dung số newsletter này thế nào?
(1 = Rất tệ / 5 = Rất tốt)
(Việc đánh giá của các bạn là rất quan trọng, sẽ giúp chúng tôi liên tục cải thiện nội dung newsletter tốt hơn)
Grokking mang lại cho các bạn những kiến thức mới mẻ và hữu ích thông qua:
Tech Talk: Là một hoạt động thường xuyên của Grokking từ những ngày đầu thành lập. Tại đây các diễn giả chia sẻ kiến thức xoay quanh Computer Science và Software Engineer. Các buổi Tech Talk đều được record và upload lên kênh youtube của Grokking.
Grokking Knowledge Graph: Tập hợp những nguồn kiến thức phong phú với hơn 1000 bài viết chọn lọc, các đầu sách, khóa học, v.v… Các bài viết đều được gán nhãn để giúp bạn đọc dễ dàng tìm kiếm.
Webinar: Là chương trình kết nối các kỹ sư Việt Nam và các kỹ sư đang làm việc tại các công ty công nghệ hàng đầu thế giới.
Dijkstra: Một ấn phẩm được xuất bản bởi các thành viên của Grokking. Với những bài viết đào sâu vào kỹ thuật và kiến thức khoa học máy tính.
Kipalog: Nền tảng chia sẻ kiến thức dành cho các lập trình viên.
Newsletter: Những bài viết hay về công nghệ sẽ được gửi tới bạn hàng tuần qua email.
Chúc các bạn sẽ tìm được nhiều điều mới mẻ khi đến với Grokking và xin hẹn gặp lại các bạn vào tuần sau.
Quotes
“A conscious human is driven by their conscience, not popular opinion.”
― Suzy Kassem, Rise Up and Salute the Sun: The Writings of Suzy Kassem