Порівняння рушіїв обробки даних на Python за допомогою даних про поїздки таксі в Нью-Йорку (Bodo vs. Spark, Dask, Ray)

Технологія Python стала основною мовою програмування для інженерів і науковців, які працюють з даними і застосовують штучний інтелект у своїх проектах. Однак ефективне масштабування Python коду залишається складним завданням для багатьох розробників. Обчислювальні рушії, такі як Bodo, Spark, Dask, і Ray/Modin, намагаються подолати цей розрив, пропонуючи масштабування Python, зберігаючи високу продуктивність.

Але з такою великою кількістю можливостей і компромісів, як обрати правильний інструмент для вашого робочого навантаження? Ми в Bodo зосереджені на тому, щоб зробити Python значно швидшим, при цьому показуючи суттєві переваги з точки зору продуктивності (та економії витрат). Тому ми вирішили провести тестування за допомогою бенчмарка.

Ми вибрали приклад програми на Python, яка обчислює підсумки місячних поїздок з даними про опади на публічному наборі даних NYC Taxi. Цей приклад простий, але відображає багато програм обробки даних Python/Pandas. Інші бенчмарки зазвичай переводяться з SQL (наприклад, TPC-H) і не відображають типові робочі процеси Python. Зокрема, сила Python як універсальної мови полягає у написанні власного процедурного коду (наприклад, у Series.map або DataFrame.apply), що часто відсутнє в SQL-орієнтованих бенчмарках. Ми вважаємо, що більш "пайтонівські" бенчмарки, як цей, є необхідними в цій галузі загалом.

Наші результати виявляють величезні різниці в продуктивності: Bodo показав 20x прискорення порівняно з Spark (95% економія витрат), 50x порівняно з Dask (98% економія витрат), і неймовірні 250x порівняно з Ray/Modin (99% економія витрат) для цього бенчмарка. Це можна пояснити підходом Bodo, заснованим на компіляторі з високою продуктивністю (HPC), на відміну від розподіленого планування завдань інших рушіїв.

pic

Ми визнаємо, що ми є зацікавленою стороною — ми найкраще знаємо Bodo. Однак ми підходили до цього бенчмарка з прозорістю та справедливістю, дотримуючись належних практик і відкрито ділимося всім кодом бенчмарка тут (цей код розроблено таким чином, щоб його було легко відтворити). Протягом всього процесу наш акцент був на тому, що звичайний користувач Python/Pandas може досягти без значних переписів коду та експертної налаштування. Ми запрошуємо ваші відгуки, відтворення та внески для покращення цих висновків. Давайте розглянемо, що ці обчислювальні рушії можуть зробити для ваших робочих навантажень на Python!

Огляд рушіїв

Ось короткий опис рушіїв, які ми тестували:

  • Bodo: Використовує нативну компіляцію Python та задню частину на основі MPI для досягнення продуктивності, наближеної до C, та масового паралелізму. Зосереджується на нативному робочому процесі Python та продуктивності рівня HPC для масштабованої обробки даних.
  • Apache Spark: Відомий розподілений обчислювальний рушій, розроблений для надійності та масової масштабованості, хоча часто має накладні витрати через свою архітектуру на основі JVM.
  • Dask: Нативний Python рушій, який дозволяє гнучке обчислення за допомогою знайомих API, при цьому підтримує розподілені обчислення.
  • Ray: Орієнтований на паралельні та розподілені Python додатки, спроектований для масштабованості та гнучкості, але може мати проблеми з високою вартістю ефективності для певних робочих навантажень.

Бенчмаркінг: Bodo проти Spark, Dask, Ray

Набір даних NYC Taxi є колекцією поїздок таксі, які відбулися в Нью-Йорку з 2009 року. Це дуже цікаві реальні публічні дані, часто використовувані для прикладів у галузі науки про дані та бенчмаркінгу. Вони містять детальну інформацію, таку як дата та час підйому і координати поїздки. Ми використовуємо підмножину For-Hire Vehicles High Volume (FHVHV), яка є найбільшою підмножиною, орієнтованою на орендовані транспортні засоби (Uber, Lyft тощо) з 2019 року до початку 2024 року. Наш приклад коду базується на коді, який використовував Тодд В.
Шнайдер](https://github.com/toddwschneider/nyc-taxi-data) у своєму захоплюючому блог-пості.

Налаштування бенчмарка

Ми використовуємо кластер з 4 вузлів на AWS для запуску бенчмарка на всіх рушіях (Dask також використовує невеликий окремий екземпляр для планувальника). Конфігурація кластера була обрана, щоб переконатися, що всі рушії мають достатньо пам'яті (особливо Spark), але Bodo зміг запустити цей бенчмарк на значно меншій частині цієї конфігурації завдяки ефективному використанню пам'яті. Ця таблиця підсумовує конфігурацію кластера:

pic

Загальний розмір набору даних становить 24,7 GiB у форматі Parquet. Дані про погоду в Центральному парку зберігаються в одному CSV файлі на S3, і його загальний розмір становить 514 KiB.

Версії програмного забезпечення

Ось версії програмного забезпечення, що використовуються для відтворюваності:

pic

Результати продуктивності

Нижче наведено графік часу виконання бенчмарка для різних систем. Ми запускали кілька разів і взяли середнє значення, яке виглядає досить послідовно по всіх запусках. Bodo виявився у 20 разів швидшим за Spark (економія 95% витрат), 50 разів швидшим за Dask (економія 98% витрат), і приголомшливі 250 разів швидше за Ray/Modin (економія 99% витрат) для цього бенчмарка.

pic

Bodo та PySpark — найшвидші рушії для цього бенчмарка. Нижче наведено графік, який порівнює їх більш чітко.

pic

Локальні запуски

Ми використовуємо меншу підмножину набору даних FHVHV, щоб дозволити запуск робочого навантаження локально на ноутбуці, оскільки запуск коду локально — це типовий робочий процес багатьох розробників. Ми також включили реалізацію, що використовує Pandas для локального порівняння. Для цієї конфігурації ми використовуємо підмножину даних з 20 мільйонів рядків, щоб переконатися, що вона поміщається в пам'ять для всіх рушіїв, окрім PySpark, який вимагає дуже високих потреб у пам'яті (Bodo може працювати з набагато більшими наборами даних локально).

Навіть на такому меншому масштабі Bodo показує покращення продуктивності в ~4 рази порівняно з Pandas, тоді як інші рушії можуть працювати значно повільніше за звичайний Pandas.

pic

Робота з Bodo

Запуск коду Pandas з Bodo був просто питанням додавання декоратора @bodo.jit до функції обчислення для нас (хоча наше попереднє знання про Bodo могло зіграти роль). Bodo зміг працювати на значно менших розмірах кластерів і не мав проблем з масштабуванням на інших конфігураціях.

Робота з Dask

Бібліотека DataFrame Dask дозволила досить легко перевести робоче навантаження Pandas з кількома змінами, окрім тривіальних змін на заміну pd на dd. Хоча бібліотека DataFrame Dask дуже схожа на API Pandas, було одне місце, де аргумент не підтримувався (reset_index=False в df.groupby) і ще одне, де за замовчуванням був невеликий розрив ( sort_values вимагає аргументу ascending=True). Однак ці зміни були відносно простими для виконання для користувача Pandas. Єдина критична зміна продуктивності полягала в уточненні типу вихідних даних UDF. Це було б важко помітити, якби не корисне попередження користувача. Дотримуючись кращих практик Dask, лише кінцевий результат був фактично обчислений, тоді як решта робочого навантаження була відкладеною для оцінки, що дозволило оптимізувати граф завдань. Запуск повного набору даних на меншому кластері спочатку призвів до помилки через нестачу пам'яті, але ми зрештою вирішили це, збільшивши розмір екземпляра (з c6i.4xlarge до r6i.8xlarge).

Робота з Modin на Ray

Бібліотека DataFrame Modin також зробила дуже легким перенесення робочого навантаження Pandas завдяки майже ідентичним API з Pandas.
Єдине, що потрібно було змінити, це конвертувати DataFrame Modin у об'єкт Ray перед записом у Parquet. Хоча запуск Modin на Ray на невеликому наборі даних був простим, запуск повного набору даних призвів до проблем з пам'яттю на менших екземплярах. Навіть на великому розмірі кластера (r6i.16xlarge), Ray спливав об'єкти на диск, що змусило нас налаштувати розмір локального диска екземплярів.

Використання Ray для створення та налаштування кластерів також здебільшого було безболісним, оскільки наданий yaml файл з їх документації для швидкого старту зробив налаштування кластера досить простим для нашого випадку. Основна складність при роботі з Ray полягала в використанні автоскейлера, який за замовчуванням створює лише один вузол при створенні кластера. Щоб забезпечити чесність нашого порівняння, ми використовували SDK Ray для запиту, а потім чекали, поки робочі вузли будуть повністю налаштовані, перед тим як розпочати запуск бенчмарку.

Робота з PySpark

Запуски Spark викликали найбільше труднощів у порівнянні з іншими системами. Ми вибрали API Pandas on Spark замість PySpark, щоб уникнути складних переписувань коду, які можуть бути непридатними для звичайних користувачів Pandas. Перетворення робочого навантаження Pandas в Pandas on Spark спочатку здавалося простим, оскільки нам просто потрібно було замінити виклики до Pandas на Pandas on Spark. Однак виникли численні проблеми, які потрібно було вирішити. По-перше, проблеми доступу вимагали заміни s3a провайдера облікових даних на AnonymousCredentialsProvider. По-друге, ми прочитали дані звичайними API PySpark і видалили чотири стовпці типу datetime, які Pandas on Spark не міг прочитати (як з, так і без spark.sql.execution.arrow.pyspark.enabled). По-третє, Spark не об'єднував типи даних деяких стовпців, навіть з увімкненим mergeSchema, тому нам довелося прочитати і переписати набір даних з Bodo, щоб мати єдину схему. Підсумовуючи, отримати робочу версію коду Spark (особливо з API Pandas on Spark) зайняло чимало часу і потребувало вирішення кількох проблем.

Чому Bodo перевершує інших

Перевага Bodo в цьому бенчмарку обумовлена його фундаментально іншою архітектурою та дизайном:

  1. Нативна компіляція: На відміну від таких як Spark, Bodo компілює Python в нативний машинний код, уникаючи накладних витрат від інтерпретаторів і віртуальних машин.
  2. Паралелізм на основі MPI: Забезпечує продуктивність рівня HPC з ефективною комунікацією та мінімальною затримкою. Це дозволяє уникнути накладних витрат на проектування розподілених бібліотек виконувачів, властивих іншим системам.
  3. Легкість використання: Синтаксис Python без шкоди для продуктивності, що робить його зручним для використання науковцями з даними.

Здатність Bodo поєднувати легкість використання і продуктивність рівня HPC робить його сильним конкурентом існуючим рушіям, таким як Spark, Dask і Ray. Хоча Spark залишається домінуючою силою в розподілених системах завдяки своєму екосистемі, а Dask і Ray відзначаються гнучкістю, Bodo пропонує безпрецедентну швидкість, зручність використання і ефективність витрат для ресурсозатратних робочих навантажень.

Висновки

Бенчмарки обробки даних Python, такі як той, що ми тестували, необхідні для порівняння продуктивності рушіїв обчислень. Хоча Spark, Dask і Ray мають свої переваги — такі як гнучкість або великі екосистеми — компіляція на основі HPC і паралелізм MPI в Bodo забезпечують неперевершену швидкість і ефективність витрат для цього конкретного тесту. Від прискорення у 20 разів порівняно зі Spark до 250 разів порівняно з Ray/Modin, покращення є вражаючими, особливо враховуючи нативний стиль коду Python, який підтримує Bodo.

Однак жоден бенчмарк не є остаточним. Ми закликаємо вас дослідити наш відкритий код бенчмарка, відтворити наші висновки і подивитися, як ці інструменти працюють у вашому середовищі.
Якщо вам потрібна висока масштабованість і продуктивність без жертв для звичних робочих процесів Python, унікальний підхід Bodo вартий того, щоб спробувати. Ви можете встановити Bodo за допомогою простого pip install bodo. Відвідайте наш GitHub репозиторій для отримання додаткової інформації та приєднуйтесь до обговорення в нашому Slack спільноті.‍

Оригінально опубліковано на https://www.bodo.ai.

Перекладено з: Python data processing engine comparison with NYC Taxi trips (Bodo vs. Spark, Dask, Ray)

Leave a Reply

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