Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Pemrosesan asinkron dengan
Python transformWithState mendukung pemrosesan asinkron yang dibangun di atas asyncio. Dengan menjalankan operasi state dan logika pengguna secara bersamaan di seluruh grouping key serta menggabungkan komunikasi antar-proses, pemrosesan asinkron memiliki throughput lebih tinggi dibandingkan pemrosesan sinkron dengan hanya perubahan kode minor. Peningkatan throughput ini tidak memerlukan pustaka asinkron pihak ketiga. Pengguna tingkat lanjut dapat mengoptimalkan aplikasi mereka lebih lanjut dengan pola pemrograman async dan pustaka yang mendukung async.
Pemrosesan asinkron mendukung kueri mode baik mikrobatch maupun real-time. Untuk satu kunci pengelompokan, pemrosesan asinkron mempertahankan urutan baris. Proses dengan kunci pengelompokan yang berbeda berjalan secara bersamaan.
Untuk menggunakan pemrosesan asinkron, implementasikan AsyncStatefulProcessor alih-alih StatefulProcessor sinkron. API AsyncStatefulProcessor ini mencerminkan API sinkron StatefulProcessor, sehingga sebagian besar aplikasi hanya memerlukan perubahan kecil untuk menggunakan API asinkron. Lihat Implement AsyncStatefulProcessor.
Untuk API sinkron transformWithState dan konsep inti, lihat Membangun aplikasi stateful kustom dengan transformWithState.
Requirements
Pemrosesan asinkron memiliki persyaratan sebagai berikut:
- Tersedia di Databricks Runtime 19 dan ke atas, atau pada komputasi serverless dengan versi lingkungan 6 ke atas.
- Tersedia hanya untuk API Python berbasis baris
transformWithState. Pemrosesan asinkron tidak didukung untuktransformWithStateInPandasatau untuk API ScalatransformWithState. - Dalam pipeline Lakeflow, konfigurasikan pipeline untuk menggunakan channel PREVIEW. Persyaratan ini berlaku untuk komputasi pipeline klasik dan serverless. Kanal CURRENT tidak mendukung pemrosesan asinkron. Lihat
channeldi Konfigurasi pipeline dan saluran runtime Lakeflow pipelines.
Implementasikan AsyncStatefulProcessor
Untuk mengonversi objek sinkron StatefulProcessor menjadi AsyncStatefulProcessor, lakukan perubahan berikut:
- Definisikan metode API (
init,close,handleInputRows,handleExpiredTimer, danhandleInitialState) denganasync defkata kunci. - Baca dan perbarui nilai status dan timer dengan
await, atau menjalankannya menggunakan pustaka Pythonasyncio. Ini berlaku untuk operasi status sepertivalueState.get()dan untuk operasi timer sepertiregisterTimer. Membuat objek state, sepertihandle.getValueState, tetap sinkron.
Pertimbangan berikut berlaku untuk pemrosesan asinkron:
- Jika aplikasi Anda menyimpan data dalam variabel anggota atau di sistem eksternal, Databricks merekomendasikan agar Anda menulis ulang logika agar aman untuk eksekusi bersamaan. Karena
handleInputRowsdanhandleExpiredTimerdapat berjalan bersamaan di seluruh kunci pengelompokan, run interleaved tidak boleh merusak data yang dibagikan. Sebagian besar aplikasi sudah memenuhi persyaratan ini. - Databricks menyarankan agar Anda tidak menangkap atau mengabaikan error dari operasi state. Apache Spark menangani kesalahan ini untuk Anda. Jika operasi state gagal, Apache Spark membuat tugas tersebut gagal dan mencobanya kembali.
- Dalam
AsyncStatefulProcessor, kesalahan operasi state dikelola untuk Anda dan tidak pernah diteruskan ke kode Anda. - Dalam operasi sinkron,
StatefulProcessorkesalahan operasi state muncul dalam kode Anda, tetapi menekan kesalahan tersebut dapat mengorbankan kebenaran data.
- Dalam
Contoh: hitung baris untuk setiap kunci pengelompokan
Contoh berikut mendefinisikan AsyncCountProcessor yang menghitung jumlah baris untuk setiap kunci pengelompokan. Variabel value_schema mendefinisikan skema objek ValueState yang menyimpan jumlah yang berjalan. Dibandingkan dengan StatefulProcessor sinkron, perubahan tersebut adalah kata kunci async def pada setiap metode dan await pada operasi pembacaan dan pembaruan status. Panggilan ke getValueState di init tetap sinkron. Definisikan prosesor seperti dalam kode berikut:
from pyspark.sql import Row
from pyspark.sql.streaming import AsyncStatefulProcessor, AsyncStatefulProcessorHandle
from pyspark.sql.types import StructType, StructField, LongType
value_schema = StructType([StructField("count", LongType(), True)])
class AsyncCountProcessor(AsyncStatefulProcessor):
async def init(self, handle: AsyncStatefulProcessorHandle) -> None:
self.count = handle.getValueState("count", value_schema)
async def handleInputRows(self, key, rows, timerValues):
total = (await self.count.get() or (0,))[0]
for _ in rows:
total += 1
await self.count.update((total,))
yield Row(action=key[0], count=total)
async def close(self) -> None:
pass
Jalankan kueri dengan prosesor asinkron
Untuk menjalankan query dengan prosesor asinkron, berikan AsyncStatefulProcessor ke transformWithState. Kueri menggunakan sintaks yang sama dengan jalur sinkron. API asinkron dan sinkron berbagi format state yang sama, sehingga Anda dapat mengganti kueri yang sudah ada antara AsyncStatefulProcessor dan StatefulProcessor sinkron sambil menggunakan kembali checkpoint yang sama.
Contoh: hitung peristiwa dalam events dataset contoh
Contoh berikut menjalankan AsyncCountProcessor pada dataset sampel events. Setiap catatan memiliki bidang time (detik epoch) dan bidang action dengan nilai Open atau Close. Query mengelompokkan berdasarkan action dan menghitung event untuk setiap jenis aksi. Untuk contoh dataset lainnya, lihat Dataset contoh.
input_schema variabel mendefinisikan skema catatan sumber, dan output_schema variabel mendefinisikan skema baris yang dihasilkan prosesor. Untuk membaca dataset contoh sebagai aliran, definisikan kedua skema, lalu mulai kueri seperti dalam kode berikut:
from pyspark.sql.types import StructType, StructField, StringType, LongType
input_schema = StructType([
StructField("time", LongType(), True),
StructField("action", StringType(), True),
])
output_schema = StructType([
StructField("action", StringType(), True),
StructField("count", LongType(), True),
])
events = (
spark.readStream.schema(input_schema)
.option("maxFilesPerTrigger", 10)
.json("/databricks-datasets/structured-streaming/events")
)
q = (
events.groupBy("action")
.transformWithState(
statefulProcessor=AsyncCountProcessor(),
outputStructType=output_schema,
outputMode="Update",
timeMode="None",
)
.writeStream.format("memory")
.queryName("async_counts")
.trigger(availableNow=True)
.start()
)
q.awaitTermination()
Setelah kueri selesai, lihat jumlah berjalan untuk setiap jenis aksi seperti dalam kode berikut:
display(spark.sql("SELECT action, MAX(count) AS count FROM async_counts GROUP BY action ORDER BY action"))
Operasi status asinkron dan timer
Dalam AsyncStatefulProcessor, operasi variabel status dan timer yang membaca atau menulis nilai bersifat asinkron. Sebagian besar operasi ini mengembalikan satu hasil yang Anda ambil dengan await. Operasi yang mengembalikan koleksi justru mengembalikan iterator asinkron yang Anda konsumsi dengan async for. Untuk pengantar tentang async/await dan iterator asinkron di Python, lihat dokumentasi Python asyncio.
Tabel berikut mencantumkan operasi yang mengembalikan satu hasil yang dapat Anda ambil dengan await:
| Class | Operasi yang menggunakan await |
|---|---|
AsyncValueState |
exists,get,update,clear |
AsyncMapState |
exists, getValue, containsKey, updateValue, removeKey, clear |
AsyncListState |
exists, put, appendValue, appendList, clear |
AsyncStatefulProcessorHandle |
registerTimer, deleteTimer |
Tabel berikut mencantumkan operasi yang mengembalikan iterator asinkron yang dapat Anda ambil dengan async for:
| Class | Operasi yang menggunakan async for |
|---|---|
AsyncMapState |
iterator, keys, values |
AsyncListState |
get |
AsyncStatefulProcessorHandle |
listTimers |
Contoh: async for
Misalnya, untuk membaca nilai dalam AsyncListState, lakukan iterasi dengan async for seperti dalam kode berikut:
total = 0
async for value in self.items.get():
total += value[0]
Metode yang membuat objek status dan menghapus variabel status tetap sinkron: getValueState, getMapState, getListState, dan deleteIfExists.
Untuk deskripsi setiap jenis state, lihat Jenis state kustom.
Optimasi dengan pola pemrograman asinkron
Pemrosesan asinkron berguna ketika logika Anda bergantung pada operasi eksternal, seperti permintaan jaringan. Alih-alih menunggu setiap permintaan secara berurutan, gunakan asyncio untuk menjalankan permintaan secara bersamaan dan mengurangi waktu idle.
Contoh: jalankan request bersamaan dengan asyncio.gather
Contoh berikut menggunakan asyncio.gather untuk menjalankan semua permintaan HTTP per baris secara bersamaan dan menunggu hingga selesai, lalu menyimpan skor maksimum dalam status. Definisikan prosesor seperti dalam kode berikut:
import asyncio
import aiohttp
from pyspark.sql import Row
from pyspark.sql.streaming import AsyncStatefulProcessor
class HttpScoreRowGatherProcessor(AsyncStatefulProcessor):
async def init(self, handle):
self._score_state = handle.getValueState("last_score", "score double")
self._session = aiohttp.ClientSession()
async def _fetch_score(self, row) -> float:
async with self._session.get(
f"https://api.example.com/score/{row.event_id}"
) as resp:
return (await resp.json())["score"]
async def handleInputRows(self, key, rows, timerValues):
user_id = key[0]
scores = await asyncio.gather(*[self._fetch_score(row) for row in rows])
max_score = max(scores)
await self._score_state.update((max_score,))
yield Row(user_id=user_id, score=max_score)
async def close(self):
await self._session.close()