Nhu cầu về các cửa hàng tính năng học máy chậm trễ thấp cao hơn bao giờ hết, nhưng thực tế thực hiện một cửa hàng tính năng học máy chậm trễ vẫn là một thách thức.Điều đó trở nên rõ ràng khi các kỹ sư ShareChat Ivan Burmistrov và Andrei Manakov đã tham gia giai đoạn P99 CONF 23 để chia sẻ cách họ đã xây dựng một cửa hàng tính năng ML chậm trễ thấp dựa trên ScyllaDB. Đây không phải là một nghiên cứu trường hợp gọn gàng, nơi việc áp dụng một sản phẩm mới tiết kiệm ngày. Đó là một câu chuyện về những bài học đã học được, một cái nhìn vào giá trị của tối ưu hóa hiệu suất không ngừng - với một số bước quan trọng trong kỹ thuật. Mục tiêu cuối cùng là hỗ trợ 1 tỷ tính năng mỗi giây, nhưng hệ thống thất bại dưới tải trọng chỉ 1 triệu.Với một số giải pháp vấn đề thông minh, nhóm đã loại bỏ nó mặc dù.Chúng ta hãy xem làm thế nào các kỹ sư của họ quản lý để xoay chuyển từ thất bại ban đầu để đáp ứng mục tiêu hiệu suất cao của họ mà không cần mở rộng cơ sở dữ liệu cơ bản. Bị ám ảnh bởi việc tối ưu hóa hiệu suất và kỹ thuật chậm trễ thấp? Tham gia với các đồng nghiệp của bạn tại P99 24 CONF, một hội nghị ảo kỹ thuật cao miễn phí về "tất cả các thứ hiệu suất." Michael Stonebraker, người sáng lập Postgres và giáo sư MIT Bryan Cantrill, đồng sáng lập và CTO của Oxide Computer Avi Kivity, người sáng lập KVM, đồng sáng lập ScyllaDB và CTO Liz Rice, Giám đốc nguồn mở với các chuyên gia eBPF Isovalent Andy Pavlo, Giáo sư CMU Ashley Williams, người sáng lập / CEO của Axo, cựu nhóm cốt lõi Rust, người sáng lập Quỹ Rust Carl Lerche, người sáng tạo Tokyo, đóng góp viên Rust và kỹ sư tại AWS Đăng ký ngay - miễn phí Đăng ký ngay - miễn phí Đăng ký ngay - miễn phí Ngoài một cuộc trò chuyện tuyệt vời khác của Ivan từ ShareChat, mong đợi hơn 60 cuộc trò chuyện kỹ thuật về tối ưu hóa hiệu suất tại Disney / Hulu, Shopify, Lyft, Uber, Netflix, American Express, Datadog, Grafana, LinkedIn, Google, Oracle, Redis, AWS, ScyllaDB và nhiều hơn nữa. ShareChat: Nền tảng truyền thông xã hội hàng đầu của Ấn Độ Để hiểu được phạm vi của thách thức, điều quan trọng là phải biết một chút về ShareChat, nền tảng truyền thông xã hội hàng đầu ở Ấn Độ. Trên ứng dụng ShareChat, người dùng khám phá và tiêu thụ nội dung bằng hơn 15 ngôn ngữ khác nhau, bao gồm video, hình ảnh, bài hát và nhiều hơn nữa. Giữa hai ứng dụng, họ phục vụ một cơ sở người dùng phát triển nhanh chóng đã có hơn 325 triệu người dùng hoạt động hàng tháng. Cửa hàng tính năng Machine Learning tại ShareChat Câu chuyện này tập trung vào hệ thống đằng sau các cửa hàng tính năng ML cho ứng dụng video ngắn Moj. Nó cung cấp nguồn cấp dữ liệu cá nhân hóa đầy đủ cho khoảng 20 triệu người dùng hoạt động hàng ngày, 100 triệu người dùng hoạt động hàng tháng. nguồn cấp dữ liệu phục vụ 8.000 yêu cầu mỗi giây, và có trung bình 2.000 ứng viên nội dung được xếp hạng trên mỗi yêu cầu (ví dụ, để tìm ra 10 mặt hàng tốt nhất để đề xuất). Ivan Burmistrov, kỹ sư phần mềm chính tại ShareChat, giải thích: “Chúng tôi tính toán các tính năng cho các ‘tổ chức khác nhau.’ Post là một thực thể, User là một thực thể khác và như vậy. Từ quan điểm tính toán, chúng khá giống nhau. Tuy nhiên, sự khác biệt quan trọng là số lượng các tính năng chúng ta cần thu thập cho mỗi loại thực thể. Khi người dùng yêu cầu một nguồn cấp dữ liệu, chúng tôi thu thập các tính năng của người dùng cho người dùng duy nhất đó. Tuy nhiên, để xếp hạng tất cả các bài đăng, chúng tôi cần thu thập các tính năng cho mỗi ứng cử viên (post) được xếp hạng, vì vậy tổng tải hệ thống được tạo ra bởi các tính năng của bài đăng lớn hơn nhiều so với tính năng do người dùng tạo ra. Sự khác biệt này đóng một vai trò quan trọng trong câu chuyện của chúng tôi.” Điều gì đã sai Lúc đầu, trọng tâm chính là xây dựng một cửa hàng tính năng người dùng thời gian thực bởi vì, tại thời điểm đó, tính năng người dùng là quan trọng nhất. Nhóm bắt đầu xây dựng cửa hàng tính năng với mục tiêu đó trong tâm trí. nhưng sau đó các ưu tiên thay đổi và các tính năng bài trở thành trọng tâm. Sự thay đổi này xảy ra bởi vì nhóm bắt đầu xây dựng một hệ thống xếp hạng hoàn toàn mới với hai sự khác biệt chính so với người tiền nhiệm của nó: Các tính năng bài viết gần thời gian thực quan trọng hơn Số lượng bài đăng được xếp hạng tăng từ hàng trăm lên hàng ngàn Ivan giải thích: “Khi chúng tôi đi thử nghiệm hệ thống mới này, nó đã thất bại đáng tiếc.Với khoảng 1 triệu tính năng mỗi giây, hệ thống trở nên không đáp ứng, độ trễ đi qua mái nhà và như vậy.” Cuối cùng, vấn đề bắt nguồn từ cách kiến trúc hệ thống sử dụng các thùng dữ liệu tổng hợp trước được gọi là gạch. Ví dụ, họ có thể tổng hợp số lượt thích cho một bài đăng trong một phút nhất định hoặc khoảng thời gian khác. Điều này cho phép họ tính toán các số liệu như số lượt thích cho nhiều bài đăng trong hai giờ qua. Dưới đây là một cái nhìn cấp cao về kiến trúc hệ thống. Có một vài chủ đề thời gian thực với dữ liệu thô (thích, nhấp chuột, v.v.). Một công việc Flink tổng hợp chúng thành gạch và viết chúng vào ScyllaDB. Sau đó có một dịch vụ tính năng yêu cầu gạch từ ScyllaDB, tổng hợp chúng và trả về kết quả cho dịch vụ nguồn cấp dữ liệu. Biểu đồ cơ sở dữ liệu ban đầu và cấu hình gạch dẫn đến các vấn đề về khả năng mở rộng. ban đầu, mỗi thực thể có phân vùng riêng, với dòng timestamp và tên tính năng được sắp xếp để nhóm các cột. ]. gạch được tính cho các phân đoạn của một phút, 30 phút và một ngày. tìm kiếm một giờ, một ngày, bảy ngày hoặc 30 ngày đòi hỏi phải thu thập khoảng 70 gạch mỗi tính năng trung bình. Tìm hiểu thêm trong NoSQL Data Modeling Masterclass này Nếu bạn thực hiện toán học, nó trở nên rõ ràng tại sao nó thất bại. hệ thống cần phải xử lý khoảng 22 tỷ hàng mỗi giây. tuy nhiên, công suất cơ sở dữ liệu chỉ là 10 triệu hàng / giây. Tối ưu hóa ban đầu Tại thời điểm đó, nhóm đã thực hiện một nhiệm vụ tối ưu hóa. sơ đồ cơ sở dữ liệu ban đầu đã được cập nhật để lưu trữ tất cả các hàng tính năng cùng nhau, được sắp xếp thành buffer giao thức cho một dấu thời gian nhất định. Bởi vì kiến trúc đã sử dụng Apache Flink, quá trình chuyển đổi sang sơ đồ gạch mới khá dễ dàng, nhờ khả năng tiên tiến của Flink trong việc xây dựng đường ống dẫn dữ liệu. Với tối ưu hóa này, bộ nhân "Tính năng" đã được loại bỏ khỏi phương trình trên và số hàng cần thu được đã giảm 100X: từ khoảng 2 tỷ đến 200 triệu hàng / giây. Nhóm nghiên cứu cũng tối ưu hóa cấu hình gạch, thêm gạch bổ sung trong năm phút, ba giờ và năm ngày vào gạch một phút, 30 phút và một ngày. Để xử lý nhiều hàng/giây hơn ở phía cơ sở dữ liệu, họ đã thay đổi chiến lược nén ScyllaDB từ tăng dần sang cấp. Tùy chọn đó phù hợp hơn với các mẫu truy vấn của họ, giữ các hàng có liên quan với nhau và giảm đọc I/O. Kết quả: công suất của ScyllaDB đã được tăng gấp đôi. Tìm hiểu thêm về các chiến lược compaction Cách dễ nhất để phù hợp với tải trọng còn lại sẽ là mở rộng ScyllaDB 4x. Tuy nhiên, các cụm lớn hơn sẽ làm tăng chi phí và điều đó đơn giản là không nằm trong ngân sách của họ. Cải thiện vị trí cache Một cách tiềm năng để giảm tải trên ScyllaDB là cải thiện tỷ lệ hit bộ nhớ cache địa phương, vì vậy nhóm đã quyết định nghiên cứu làm thế nào điều này có thể đạt được. Lựa chọn rõ ràng là sử dụng một cách tiếp cận hashing nhất quán, một kỹ thuật nổi tiếng để hướng một yêu cầu đến một bản sao nhất định từ khách hàng dựa trên một số thông tin về yêu cầu. Vì nhóm đang sử dụng NGINX Ingress trong thiết lập Kubernetes của họ, sử dụng khả năng hashing nhất quán của NGINX dường như là một lựa chọn tự nhiên. Theo tài liệu của NGINX Ingress, thiết lập hashing nhất quán sẽ đơn giản như thêm ba dòng mã. Một chút. cấu hình đơn giản này không hoạt động. cụ thể: Các subset của khách hàng dẫn đến một remapping khóa khổng lồ - lên 100% trong trường hợp tồi tệ nhất. vì các phím nút có thể được thay đổi trong một vòng hash, nó là không thể sử dụng các kịch bản thực tế với autoscaling. Thật khó để cung cấp một giá trị hash cho một yêu cầu vì Ingress không hỗ trợ giải pháp rõ ràng nhất: tiêu đề gRPC. Sự chậm trễ bị suy giảm nghiêm trọng, và không rõ nguyên nhân gây ra sự chậm trễ đuôi là gì. Để hỗ trợ một tiểu tập các pods, nhóm đã sửa đổi cách tiếp cận của họ. Họ đã tạo ra một hàm hash hai bước: đầu tiên hash một thực thể, sau đó thêm một tiền tố ngẫu nhiên. Điều đó phân phối thực thể trên số lượng pods mong muốn. Về mặt lý thuyết, phương pháp này có thể gây ra sự va chạm khi một thực thể được lập bản đồ vào cùng một pod nhiều lần. tuy nhiên, rủi ro là thấp do số lượng lớn các bản sao. Ingress không hỗ trợ sử dụng tiêu đề gRPC như một biến, nhưng nhóm đã tìm thấy một giải pháp: sử dụng viết lại đường dẫn và cung cấp khóa hash cần thiết trong đường dẫn. Thật không may, việc xác định nguyên nhân của sự suy giảm độ trễ sẽ mất rất nhiều thời gian, cũng như cải thiện khả năng quan sát. Để đáp ứng thời hạn, nhóm đã chia dịch vụ Feature thành 27 dịch vụ khác nhau và thủ công chia tất cả các thực thể giữa chúng trên máy khách. Đó không phải là cách tiếp cận thanh lịch nhất, nhưng, nó đơn giản và thực tế – và nó đạt được kết quả tuyệt vời. Tỷ lệ hit bộ nhớ cache được cải thiện đến 95% và tải ScyllaDB được giảm xuống còn 18,4 triệu hàng mỗi giây. Tuy nhiên, cách tiếp cận phân chia triển khai "trường cũ" này vẫn không phải là thiết kế lý tưởng. Duy trì 27 triển khai là tẻ nhạt và không hiệu quả.Thêm vào đó, tỷ lệ hit bộ nhớ cache không ổn định, và quy mô bị hạn chế bằng cách phải duy trì số lượng pod tối thiểu cao trong mỗi triển khai.Vì vậy, mặc dù cách tiếp cận này đáp ứng nhu cầu của họ về mặt kỹ thuật, nhóm tiếp tục tìm kiếm một giải pháp lâu dài tốt hơn. Giai đoạn tiếp theo của các tối ưu hóa: hashing nhất quán, dịch vụ tính năng Sẵn sàng cho một vòng tối ưu hóa khác, nhóm đã xem xét lại cách tiếp cận hashing nhất quán bằng cách sử dụng một sidecar, được gọi là Envoy Proxy, được triển khai với dịch vụ tính năng. Envoy Proxy cung cấp khả năng quan sát tốt hơn giúp xác định vấn đề đuôi chậm trễ.Vấn đề: các mô hình yêu cầu khác nhau cho dịch vụ tính năng gây ra một tải trọng lớn trên lớp gRPC và bộ nhớ cache. Sau đó, nhóm đã tối ưu hóa dịch vụ Feature. Phá vỡ thư viện bộ nhớ đệm (FastCache từ VictoriaMetrics) và thực hiện các bản ghi lô và loại bỏ tốt hơn để giảm sự tranh chấp mutex bằng 100x. Forked gprc-go và thực hiện bể đệm trên các kết nối khác nhau để tránh tranh chấp trong sự song song cao. Sử dụng các tham số tập hợp đối tượng và bộ sưu tập rác được điều chỉnh (GC) để giảm tỷ lệ phân bổ và chu kỳ GC. Với Envoy Proxy xử lý 15% lưu lượng truy cập trong Proof-of-concept của họ, kết quả rất hứa hẹn: tỷ lệ hit bộ nhớ cache 98%, làm giảm tải trọng trên ScyllaDB xuống còn 7,4M hàng / giây. Bài học học Đây là cách chuyến đi này trông như thế nào từ quan điểm thời gian: Để kết thúc, Andrei tóm tắt những bài học hàng đầu của nhóm đã học được từ dự án này (cho đến nay): Mặc dù nhóm ShareChat đã thay đổi đáng kể thiết kế hệ thống của họ, ScyllaDB, Apache Flink và VictoriaMetrics tiếp tục làm việc tốt. Mỗi tối ưu hóa là khó khăn hơn so với trước đó - và có tác động ít hơn. Các giải pháp đơn giản và thực tế (chẳng hạn như chia cửa hàng tính năng thành 27 triển khai) thực sự làm việc. Giải pháp cung cấp hiệu suất tốt nhất không phải lúc nào cũng thân thiện với người dùng. Ví dụ, sơ đồ cơ sở dữ liệu được sửa đổi của họ mang lại hiệu suất tốt, nhưng rất khó để duy trì và hiểu. Mỗi hệ thống là duy nhất.Đôi khi bạn có thể cần phải đúc một thư viện mặc định và điều chỉnh nó cho hệ thống cụ thể của bạn để có được hiệu suất tốt nhất. Xem toàn bộ P99 CONF nói chuyện của họ! Xem toàn bộ P99 CONF nói chuyện của họ! Xem toàn bộ P99 CONF nói chuyện của họ! Thông tin Cynthia Dunlop Cynthia là giám đốc quản lý chiến lược nội dung tại ScyllaDB. Cô đã viết về phát triển phần mềm và kỹ thuật chất lượng trong hơn 20 năm.