Kiến trúc của một công cụ tìm kiếm web quy mô lớn, vào khoảng năm 2019

[ad_1]

Trong các bài viết trước của loạt bài mạo hiểm này, chúng tôi đã mô tả một số công nghệ cung cấp năng lượng cho các sản phẩm tìm kiếm riêng tư của chúng tôi. Đó là khoảng thời gian mà chúng tôi giới thiệu các hệ thống mang mọi thứ lại với nhau. Điều quan trọng là phải hiểu rằng một công cụ tìm kiếm quy mô web rất phức tạp. Nó là một hệ thống phân tán với những hạn chế mạnh mẽ về hiệu suất và độ trễ. Trên hết, nó có thể dễ dàng trở nên cực kỳ tốn kém để vận hành; cả về nguồn nhân lực và tất nhiên là bằng tiền.

Bài viết này tìm hiểu về công nghệ mà chúng ta sử dụng ngày nay và một số lựa chọn và quyết định của chúng ta, đã được thực hiện và lặp đi lặp lại trong nhiều năm qua, để phục vụ cả bên ngoài và người dùng nội bộ.

Chủ đề trong tầm tay rất rộng và không thể được đề cập trong một lần ngồi, nhưng chúng tôi hy vọng sẽ cung cấp cho bạn ý chính của nó.

Chúng tôi sử dụng kết hợp mở nổi bật các công nghệ nguồn và đám mây được bọc bằng dụng cụ trồng tại nhà, đã được thử nghiệm trong trận chiến. Những nơi mà chúng tôi chưa tìm thấy giải pháp trong thế giới nguồn mở hoặc các nỗ lực thương mại, chúng tôi đã sẵn sàng lặn sâu và viết một số hệ thống cốt lõi từ đầu, hoạt động tốt cho chúng tôi ở quy mô của chúng tôi.

Tuyên bố miễn trừ trách nhiệm: Chúng tôi mô tả hệ thống của chúng tôi như thế nào, cho đến ngày hôm nay. Tất nhiên chúng tôi đã không bắt đầu như thế này. Chúng tôi đã có nhiều cuộc đại tu kiến ​​trúc trong suốt những năm qua, luôn xem xét các hạn chế như chi phí, lưu lượng truy cập và kích thước dữ liệu. Chúng tôi sẽ đề nghị rằng đây là một công thức để xây dựng một công cụ tìm kiếm; đó là những gì đang hoạt động ngày hôm nay, như những người khôn ngoan hơn đã nói:

Tối ưu hóa sớm là gốc rễ của tất cả tà ác ~ Donald Knuth

Và chúng tôi hoàn toàn đồng ý. Trên thực tế, chúng tôi thực sự khuyên bất cứ ai, đừng bao giờ cố gắng ném tất cả các thành phần vào nồi cùng một lúc. Nhưng thay vào đó để thêm từng cái một; từ từ và tăng dần độ phức tạp từng bước một.

Với bản chất của bài đăng này, chúng tôi muốn cung cấp một phác thảo có trật tự của tất cả các chủ đề được đề cập:

  • Tìm kiếm Cliqz như một sản phẩm và các yêu cầu hệ thống của nó.
  • Hệ thống tìm kiếm trên web: Một hệ thống tìm kiếm thực sự tự động và thời gian thực.
  • Nền tảng xử lý dữ liệu: Tạo thuận lợi cho việc lập chỉ mục hàng loạt và thời gian thực.
  • Làm thế nào triển khai đã được thực hiện trong quá khứ? Ưu điểm và nhược điểm của các cách tiếp cận khác nhau.
  • Kiến trúc microservice: Dịch vụ phối hợp có liên quan để cung cấp nội dung cho trang kết quả của công cụ tìm kiếm.
  • Nhu cầu sử dụng container và hệ thống điều phối container (Kubernetes) của chúng tôi.
  • Giới thiệu ngăn xếp Kubernetes của chúng tôi – Cách chúng tôi triển khai, chạy và quản lý Kubernetes và các tiện ích bổ sung khác nhau và các vấn đề họ giải quyết cho chúng tôi.
  • Phát triển cục bộ trên Kubernetes – Trường hợp kết thúc sử dụng.
  • Tối ưu hóa chi phí.
  • Hệ thống máy học.

Trải nghiệm tìm kiếm của chúng tôi tại Drop Drop & SERP

Công cụ tìm kiếm tại Cliqz có hai người tiêu dùng với các yêu cầu khác nhau.

Loại tìm kiếm

 Hình 1: Thả xuống Cliqz trong Trình duyệt "load =" lazy "src =" http : //www.0x65.dev/static/img/posts/arch architecture-of-larsh-scale-web-search-engine / ext.png "/> 
 
<figcaption> Figu re 1: Cliqz Dropdown in the Browser </figcaption></figure>
<p> Tìm kiếm trong thanh địa chỉ trình duyệt <sup class= [1] với kết quả có sẵn trên danh sách thả xuống. Loại tìm kiếm này yêu cầu ít kết quả hơn (thường là 3) nhưng cực kỳ nhạy cảm (dưới 150 ms); mặt khác, trải nghiệm người dùng bị ảnh hưởng.

Tìm kiếm trong SERP

 Hình 2: Trang kết quả của công cụ tìm kiếm Cliqz beta.cliqz.com "load =" lazy "src = "http://www.0x65.dev/static/img/posts/arch architecture-of-larsh-scale-web-search-engine / serp.gif" /> 
 
<figcaption> Hình 2: Trang kết quả của công cụ tìm kiếm Cliqz .cliqz.com </figcaption></figure>
<p> Tìm kiếm trên một trang web, trang kết quả của công cụ tìm kiếm thông thường mà mọi người đều biết. Ở đây, độ sâu của tìm kiếm không bị ràng buộc nhưng ít đòi hỏi về độ trễ (dưới 1000 ms ) so với phiên bản thả xuống. </p>
<h2> Tìm kiếm hoàn toàn tự động và gần thời gian thực </h2>
<p> Hãy xem xét một truy vấn như <em> ở vịnh bayern munich [</em>. Bây giờ, điều này có vẻ rất Truy vấn chung, nhưng khi được phát hành, nó chạm vào một số dịch vụ trong hệ thống của chúng tôi. Nếu chúng tôi cố gắng diễn giải ý định từ truy vấn, chúng tôi sẽ tìm ra rằng người dùng có thể là: </p>
<ul>
<li> Nghiên cứu về clu b (trong trường hợp một đoạn trích Wikipedia có liên quan) </li>
<li> Quan tâm đến việc đặt vé, mua hàng hóa, đăng ký làm người hâm mộ chính thức (Trang web chính thức) </li>
<li> Quan tâm đến tin tức hiện tại về câu lạc bộ:
<ul>
<li> Tin tức trước trận đấu về trò chơi </li>
<li> Thông tin trong trò chơi như: Điểm trực tiếp, Cập nhật trực tiếp hoặc Bình luận. </li>
<li> Phân tích sau trận đấu về trò chơi </li>
<li> ] Thông tin trái mùa về hoạt động bên trong của câu lạc bộ và hoạt động trong kỳ chuyển nhượng, thuê huấn luyện viên mới, vv </li>
</ul>
</li>
<li> Tìm kiếm các trang web và nội dung cũ, lịch sử câu lạc bộ, hồ sơ trò chơi trong quá khứ, vv </li>
</ul>
<p> Như người ta có thể quan sát, điều này nhiều hơn nhiều so với việc tìm các trang có liên quan. Thông tin không chỉ được yêu cầu có liên quan về mặt ngữ nghĩa mà còn phải phù hợp với thời gian w.r.t. Tính chính xác hoặc Độ nhạy tạm thời trong tìm kiếm là một yếu tố rất quan trọng đối với trải nghiệm người dùng. </p>
<p> Để biến điều này thành một trải nghiệm mạch lạc, thông tin phải được cung cấp từ các nguồn khác nhau và chuyển thành chỉ mục có thể tìm kiếm gần như thật thời gian. Chúng tôi cần đảm bảo rằng tất cả các mô hình, chỉ mục và tài sản đều được cập nhật (ví dụ: Tải hình ảnh phải phản ánh các sự kiện hiện tại và giữ cho tiêu đề và nội dung được cập nhật liên quan đến câu chuyện đang phát triển). <strong> Khó có thể thực hiện thành công ở quy mô, chúng tôi tin tưởng mạnh mẽ rằng người dùng của chúng tôi phải luôn được cung cấp thông tin cập nhật, trực giác này tạo thành nền tảng cho kiến ​​trúc hệ thống tổng thể của chúng tôi. </strong> </p>
<p> Nền tảng xử lý và phục vụ dữ liệu tại Cliqz tuân theo Kiến trúc Lambda nhiều tầng. Nó bao gồm ba tầng dựa trên độ chính xác của nội dung được lập chỉ mục. Đó là: </p>
<ol>
<li>
<p> <strong> Gần như lập chỉ mục thời gian thực </strong> </p>
<ul>
<li> Hoàn toàn tự động và được cung cấp bằng Kafka (Nhà sản xuất, Người tiêu dùng và Bộ xử lý dòng) Cassandra, Granne <sup class= [2] và RocksDB.
  • Cassandra lưu trữ dữ liệu Index trong các bảng khác nhau. Các bản ghi trong các bảng khác nhau có Thời gian sống (TTL) khác nhau, vì vậy chúng tôi có thể giải phóng bộ nhớ khi dữ liệu được lập chỉ mục lại trong các giai đoạn sau.
  • Thành phần này cũng chịu trách nhiệm cho các tính năng xếp hạng theo xu hướng hoặc phổ biến của chúng tôi giúp xác định xu hướng trên một cửa sổ chuyển động với các kích cỡ thời gian khác nhau. Chúng tôi thực hiện điều này thông qua xử lý luồng bằng KafkaStreams.
  • Tất cả điều này chuyển thành các tính năng của sản phẩm bao gồm nội dung gần đây trong kết quả tìm kiếm và tin tức hàng đầu.
  • hoặc Lập chỉ mục hàng loạt dựa trên cửa sổ trượt

    • Dựa trên nội dung của 60 ngày qua.
    • Được lập chỉ mục lại hàng tuần (Kết thúc các đường ống tự động của công việc hàng loạt trên Jenkins)
    • Đường ống dữ liệu và máy học được thực hiện dựa trên dữ liệu gần đây dẫn đến chất lượng kết quả tìm kiếm của chúng tôi cao hơn.
    • Một khung tốt để kiểm tra và tạo nguyên mẫu cho các mô hình ML mới và thay đổi thuật toán bằng cách sử dụng tập hợp dữ liệu do đó giảm chi phí cho các thử nghiệm từ đầu đến cuối trên toàn bộ dữ liệu.
    • Luồng công việc hàng loạt dựa trên Map-Giảm và Spark được quản lý thông qua Luigi và được quản lý lại bằng cách sử dụng Jenkins Pipelines.
    • Keyvi, Cassandra, qpick và Granne cho phục vụ.
  • Chỉ số hàng loạt đầy đủ

    • Dựa trên tất cả dữ liệu có sẵn
    • Lập chỉ mục lại: 2 tháng một lần
    • Luồng công việc hàng loạt dựa trên MapReduce và Spark được quản lý thông qua Luigi
    • Được sử dụng để đào tạo Mô hình học máy quy mô lớn trên một tập dữ liệu lớn. ví dụ: Truy vấn và nhúng từ, Mô hình hàng xóm gần nhất, Mô hình ngôn ngữ, v.v …
    • Keyvi, Cassandra, qpick và Granne để phục vụ
  • lưu ý ở đây là, Chỉ số hàng tuần và Thời gian thực chịu trách nhiệm cho một phần lớn nội dung liên quan đến tìm kiếm được phục vụ trên SERP. Đây là một hành vi tương tự như các công cụ tìm kiếm khác nhằm quảng bá nội dung gần đây về nội dung lịch sử về chủ đề này. Chỉ mục lô đang xử lý các truy vấn độc lập về thời gian, đuôi dài của các truy vấn và nội dung hiếm gặp, mang tính lịch sử hoặc khó hiểu trong bối cảnh hiểu một truy vấn tìm kiếm. Sự kết hợp của cả ba cho chúng ta đạn dược cần thiết để xây dựng tìm kiếm Cliqz ở dạng hiện tại. Tuy nhiên, tất cả các hệ thống đều có khả năng trả lời tất cả các truy vấn, tuy nhiên, kết quả cuối cùng là kết hợp của tất cả các chỉ mục.

    Triển khai Bối cảnh lịch sử

    thành thạo một công cụ cho đến khi bạn hiểu khi nào nó không nên được sử dụng. ~ Kelsey Hightower

    Ngay từ đầu, chúng tôi đã tập trung vào việc cung cấp dịch vụ tìm kiếm của mình bằng cách sử dụng nhà cung cấp đám mây công cộng thay vì quản lý cơ sở hạ tầng tại chỗ. Trong thập kỷ qua, điều đó đã trở thành chuẩn mực trong toàn ngành, do sự phức tạp và nguồn lực cần thiết để vận hành (các) trung tâm dữ liệu riêng của một so với sự dễ dàng tương đối của các dịch vụ lưu trữ và dễ dàng tiêu hóa khi bạn làm mô hình khởi nghiệp. Amazon Web Services (AWS) [3] đã thuận tiện cho chúng tôi vì nó cho phép chúng tôi tự trừu tượng khỏi việc quản lý máy móc và cơ sở hạ tầng của chính mình. Nếu không tham gia AWS, chúng tôi sẽ phải nỗ lực hơn rất nhiều để đạt đến giai đoạn này. (Nhưng, chúng tiện lợi như đắt tiền. Bạn sẽ thấy trong bài viết này một số thủ thuật chúng tôi đã đưa ra để giảm chi phí, nhưng chúng tôi khuyên bạn nên cực kỳ cẩn thận khi sử dụng các dịch vụ đám mây ở quy mô.)

    Chúng tôi thường cố gắng tránh việc cung cấp dịch vụ có quản lý có thể hữu ích cho chúng tôi vì chi phí có thể cao không thể chịu được ở quy mô chúng tôi thường hoạt động. Để mang đến một số bối cảnh, chúng ta hãy bắt đầu từ năm 2014. Một mối quan tâm ngày càng tăng mà chúng ta gặp sớm là cung cấp tài nguyên và triển khai các ứng dụng trên AWS.

    Chúng tôi bắt đầu với nỗ lực xây dựng cơ sở hạ tầng và cấu hình của riêng mình hệ thống quản lý trên AWS. Chúng tôi tập trung vào việc vận chuyển một giải pháp có nguồn gốc từ python để dễ dàng cho nhà phát triển lên máy bay. Chúng tôi đã gói dự án Fabric và kết hợp nó với Boto để cung cấp các giao diện đẹp để khởi động máy và định cấu hình ứng dụng của một vài dòng mã được điều khiển thông qua một triển khai tập tin cùng nằm với nguồn dịch vụ. Điều này sau đó được gói vào các trình tạo mẫu dự án để dễ dàng đưa lên các dự án mới. Trước đó, đó là những ngày đầu của docker và theo truyền thống, chúng tôi đã vận chuyển dưới dạng các gói python hoặc mã python đơn giản, đó là một thách thức vì quản lý phụ thuộc. Mặc dù dự án đã đạt được rất nhiều lực kéo và được sử dụng bởi nhiều dịch vụ điều khiển nhiều sản phẩm tại Cliqz, nhưng chắc chắn có những điều mà một thư viện hướng đến cơ sở hạ tầng và quản lý cấu hình thiếu. Quản lý nhà nước toàn cầu, khóa trung tâm để thay đổi thông tin, không có quan điểm trung tâm về tài nguyên đám mây được sử dụng bởi dự án hoặc nhà phát triển, phụ thuộc vào các công cụ bên ngoài để dọn sạch tài nguyên mồ côi, quản lý cấu hình hạn chế, khả năng quan sát hạn chế trong sử dụng của nhà phát triển công cụ là một số trong những thứ tạo ra ma sát và từ đó dẫn đến sự phức tạp hoạt động tăng lên.

    Điều này khiến chúng tôi khám phá các giải pháp bên ngoài thay thế khi các nỗ lực trong nhà phải dừng lại do nguồn lực hạn chế. Giải pháp thay thế cuối cùng chúng tôi đã tìm ra là sự kết hợp của các giải pháp từ Hashicorp bao gồm Consul, Terraform và Packer và cuối cùng là công cụ quản lý cấu hình như Ansible Salt .

    Terraform đã trình bày một cách tiếp cận khai báo tuyệt vời để quản lý cơ sở hạ tầng mà nhiều công nghệ hiện tại trong không gian bản địa đám mây đã tận dụng. Vì vậy, chúng tôi đã quyết định, sau khi đánh giá cẩn thận, sẽ nghỉ hưu thư viện triển khai dựa trên fab của chúng tôi cho Terraform. Bên cạnh những ưu và nhược điểm kỹ thuật, người ta luôn phải xem xét các yếu tố con người. Một số nhóm chậm chấp nhận các thay đổi so với các thay đổi khác, có thể là do thiếu tài nguyên hoặc do chi phí chuyển đổi không đồng nhất. Đối với chúng tôi, phải mất một thời gian dài, khoảng một năm, để di chuyển.

    Terraform chắc chắn đã mang đến cho chúng tôi một số tính năng mà chúng tôi đã bỏ lỡ trong dự án triển khai cũ của chúng tôi, bao gồm:

    • Quản lý cơ sở hạ tầng nhà nước trung ương.
    • Kế hoạch Verbose, vá và áp dụng hỗ trợ.
    • Dễ dàng phá vỡ tài nguyên với tài nguyên mồ côi tối thiểu.
    • Hỗ trợ cho nhiều đám mây.

    Trong khi đó, chúng tôi cũng phải đối mặt với một số thách thức trong hành trình của chúng tôi với Terraform:

    • DSL cụ thể là đám mây cụ thể DRY.
    • Khó khăn để bọc nó trong các công cụ khác.
    • Hỗ trợ tạo khuôn mẫu hạn chế và đôi khi phức tạp.
    • Không có phản hồi về sức khỏe của dịch vụ.
    • Không rollback dễ dàng.
    • Thiếu các tính năng quan trọng được thực hiện bởi các bên thứ ba như terragrunt.

    Terraform chắc chắn có chỗ đứng tại Cliqz và ngày nay chúng tôi vẫn sử dụng nó để triển khai hầu hết cơ sở hạ tầng Kubernetes của chúng tôi.

    Những rắc rối của hệ thống tìm kiếm

    3: Tổng quan về tìm kiếm "load =" lazy "src =" http://www.0x65.dev/static/img/posts/arch architecture-of-larsh-scale-web-search-engine / fuse_overview.png "/>
    Hình 3: Tổng quan về tìm kiếm

    Trong nhiều năm qua, chúng tôi đã chuyển từ một kiến ​​trúc phân tán, với hàng tá máy chủ, sang kiến ​​trúc nguyên khối, cuối cùng kết thúc trên kiến ​​trúc microservice.

    Mỗi giải pháp mà chúng tôi tin là thuận tiện nhất vào thời điểm đó, dựa trên các tài nguyên có sẵn; chẳng hạn, phiên bản nguyên khối là do phần lớn độ trễ của chúng tôi đã thoát khỏi mạng IO trong số các máy của cụm. Vào thời điểm đó, AWS đã ra mắt X1 Instance, với RAM 2 TB. Một sự thay đổi nhanh chóng về kiến ​​trúc cho phép chúng tôi giảm độ trễ một cách nhanh chóng, nhưng tất nhiên, chi phí đã tăng lên. Lặp lại tiếp theo về kiến ​​trúc, chúng tôi tập trung vào chi phí. Từng bước chúng tôi đã cố gắng sửa một biến mà không làm xấu đi các biến khác. Nó có thể trông không giống một cách tiếp cận rất lạ mắt, nhưng nó hoạt động tốt với chúng tôi.

    Phong cách kiến ​​trúc microservice là một cách tiếp cận để phát triển một ứng dụng như một bộ dịch vụ nhỏ, mỗi dịch vụ đều tự chạy xử lý và giao tiếp với các cơ chế nhẹ, thường là API tài nguyên HTTP. ~ Martin Fowler

    Định nghĩa microservice của Martin Fowler là đúng về mặt kỹ thuật, nhưng hơi trừu tượng. Đối với chúng tôi, nó thường không cung cấp đủ mô tả về cách xây dựng và cân đối chính xác các dịch vụ siêu nhỏ của bạn, đây là những mối quan tâm quan trọng. Việc chuyển sang microservice mang lại cho chúng tôi:

    • Tính mô đun và tự chủ tốt hơn của các nhóm và phân tách các mối quan tâm.
    • Khả năng mở rộng theo chiều ngang và phân vùng khối lượng công việc.
    • Cách ly lỗi và hỗ trợ tốt hơn. cho nhiều ngôn ngữ.
    • Đa thuê nhà và nói chung là một dấu chân bảo mật tốt hơn.
    • Tự động hóa tốt hơn trong hoạt động.

    Nhìn vào một bức tranh rộng lớn về kiến ​​trúc và cách thức chúng tôi cấu trúc microservice của chúng tôi khi một truy vấn tìm kiếm được đưa ra cho phụ trợ, một số dịch vụ được kích hoạt trong đường dẫn yêu cầu. Mỗi dịch vụ được coi là một dịch vụ siêu nhỏ theo nghĩa nó có sự phân tách mối quan tâm, được điều khiển bởi một giao thức nhẹ (REST / GRPC) và có thể mở rộng theo chiều ngang. Mỗi dịch vụ có thể được cấu thành từ các dịch vụ siêu nhỏ riêng lẻ và có thể có một lớp kiên trì. Đường dẫn yêu cầu thường bao gồm:

    • Tường lửa ứng dụng web (WAF) – Tường lửa ứng dụng chống lại các khai thác web phổ biến.
    • Tải cân bằng Yêu cầu nhập và cân bằng tải.
    • Nhập vào proxy – Định tuyến, quan sát cạnh, khám phá, thực thi chính sách.
    • Eagle .
    • Fuse – Cổng API, bộ trộn kết quả, bộ đệm cạnh, xác thực / ủy quyền.
    • Đề xuất – Đề xuất truy vấn [4] .
    • Xếp hạng [5] – Phục vụ kết quả tìm kiếm bằng chỉ mục gần thời gian thực và chỉ số lô được biên dịch trước (Kiến trúc Lambda).
    • Kết quả phong phú [6] – Thêm thông tin phong phú như đoạn trích cho thời tiết, trực tiếp res, các nguồn bên thứ ba khác.
    • Sơ đồ tri thức và câu trả lời tức thì – Đến thông tin điểm liên quan đến truy vấn.
    • Địa điểm – Geo- Đề xuất nội dung dựa trên địa phương.
    • Tin tức – Nội dung thời gian thực từ các nguồn tin tức có uy tín.
    • Tracker – Thông tin theo dõi tên miền cụ thể qua WhoTracks.me
    • Hình ảnh – Kết quả hình ảnh liên quan đến truy vấn của người dùng.

    Tất cả các dịch vụ này được bố trí thông qua một cổng API chung chịu trách nhiệm xử lý khối lượng tìm kiếm cũng được trang bị với các tính năng như cung cấp bảo vệ xung quanh lưu lượng truy cập tăng, Tự động mở rộng dựa trên yêu cầu / cpu / bộ nhớ / sử dụng số liệu tùy chỉnh, bộ nhớ đệm cạnh, đổ bóng và chia tách lưu lượng, Thử nghiệm A / B [7] Blue-Green [8] triển khai, phát hành Canary [9] v.v. Nền tảng này cũng chịu trách nhiệm cung cấp nhiều chức năng này cho các dịch vụ đang hoạt động.

    Hệ thống điều phối container và container Docker

    Cho đến nay, chúng tôi đã mô tả một số yêu cầu và chi tiết cụ thể về chúng tôi cung cấp sản phẩm. Chúng tôi đã mô tả cách chúng tôi đã triển khai và những thiếu sót với các giải pháp mà chúng tôi đã thử. Với những kiến ​​thức này, chúng tôi đã chọn Docker, là khối xây dựng cơ bản cho tất cả các dịch vụ của chúng tôi. Chúng tôi bắt đầu phân phối mã của mình bằng cách sử dụng các thùng chứa docker, thay vì sử dụng các máy ảo đơn giản với mã và phụ thuộc. Với docker, mã và các phụ thuộc của nó được chuyển dưới dạng hình ảnh docker đến cơ quan đăng ký container (ECR).

    Nhưng một khi các dịch vụ bắt đầu phát triển trở lại, cần phải quản lý chúng, đặc biệt là khi chúng tôi muốn mở rộng chúng sản xuất. Trong những năm qua, chúng tôi đã phải giới thiệu một hệ thống điều phối container. Các điểm đau dẫn đến việc giới thiệu thường là lãng phí tài nguyên tính toán về cơ sở hạ tầng quản lý cấu hình.

    Chúng tôi luôn thiếu con người và về sức mạnh tính toán, đây là một tình huống được chia sẻ bởi hầu hết các công ty mới khởi nghiệp với nguồn lực hạn chế. Tất nhiên, để có hiệu quả, chúng ta phải tập trung vào giải quyết các vấn đề mà chúng ta có, điều đó không thể giải quyết bằng các công cụ đã tồn tại. Nhưng, chúng tôi không tin vào việc phát minh lại bánh xe (cho đến khi nó thay đổi hoàn toàn cảnh quan hiện có). Chúng tôi là những người sử dụng phần mềm nguồn mở, nơi chúng tôi tìm thấy giải pháp cho các vấn đề kinh doanh quan trọng của mình.

    Chúng tôi bắt đầu đánh giá Kubernetes [10] (k8s) ngay khi phiên bản 1.0 được phát hành và có khối lượng công việc ở mức sản xuất chạy 1,4 1.4 khi dự án cho thấy sự ổn định và trưởng thành trong công cụ. Đồng thời, chúng tôi đã đánh giá các hệ thống điều phối khác bao gồm Apache Mesos và Docker Swarm cho các dự án quy mô lớn của chúng tôi như trình tải xuống (trình thu thập quy mô web). Cuối cùng chúng tôi đã tiếp tục điều hành mọi thứ với Kubernetes, vì rõ ràng là dự án đã cho thấy sự hứa hẹn trong việc tiếp cận chặt chẽ để giải quyết việc điều phối và quản lý cấu hình trong khi những người khác thì không, và cũng bao gồm sự hỗ trợ cộng đồng mạnh mẽ.

    Kubernetes – Ngăn xếp Cliqz

     Hình 4: OSS atCliqz "load =" lazy "src =" http://www.0x65.dev/static/img/posts/arch architecture-of-larsh- scale-web-search-engine / tech.jpg "/> 
 
<figcaption> Hình 4: OSS tại Cliqz </figcaption></figure>
<blockquote>
<p> Nguồn mở đã giành chiến thắng! </p>
</blockquote>
<p> Cliqz phụ thuộc rất nhiều vào nhiều dự án Phần mềm nguồn mở (OSS) thường nằm dưới sự bảo trợ của Tổ chức điện toán đám mây <sup class= [11] để cung cấp trải nghiệm bản địa đám mây gắn kết. Chúng tôi cố gắng hết sức để đóng góp lại cho cộng đồng về mã, bài đăng trên blog và trên các kênh khác bao gồm cả chùng. Chúng tôi sẽ chia sẻ chi tiết về việc sử dụng một số hệ điều hành quan trọng Các dự án tạo thành cốt lõi của ngăn xếp của chúng tôi:

    KOPS cố Kubernetes Dàn nhạc

    Để điều phối container, chúng tôi tự quản lý các cụm Kubernetes đa vùng bằng cách sử dụng công cụ KOPS và một số công cụ gia đình. trên cùng để quản lý vòng đời cụm và quản lý addon. Hét lên Justin Santa Barbara và kops duy trì công việc tuyệt vời của họ, cung cấp trải nghiệm tích hợp tốt trong việc đưa lên các nút điều khiển máy bay và công nhân k8s theo cách phù hợp. Hiện tại chúng tôi không dựa vào việc cung cấp có quản lý chỉ vì tính linh hoạt của KOPS và thiếu trưởng thành trong EKS, máy bay điều khiển k8s do AWS quản lý.

    Sử dụng KOPS và tự quản lý một cụm có nghĩa là chúng tôi thực sự có thể thiết lập theo tốc độ của chúng tôi, lặn sâu hơn trong quá trình khắc phục sự cố, kích hoạt các tính năng là yêu cầu ứng dụng nhưng chỉ có trong các bản phát hành Kubernetes cụ thể. Nếu chúng tôi đã chờ đợi một dịch vụ đám mây, chúng tôi sẽ phải chờ một thời gian dài hơn đáng kể để đạt đến giai đoạn mà chúng tôi có bây giờ.

    Lớp phủ mạng lưới dệt

    Điều quan trọng cần lưu ý là Kubernetes giúp trừu tượng hóa tất cả các phần của hệ thống. Điều này không chỉ bao gồm tính toán và lưu trữ, mà còn kết nối mạng. Đối với các cụm của chúng tôi có thể phát triển lên hàng trăm nút, chúng tôi sử dụng mạng lớp phủ tạo thành xương sống để cung cấp khả năng thực thi chính sách mạng và mạng phẳng cho các nhóm sinh sản trên nhiều nút, vùng khả dụng và vùng. Mạng lưới dệt là lớp phủ của sự lựa chọn mà chúng tôi đã đến sớm vì khả năng quản lý và quản lý tuyến đường dễ dàng thông qua tin đồn. Khi chúng ta phát triển lớn hơn, chúng ta có thể chuyển sang AWS VPC CNI và Calico khi chúng trưởng thành để cung cấp ít bước nhảy mạng hơn và nhất quán hơn trong việc định tuyến và lưu lượng. Cho đến bây giờ, mạng lưới dệt đã thực hiện một cách mẫu mực trong các mục tiêu về độ trễ và thông lượng của chúng tôi và không có lý do gì để chuyển đổi.

    Quản lý và phân phối gói Helm / Helmfile

    Chúng tôi đã dựa vào helm (v2) từ đầu cho gói và quản lý phát hành các bản kê khai Kubernetes. Mặc dù nó có những điểm đau đớn, chúng tôi thấy nó là một nguồn tài nguyên tuyệt vời để quản lý phát hành và tạo khuôn mẫu. Chúng tôi tuân theo một cấu trúc kho lưu trữ duy nhất cho biểu đồ helm của tất cả các dịch vụ của chúng tôi được đóng gói và phục vụ bằng dự án chartmuseum. Các giá trị cụ thể của môi trường sau đó được giữ trong một kho lưu trữ riêng để tách các mối quan tâm. Chúng được điều khiển bằng cách sử dụng mẫu gitOps thông qua Helmfile, cung cấp cách tiếp cận khai báo cho nhiều quản lý phát hành biểu đồ helm và các plugin thiết yếu liên quan như quản lý diff, tillerless và bí mật trong phần còn lại với SOPS. Các thay đổi đối với kho lưu trữ này được xác thực và triển khai bằng cách sử dụng các đường ống CI / CD được điều khiển thông qua Jenkins.

    Tilt / K9s. Không có sự phát triển Kubernetes cục bộ

    Một trong những vấn đề chúng tôi gặp phải ban đầu là: Làm thế nào tốt nhất để đưa k8 vào vòng lặp bên trong của vòng đời phát triển của nhà phát triển. Một số yêu cầu nhanh chóng rõ ràng. Cách xây dựng và đồng bộ mã vào các thùng chứa và thực hiện nhanh nhất có thể. Ban đầu, chúng tôi có một giải pháp cây nhà đơn giản để tham gia vào các sự kiện hệ thống tập tin về thay đổi nguồn và chỉ cần đồng bộ hóa mọi thứ với các thùng chứa. Chúng tôi cũng đã thử nghiệm các dự án bao gồm Skaffold từ Google và Dự thảo từ Microsoft đang cố gắng giải quyết các vấn đề tương tự. Cuối cùng, những gì làm việc cho chúng tôi là Tilt from Windmill Engineering (hét to Daniel Bentley), người có một sản phẩm tuyệt vời trên tay với một quy trình làm việc được điều khiển bởi Tiltfile được viết bằng ngôn ngữ starlark. Nó có thể xem các tệp để chỉnh sửa, có thể tự động áp dụng các thay đổi, xây dựng hình ảnh trong thời gian thực, xây dựng nhanh hơn với các bản dựng cụm và bỏ qua các đăng ký và có một giao diện người dùng đẹp để xem tất cả thông tin về các dịch vụ của bạn trong một khung, v.v. Và khi bạn muốn tìm hiểu sâu hơn một chút, chúng tôi sẽ mở nitty gritty của k8 thông qua một công cụ CLI tuyệt vời có tên K9 để chạy các lệnh k9s một cách tương tác và đơn giản hóa quy trình làm việc của nhà phát triển. Ngày nay, tất cả các khối lượng công việc của chúng tôi chạy trong k8 được phát triển theo cụm với kinh nghiệm gắn kết và nhanh chóng qua các dự án nhờ helm / tilt / k9 và bất kỳ ai mới tham gia đều có thể dễ dàng tham gia với một vài lệnh.

    Prometheus , AlertManager, Jaeger, Grafana và Loki, Khả năng quan sát

    Chúng tôi phụ thuộc rất nhiều vào giải pháp theo dõi Prometheus và cơ sở dữ liệu chuỗi thời gian (tsdb) để thu thập, tổng hợp và chuyển tiếp các số liệu của chúng tôi. Prometheus xuất xưởng với ngôn ngữ truy vấn tuyệt vời PromQl và giải pháp cảnh báo Trình quản lý cảnh báo. Jaeger tạo thành xương sống cho tập hợp dấu vết của chúng tôi. Gần đây, chúng tôi đã bắt đầu chuyển từ Graylog sang Loki làm phụ trợ đăng nhập để cung cấp trải nghiệm tương tự như Prometheus. Tất cả điều này được thực hiện để cung cấp một ô kính duy nhất trong đó tất cả các yêu cầu về khả năng quan sát có thể được đáp ứng và chúng tôi dự định sẽ cung cấp điều đó với Grafana, đó là giải pháp biểu đồ của chúng tôi. Để phối hợp tất cả các dịch vụ này, chúng tôi phụ thuộc rất nhiều vào dự án Nhà khai thác Prometheus với các tích hợp trên cùng để quản lý vòng đời của nhiều triển khai Prometheus nhiều khách thuê mà chúng tôi có ngày nay. Tại bất kỳ thời điểm nào, chúng tôi sử dụng hàng trăm nghìn chuỗi thời gian để thu thập thông tin chuyên sâu về việc vận hành cơ sở hạ tầng và dịch vụ để hỗ trợ khi có sự cố.

    Trong tương lai, chúng tôi dự định tích hợp dự án Thanos hoặc Cortex để giải quyết các thách thức về khả năng mở rộng của Prometheus và cung cấp chế độ xem truy vấn toàn cầu, tính sẵn sàng cao và sao lưu dữ liệu để phân tích lịch sử.

    Luigi và Jenkins, Tự động hóa đường ống dữ liệu

    Chúng tôi sử dụng Luigi và Jenkins để phối hợp và tự động hóa đường ống dữ liệu của chúng tôi. Các công việc hàng loạt được gửi qua các bước tới EMR và Luigi giúp chúng tôi xây dựng các quy trình công việc hàng loạt rất phức tạp trên đầu các công việc này. Jenkins được sử dụng để kích hoạt một loạt các hoạt động trong quá trình ETL cung cấp cho chúng tôi quyền kiểm soát tự động hóa và sử dụng tài nguyên, được thực hiện theo nhiệm vụ riêng lẻ.

    Chúng tôi đóng gói và phiên bản mã công việc hàng loạt của chúng tôi trong các container docker phiên bản, để giữ một nhà phát triển và kinh nghiệm sản xuất nhất quán.

    Dự án Addon

    Chúng tôi cũng bao gồm nhiều dự án khác được phát triển bởi cộng đồng, được phân phối dưới dạng addons và được duy trì như một phần của vòng đời cụm để cung cấp giá trị cho các dịch vụ được triển khai cả trong môi trường sản xuất và phát triển. Chúng tôi thảo luận về chúng một cách ngắn gọn dưới đây:

    • Argo Workflow và CD ChuyệnEvaluating như một sự thay thế cho Jenkins cho nhiệm vụ xử lý hàng loạt và nỗ lực triển khai liên tục.
    • AWS IAM Authenticator Tập tin quản lý danh tính người dùng trong k8s.
    • ChartMuseum Chuyện bảo vệ biểu đồ helm từ xa của chúng tôi.
    • của các đội tàu theo yêu cầu và tại chỗ trong các cụm của chúng tôi.
    • Autoscaler dọc [[19900900]] Các thang đo chính xác ở các vị trí cần thiết hoặc dựa trên các số liệu tùy chỉnh.
    • ] Lưu trữStateState cho nhiều dự án, nơi chúng tôi có thể cố gắng chuyển sang Định nghĩa tài nguyên tùy chỉnh (CRDs).
    • DNS bên ngoài Bản ghi DNSMapsMaps sang Route53 để truy cập bên ngoài và bên trong.
    • Kube Downscaler triển khai triển khai và nhà nước Chúng không còn được sử dụng nữa.
    • Kube2IAM proxyTransparent proxy để hạn chế quyền truy cập siêu dữ liệu và quản lý vai trò cho các nhóm.
    • Loki / Promtail Tổng hợp và giao hàng của tập đoàn logLog.
    • Máy chủ Metrics Tập hợp và giao tiếp với nhau cho người tiêu dùng khác.
    • Nginx Ingress dịch vụ. Chúng tôi tiếp tục đánh giá các bộ điều khiển xâm nhập khác cho các chức năng cổng API mở rộng bao gồm Gloo, Istio ingress gateway và Kong.
    • Người quản lý RBAC Toán tử điều khiển dễ dàng quản lý Kiểm soát truy cập dựa trên vai trò đối với tài nguyên của k8s.
    • Trình xử lý chấm dứt tại chỗ nút dây và thoát nước.
    • Istio Chúng tôi tiếp tục đánh giá Istio về khả năng quan sát, định tuyến, định tuyến giao thông và định hình giao thông. Đối với nhiều tính năng này, chúng tôi đã xây dựng các giải pháp nội bộ, đã cho thấy những hạn chế theo thời gian, mà chúng tôi dự định sẽ thực hiện với dự án tuyệt vời này.

    us to not only ship our core stateless services providing search, but also helped us run large and critical stateful workloads like Cassandra, Kafka, Memcached and RocksDB in multiple availability zones and clusters, for high availability and replication. We have developed additional tooling to manage and safely execute these workload for our scale within Kubernetes.

    Local Development with Tilt—An end to end use case.

    So far we covered a lot of ground describing all the tools we use, but we would like to give a concrete example on how this tooling, well, parts of it, is affecting the typical day-to-day workflow of our developers.

    Let us take the example of an engineer working on Ranking. Previously, the workflow was:

    1. Start a spot instance with a custom OS image, tag instance and associated resources with ownership information.
    2. Rsync application code to the instance and install application dependencies.
    3. Figure out setting up other services like api-gateway and front-end, their dependencies and deployments.
    4. Configure them to work well with one another.
    5. Start working on the Ranking application.
    6. At the end, once done, make sure to terminate the instance.

    We can see that, one needs to follow a series of steps repeatedly, over and over again and every new engineer in the team will have to repeat it, which is a total waste of developer productivity. If the instance is lost we repeat. Also there is a stark difference between the production and local development workflow, leading to inconsistencies at some point of time. One might also argue the need for setting up other services like front-end along with ranking, but aim is to be generic here and in addition its always good to have complete visibility of the product. Additionally, as the team size grows, more cloud resources are created and more resources are under-utilized. Engineers let instances run, because they don’t want to redo the setup process every day. If a team member leaves and has an orphan instance without sufficient tags, it is a challenge to identify whether or not it is safe to turn off the instance and delete said cloud resources.

    What would be ideal, is to provide an engineer with a base template to set up local environment with his own full version of SERP along with other services responsible for ranking. We configure the base template generically, which tags resources created by the user with thier unique identifier names and allows them to control the life-cycle of their application. As K8s already abstract out need to launch instances and managing them (we centrally administer them using KOPS), we use the template to set defaults (auto downscaling during non-work hours) and hence tremendously reduce costs.

    All the user now has to care about is the code written in his local editor and our tooling which is composed of a combination of Docker, Helm and Tilt on top of Kubernetes facilitates this said workflow, working behind the scenes like magic.

    Here is an example Tiltfile, which describes the services and other dependent services required to setup a mini-SERP version. For launching these services in development mode, all the user has to do is run: tilt up

    # -*- mode: Python -*-
    
    """
    This Tiltfile manages 1 primary service which depends on a number of other micro services.
    Also, it makes it easier to launch some extra ancilliary services which may be
    useful during development.
    Here's a quick rundown of these services and their properties:
    * ranking: Handles ranking
    * api-gateway: API Gateway for frontend
    * frontend: Server Side Rendering for SERP
    
    """
    
    ####################
    # Project defaults #
    ####################
    
    project = "some-project"
    namespace = "some-namespace"
    chart_name = "some-project-chart"
    deploy_path = "../../deploy"
    charts_path = "{}/charts".format(deploy_path)
    chart_path = "{}/{}".format(charts_path, chart_name)
    values_path = "{}/some-project/services/development.yaml".format(deploy_path)
    secrets_path = "{}/some-project/services/secrets.yaml".format(deploy_path)
    secrets_dec_path = "{}/some-project/services/secrets.yaml.dec".format(deploy_path)
    chart_version = "X.X.X"
    
    # Load tiltfile library
    load("../../libs/tilt/Tiltfile""validate_environment")
    env = validate_environment(project, namespace)
    
    # Docker repository path for components
    serving_image = env["docker_registry"] + "/some-repo/services/some-project/serving"
    
    ####################################
    # Build services and deploy to k8s #
    ####################################
    
    # Watch development values file for helm chart to re-execute Tiltfile in case of changes
    watch_file(values_path)
    
    # Build docker images
    # Uncomment the live_update part if you wish to use the live_update function
    # i.e., no container restarts while developing. Ex: Using Python debugging
    docker_build(serving_image, "serving"dockerfile="./serving/Dockerfile"build_args={"PIP_INDEX_URL": env["pip_index_url"]"AWS_REGION": env["region"]} #, live_update=[sync('serving/src/', '/some-project/'),]
    )
    
    # Update local helm repos list
    local("helm repo update")
    
    # Remove old download chart in case of changes
    local("rm -rf {}".format(chart_path))
    
    # Decrypt secrets
    local("export HELM_TILLER_SILENT=true && helm tiller run {} -- helm secrets dec {}".format(namespace, secrets_path))
    
    # Convert helm chart to standard k8s manifests
    template_script = "helm fetch {}/{} --version {} --untar --untardir {} && helm template {} --namespace {} --name {} -f {} -f {}".format(env["chart_repo"]chart_name, chart_version, charts_path, chart_path, namespace, env["release_name"]values_path, secrets_dec_path)
    yaml_blob = local(template_script)
    
    # Clean secrets file
    local("rm {}".format(secrets_dec_path))
    
    # Deploy k8s manifests
    k8s_yaml(yaml_blob)
    
    dev_config = read_yaml(values_path)
    
    # Port-forward specific resources
    k8s_resource('{}-{}'.format(env["release_name"]'ranking'), port_forwards=['XXXX:XXXX']new_name="short-name-1")
    k8s_resource('{}-{}'.format(env["release_name"]'some-project-2'), new_name="short-name-2")
    
    if dev_config.get('api-gateway'{}).get('enabled'False):
      k8s_resource('{}-{}'.format(env["release_name"]'some-project-3'), port_forwards=['XXXX:XXXX']new_name="short-name-3")
    
    if dev_config.get('frontend'{}).get('enabled'False):
      k8s_resource('{}-{}'.format(env["release_name"]'some-project-4-1'), port_forwards=['XXXX:XXXX']new_name="short-name-4-1")
      k8s_resource('{}-{}'.format(env["release_name"]'some-project-4-2'), new_name="short-name-4-2")
    
    
    

    Notes:

    1. Helm charts are primarily responsible for the application packaging and managing their release lifecyle. We use helm templating and the use of customizable yamls for providing values to these templates. This allows us to configure releases to their very core. This includes allocating resources to containers, allowing an easy way to configure which services they connect to, the ports on which they can run, etc.

    2. Tilt is used to setup the local k8s development environment with the provided helm charts and mapping local code to the services described in the charts. It provides functionality where we can continuously build docker container and deploy application to k8s or perform a local update (rsync local changes into a running container). One can also port forward the application to his local instance to access the service end-point while developing. In our case, we deploy using the k8s manifest by extracting the rendered template from the helm chart. This was due to our complex chart requirements where we are unable to fully utilize the helm functions provided with Tilt.

    3. If the application endpoint needs to be shared with other team members, the charts provide a uniform mechanism to create internal ingress endpoints.

    4. Our charts are served via the common helm charts repository, thus in production and development, we are using the same base code (versioned docker images), same chart template, but different values files for templating them according to our needs (deployment names, endpoint names, resources, replication, etc.)

    5. We keep this practice consistent across each and every project providing a much easier onboarding experience and improved manageability and control over cloud resources.

    Any sufficiently advanced technology is indistinguishable from magic. ~ Arthur C. Clarke.

    One caveat though, Magic, however, has its short-comings. It increases productivity, reliability and reduces costs by means of more efficient resource sharing. But, when something break, people are blind to what they issue must be and tracking down the problem become a difficult task, specially because things always tend to fail at the most inconvenient moment. So, as much as we are proud of our work, we stay humble knowing this fact.

    Optimizing Costs

    Having a cheap infrastructure and a web scale search-engine do not go hand in hand, that said, there are ways by which you can save money. Let’s discuss how we optimized for costs using our K8s based infrastructure:

    1 . Spot Instances

    • We heavily relied on AWS spot instances, as using them forced us to build the system for failures. But it was worth it, as they are a lot cheaper as compared to on-demand instances. Be wary though of not falling on the same self-inflicted damage we did. We were so used to those, that sometimes we outbid ourselves, happened more often than what we would have liked. Also, Don’t exhaust high performance machines or you will get in a bidding war with other companies. Lastly, Never use spot GPU instances before a major NLP/ML conference.
    • Mixed Instance Pools with Spot: Not only did we utilize spot instances for one-off jobs, but for service workloads. We came up with a neat strategy, where we create a node pool for running kubernetes resources using mixed instance types (but, similar configurations) which were distributed across multiple Availability Zones. This coupled with Spot Termination Handler allowed us to move our stateless workloads just in time to newly created or spare capacity spot nodes thus saving us from a potentially high downtime.

    2 . Sharing CPU and Memory

    As we are fully committed on Kubernetes, we discuss workload provisioning based on how much CPU or memory is necessary and how many replicas does one service need. In this, if the Request and Limits are equal we get guaranteed performance. Although, if the Request is low but Limit is high, which may be useful in case of sporadic workloads, we could over-provision and maximally utilize the resources on an instance (reduce idle resources on an instance).

    3 . Cluster Auto-scaler, Vertical and Horizontal Pod Autoscaler

    We deploy these to automate launching and downscaling of pods and in turn instances only when the need arises. This means when there is no workload, only the minimum set of instances are up and we don’t need manual intervention to facilitate this.

    4 . Deployment downscalers in development environment

    We use deployment down-scalers to downscale pod replicas to 0 at specific times for all services in development setting. Using an annotation in our application’s kubernetes manifest, we can specify an uptime schedule:

    annotations:
        downscaler/uptime: Mon-Fri 08:00-19:30 Europe/Berlin
    

    This means the deployment is downscaled to zero during non-working hours. And in turn the instances are automatically downscaled by the cluster autoscaler since there are no active workloads on the instance.

    5 . Cost Assessment and instance recommendations – Long term cost reduction

    In production, once we identify our resource utilization, we can select the instances which will be used heavily. Instead of on-demand, we could go towards a reserved instance pricing model which requires a minimum of 1 year upfront payment. In turn, the costs are significantly cheaper as compared to running instances on-demand.

    For kubernetes, there are some solutions like kubecost, which monitors usage over time and based on that recommend additional ways to save costs. It also provides an estimated price for a workload, so one can get a decent idea of the overall cost for deploying a system. One is notified also of the resources which might not be of use anymore like ebs volumes, etc in one single interface.

    All of these steps result in saving tens and thousands of euros for us annually. For larger organizations with high infrastructure bills, if executed properly, these strategies could easily save millions on average per year.

    Machine Learning Systems

    Figure 5: Hidden Technical Debt in Machine Learning Systems — Sculley etal." loading="lazy" src=Figure 5: Hidden Technical Debt in Machine Learning Systems — Sculley et al.[12]

    It is interesting to note that our Kubernetes journey started in the most unexpected manner. We were exploring the idea to set up an infrastructure, which allows us to run distributed deep learning experiments using Tensorflow. At the time this idea was new and although Tensorflow had shipped distributed training a short while ago, apart from a few handful of very well resourced organizations, only few knew how to run and manage this workload End-to-End specially for large settings. It was also a time when there was no cloud offering which could help solve this problem.

    We started out using a distributed setup deployed using Terraform, but we soon realized this solution has its limitations if we wish to scale it to all engineers of the organization. At the same time we found some community contributions, where plain Kubernetes manifests were generated via the use of smart jinja templating engine to create a distributed deployment of Deep Learning Training Application (Parameter Server & Worker Mode) This was our first contact with Kubernetes. In parallel, we started working on building our search to work near real-time, along-side experimenting with recency ranking. It was then, when kubernetes shone the brightest for us and we decided to get stuck in and dive deeper into it.

    As part of our Machine Learning Systems journey, like with most of the infrastructure described above, our goal was to open it to the entire organization and make it easier for all developers to deploy applications on Kubernetes. We really wanted them to focus more on solving the problems instead of trying to solve infrastructure challenges associated with services.

    But, from all the gains one gets from applying Machine Learning to their problems we quickly realize that maintaining machine learning systems is a real pain. It goes a lot deeper than just writing ML code or training models. Even for an organization at our scale, we need to address some of these issues. They are described in depth in the paper, “Hidden Technical Debt in Machine Learning Systems”[12:1]. It is a good read for anyone thinking of relying and running machine learning systems at scale in production. In our process, we looked at several solutions,e.g.:

    Among all these, we found Kubeflow the most relevant, feature complete, cost effective and customizable for our needs.

    We have also penned down some of these reasons[17] on the official Kubeflow Blog a while back. Apart from providing us with custom resources like TfJob and PytorchJob to run our training code, one of the benefits of kubeflow has been its out of the box excellent notebook support.

    Kubeflow use-case @ Cliqz

    Many of the features responsible for our near-realtime search ranking utilized notebooks from Kubeflow. An engineer can spin up a notebook in the cluster and directly tap into our data infrastructure (batch and realtime streaming). It made it easier to share notebooks and work on different parts of the code together. Experimentation became easier for engineers as they don’t have to re-setup notebook servers, provide perimissions to access data infrastructure and look into the gory details of deployment, using a simple web interface one can choose what resources they needed for the notebook (cpu, memory and even gpu), allocate an ebs volume and start up a notebook server. Interestingly, some of the experiments, were done on notebooks with as low as 0.5 CPU and 1 GB of RAM. Usually this capacity was readily available in our cluster and we could easily facilitate spawning of such notebooks without starting newer instances. In a different setting, if two engineers from different teams were working, they most likely will start their own instances. This leads to increased costs and under-utilization of resources.

    In addition, Jobs can be submitted which can then be used to train, validate and serve the model from within the notebook. An interesting project in this regard is Fairing.

    Kubeflow itself is a very comprehensive initiative and we have only started scratching its surface. More recently, we have also started looking into projects like Katib (hyperparameter tuning for machine learning models), KFServing (Serverless inferencing of Machine Learning models on Kubernetes), Kubeflow Pipelines (End to End Machine Learning Pipelines for Kubeflow) and TFX (Create and manage a production ML pipeline). We already have some prototype around these projects and hope to release them to production in near future.

    Given all these benefits, we would like to thank whole-heartedly the team behind Kubeflow for this amazing project.

    As we grow and rely more on machine learning and its variants, we want the processes surrounding Machine Learning to be streamlined and be more reproducible in general. This is where things like model tracking, model management, data versioning and lineage becomes crucial.

    To run things consistently at our scale where we apply periodic updates and assessments, we needed a solution around data management for serving models in production, which facilitates hot swapping of models and indexes in our live production services autonomously. To tackle this issue, we built a solution in-house “Hydra” which provides downstream services with the capability of performing a dataset pub-sub. It also ensures volume management for services in a Kubernetes cluster. We will describe this in detail in a future post.

    Final Words

    Once you’ve found success, your next goal should be helping others do the same. ~ Kelsey Hightower

    Architecting Cliqz has been challenging and fun at the same time. We believe there is still a long road ahead of us. As with growing development in this space, there are several possibilities and routes to take.

    Even though Cliqz employs 120+ people, the codebase is effectively developed by thousands of passionate open source developers, distributed globally, devoted to ship high quality code, and build safe and secure software systems for mankind. We would not have reached where we are without them. We would like to thank the open source community from the core of our hearts to be really generous and helpful in providing us with solutions, whenever we were stuck. Through this post, we wished to share our struggles, experiences and solutions for others who might have similar problems and are looking for answers. In the spirit of openness, we too are contributing back to the extent of our scarce resources here.

    A fully private search offering from Cliqz is our contribution towards a privacy focused web, a daunting but not an impossible task. We invite you to try out our search and download our browsers on desktop and mobile to be part of this mission. And, if you enjoy working on such problems come and join us.

    Auf Wiedersehen (until we see each other again)

    Remarks and references


    1. https://0x65.dev/blog/2019-12-11/the-pivot-that-excited-mozilla-and-google.html ↩︎

    2. https://0x65.dev/blog/2019-12-07/indexing-billions-of-text-vectors.html ↩︎

    3. https://aws.amazon.com ↩︎

    4. https://0x65.dev/blog/2019-12-08/how-do-you-spell-boscodictiasaur.html ↩︎

    5. https://0x65.dev/blog/2019-12-06/building-a-search-engine-from-scratch.html ↩︎

    6. https://0x65.dev/blog/2019-12-09/cliqz-rich-results.html ↩︎

    7. https://en.wikipedia.org/wiki/A/B_testing ↩︎

    8. https://martinfowler.com/bliki/BlueGreenDeployment.html ↩︎

    9. https://martinfowler.com/bliki/CanaryRelease.html ↩︎

    10. https://kubernetes.io ↩︎

    11. https://www.cncf.io/ ↩︎

    12. https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems.pdf ↩︎ ↩︎

    13. https://www.intel.ai/mlt-the-keras-of-kubernetes/ ↩︎

    14. https://aws.amazon.com/sagemaker ↩︎

    15. https://www.kubeflow.org ↩︎

    16. https://mlflow.org ↩︎

    17. https://medium.com/kubeflow/why-kubeflow-in-your-infrastructure-56b8fabf1f3e ↩︎

    [ad_2]
    Source link: webdesignernews

    Leave a Reply

    Your email address will not be published. Required fields are marked *