試與性能剖析完全指南:從遠程斷點到 UDF 性能剖析)
大數(shù)據(jù)數(shù)據(jù)分析批處理流處理機器學(xué)習(xí)圖計算【免費下載鏈接】sparkApache Spark - A unified analytics engine for large-scale data processing項目地址https://gitcode.com/gh_mirrors/sp/spark點擊查看免費下載本指南以 Apache Spark 倉庫中 python/docs/source/development/debugging.rst 為骨架系統(tǒng)講解 PySpark Python 側(cè)的調(diào)試與剖析方法包括借助 PyCharm Professional 對 Driver 與 Executor 兩端進行遠程斷點調(diào)試、用top/ps檢查進程資源、用memory_profiler與 Python 內(nèi)置cProfile定位內(nèi)存與 CPU 熱點以及 PySpark 常見異常與錯誤碼的排查修復(fù)。讀完本文你將掌握一套從進程定位 → 斷點調(diào)試 → 性能剖析 → 異常排除的完整 PySpark 排查鏈路。理解 PySpark 的進程模型Driver 與 Executor 兩側(cè)的調(diào)試差異PySpark 以 Spark 為計算引擎并通過Py4J在 Python 與 JVM 之間通信Driver 側(cè)PySpark 通過Py4J與 JVM 中的 Driver 通信。當(dāng)pyspark.sql.SparkSession或pyspark.SparkContext創(chuàng)建并初始化時PySpark 會啟動一個 JVM 用于通信。因此 Driver 側(cè)的 Python 代碼本質(zhì)上是一個普通 Python 進程除非以 YARN 集群模式把 Driver 運行在遠端機器上調(diào)試方式與常規(guī) Python 程序無異。Executor 側(cè)Python worker 進程負責(zé)執(zhí)行 Python 原生函數(shù)或處理 Python 數(shù)據(jù)。它們是惰性啟動的——只有應(yīng)用確實需要 Python worker 與 JVM 交互時才被拉起例如執(zhí)行 pandas UDF 或 PySpark RDD API 時。這與 Driver 側(cè)始終存在的進程不同因此兩側(cè)的調(diào)試方式必須分開討論。本文聚焦于 PySpark Python 側(cè)的調(diào)試不涉及 JVM 側(cè)剖析JVM 的 profiling/debugging 工具在 Spark 官方 Developer Tools 文檔中另有說明。另外請注意兩個前提在本地運行時Driver 側(cè)可以直接用 IDE 調(diào)試無需遠程調(diào)試特性IDE 配置方式參見 python/docs/source/development/setting_ide.rst其中包含 PyCharm 相關(guān)章節(jié)。除本文方案外也可以使用開源pydevd的遠程調(diào)試器Remote Debugger替代 PyCharm Professional 來完成類似工作。遠程調(diào)試PyCharm Professional 雙端斷點實戰(zhàn)本節(jié)以單機演示為例分別展示 Driver 與 Executor 兩側(cè)的遠程調(diào)試若要調(diào)試其他機器上的 PySpark 應(yīng)用請參照 PyCharm 官方remote debugging with product完整說明。第一步創(chuàng)建 Python Debug Server 配置從Run菜單選擇Edit Configuration...打開Run/Debug Configurations dialog點擊工具欄上的新建配置在可用配置列表中選擇Python Debug Server輸入配置名稱例如MyRemoteDebugger并指定端口號例如12345。之后需要在所有將要連接該調(diào)試器的機器上安裝與本地 PyCharm 版本匹配的pydevd-pycharm包上一對話框會直接給出安裝命令pip install pydevd-pycharm~version of PyCharm on the local machineDriver 側(cè)遠程調(diào)試Driver 側(cè)調(diào)試時應(yīng)用需要能連接到調(diào)試服務(wù)器。把對話框生成的pydevd_pycharm.settrace代碼復(fù)制到 PySpark 腳本最頂部。假設(shè)腳本名為app.pyecho #Copy and paste from the previous dialog import pydevd_pycharm pydevd_pycharm.settrace(localhost, port12345, stdoutToServerTrue, stderrToServerTrue) # # Your PySpark application codes: from pyspark.sql import SparkSession spark SparkSession.builder.getOrCreate() spark.range(10).show() app.py然后點擊運行MyRemoteDebugger調(diào)試配置再提交應(yīng)用spark-submit app.py應(yīng)用提交后即會連接 PyCharm 調(diào)試服務(wù)器從而在 Driver 側(cè)實現(xiàn)遠程斷點調(diào)試。Executor 側(cè)遠程調(diào)試Executor 側(cè)無法像 Driver 那樣直接在腳本頂部插入代碼因為 Python worker 的入口是 Spark 內(nèi)部的daemon/worker模塊。解法是自定義一個 Python daemon 模塊用pydevd_pycharm.settrace包裝 worker 主函數(shù)再通過spark.python.daemon.module配置讓 Spark 使用它。先在當(dāng)前工作目錄準(zhǔn)備remote_debug.pyecho from pyspark import daemon, worker def remote_debug_wrapped(*args, **kwargs): #Copy and paste from the previous dialog import pydevd_pycharm pydevd_pycharm.settrace(localhost, port12345, stdoutToServerTrue, stderrToServerTrue) # worker.main(*args, **kwargs) daemon.worker_main remote_debug_wrapped if __name__ __main__: daemon.manager() remote_debug.py該文件將 Python worker 替換為remote_debug_wrapped每次 worker 被調(diào)用前先settrace連接到調(diào)試服務(wù)器再轉(zhuǎn)發(fā)給真正的worker.main。隨后用該配置啟動pysparkshellpyspark --conf spark.python.daemon.moduleremote_debug啟動MyRemoteDebugger調(diào)試服務(wù)器后運行一個能創(chuàng)建 Python worker 的作業(yè)即可觸發(fā)斷點例如spark.range(10).repartition(1).rdd.map(lambda x: x).collect()源碼佐證daemon 模塊如何被加載從源碼看spark.python.daemon.module是 Spark 官方定義的核心配置項core/src/main/scala/org/apache/spark/internal/config/Python.scala 中聲明了PYTHON_DAEMON_MODULE ConfigBuilder(spark.python.daemon.module)與PYTHON_WORKER_MODULEspark.python.worker.module。在 core/src/main/scala/org/apache/spark/api/python/PythonRunner.scala 中daemonModule讀取該配置若設(shè)置了自定義模塊則用它啟動 daemon 進程未設(shè)置時使用默認的pyspark.daemon。同時pyspark/daemon.py見 python/pyspark/daemon.py中manager()正是 daemon 進程的事件循環(huán)入口daemon.worker_main則被替換為包裝函數(shù)以注入調(diào)試邏輯。檢查資源占用top與ps定位 Python 進程Driver 與 Executor 兩側(cè)的 Python 進程都可以用常規(guī)的top、ps命令查看。Driver 側(cè)直接取 PID在 PySpark shell 中直接獲取當(dāng)前進程 ID import os; os.getpid() 18482再查看該進程的詳細信息與資源占用ps -fe 18482UID PID PPID C STIME TTY TIME CMD 000 18482 12345 0 0:00PM ttys001 0:00.00 /.../pythonExecutor 側(cè)grep 定位 daemon 派生的 workerPython worker 是從pyspark.daemonfork 出來的因此直接 grep 即可得到進程 ID 與資源占用情況ps -fe | grep pyspark.daemon000 12345 1 0 0:00PM ttys000 0:00.00 /.../python -m pyspark.daemon 000 12345 1 0 0:00PM ttys000 0:00.00 /.../python -m pyspark.daemon 000 12345 1 0 0:00PM ttys000 0:00.00 /.../python -m pyspark.daemon 000 12345 1 0 0:00PM ttys000 0:00.00 /.../python -m pyspark.daemon ...當(dāng) Executor 數(shù)量較大時可以結(jié)合top按 CPU/內(nèi)存排序快速鎖定異常 worker 進程。剖析內(nèi)存使用memory_profiler 逐行定位memory_profiler是逐行檢查內(nèi)存占用的剖析器支持 Driver 側(cè)普通腳本也支持 PySpark 為 UDF 提供的內(nèi)置遠程內(nèi)存剖析。Driver 側(cè)裝飾profile逐行統(tǒng)計只要 Driver 不在遠端機器如 YARN 集群模式就能直接對 Driver 進程做內(nèi)存剖析。假設(shè)腳本名為profile_memory.pyecho from pyspark.sql import SparkSession #Your function should be decorated with profile from memory_profiler import profile profile # def my_func(): session SparkSession.builder.getOrCreate() df session.range(10000) return df.collect() if __name__ __main__: my_func() profile_memory.py用 memory_profiler 模塊方式運行python -m memory_profiler profile_memory.py輸出逐行內(nèi)存報表Filename: profile_memory.py Line # Mem usage Increment Line Contents ... 6 def my_func(): 7 51.5 MiB 0.6 MiB session SparkSession.builder.getOrCreate() 8 51.5 MiB 0.0 MiB df session.range(10000) 9 54.4 MiB 2.8 MiB return df.collect()可以看到創(chuàng)建 SparkSession 后基線內(nèi)存約 51.5 MiBcollect()拉取 10000 行結(jié)果到 Driver 增加了約 2.8 MiB。對大數(shù)據(jù)量的collect場景這類報表能直觀暴露內(nèi)存峰值來源。Python/Pandas/Arrow UDF 內(nèi)存剖析內(nèi)置遠程 ProfilerPySpark 為 Python/Pandas/Arrow UDF 提供了內(nèi)置的遠程 memory_profiler適用于帶行號的編輯器如 Jupyter Notebook但不支持生成器函數(shù)generator functions。通過設(shè)置運行時 SQL 配置spark.sql.pyspark.udf.profiler為memory即可開啟from pyspark.sql.functions import pandas_udf df spark.range(10) pandas_udf(long) def add1(x): return x 1 spark.conf.set(spark.sql.pyspark.udf.profiler, memory) added df.select(add1(id)) added.show() spark.profile.show(typememory)輸出結(jié)果 Profile of UDFid2 Filename: ... Line # Mem usage Increment Occurrences Line Contents 4 974.0 MiB 974.0 MiB 10 pandas_udf(long) 5 def add1(x): 6 974.4 MiB 0.4 MiB 10 return x 1UDF 的 ID 可以從查詢計劃中看到——例如物理計劃里ArrowEvalPython節(jié)點中的add1(...)#2Ladded.explain() Physical Plan *(2) Project [pythonUDF0#11L AS add1(id)#3L] - ArrowEvalPython [add1(id#0L)#2L], [pythonUDF0#11L], 200 - *(1) Range (0, 10, step1, splits16)剖析結(jié)果還支持自定義渲染與清理def do_render(codemap): # Your custom rendering logic ... spark.profile.render(id2, typememory, rendererdo_render) spark.profile.clear(id2, typememory)源碼佐證SparkSession 級 Profiler APIspark.profile是 PySpark 4.0 引入的會話級剖析入口實現(xiàn)在 python/pyspark/sql/profiler.pyWorkerMemoryProfilerprofiler.py基于UDFLineProfilerV2按調(diào)用次數(shù)統(tǒng)計逐行內(nèi)存并將結(jié)果經(jīng)_ProfileResultsParamV2累加器SQL_UDF_PROFIER_V2通道聚合回 DriverProfile類profiler.py提供show/dump/render/clear四個方法type參數(shù)取perf或memory未指定時默認同時展示/清理兩類結(jié)果剖析數(shù)據(jù)通過 Spark Accumulator 機制從各 executor 匯總因此show展示的是所有 Python 執(zhí)行任務(wù)的聚合結(jié)果例如 8 個 task 各處理 1000 行則展示 8000 行的累計統(tǒng)計。定位熱點Python 內(nèi)置 ProfilerscProfilePython 標(biāo)準(zhǔn)庫的Python Profilers提供確定性剖析能給出豐富的統(tǒng)計信息用于定位 Driver 側(cè)與 UDF 側(cè)的昂貴熱點代碼路徑。Driver 側(cè)當(dāng)作普通 Python 程序剖析Driver 側(cè)本質(zhì)是普通 Python 進程除非運行在 YARN 集群模式等遠端因此按常規(guī)方式使用即可echo from pyspark.sql import SparkSession spark SparkSession.builder.getOrCreate() spark.range(10).show() app.pypython -m cProfile app.py輸出示例... 129215 function calls (125446 primitive calls) in 5.926 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1198/405 0.001 0.000 0.083 0.000 frozen importlib._bootstrap:1009(_handle_fromlist) 561 0.001 0.000 0.001 0.000 frozen importlib._bootstrap:103(release) 276 0.000 0.000 0.000 0.000 frozen importlib._bootstrap:143(__init__) 276 0.000 0.000 0.002 0.000 frozen importlib._bootstrap:147(__enter__) ...Python/Pandas/Arrow UDF 性能剖析內(nèi)置遠程 Profiler與內(nèi)存剖析類似PySpark 為 UDF 提供內(nèi)置的遠程 Python Profilers同樣不支持生成器函數(shù)。將spark.sql.pyspark.udf.profiler設(shè)為perf即可 from pyspark.sql.functions import pandas_udf df spark.range(10) pandas_udf(long) ... def add1(x): ... return x 1 ... added df.select(add1(id)) spark.conf.set(spark.sql.pyspark.udf.profiler, perf) added.show() -------- |add1(id)| -------- ... -------- spark.profile.show(typeperf) Profile of UDFid2 2300 function calls (2270 primitive calls) in 0.006 seconds Ordered by: internal time, cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 10 0.001 0.000 0.005 0.001 series.py:5515(_arith_method) 10 0.001 0.000 0.001 0.000 _ufunc_config.py:425(__init__) 10 0.000 0.000 0.000 0.000 {built-in method _operator.add} 10 0.000 0.000 0.002 0.000 series.py:315(__init__) ...UDF ID 同樣可以從查詢計劃ArrowEvalPython節(jié)點中讀取 added.explain() Physical Plan *(2) Project [pythonUDF0#11L AS add1(id)#3L] - ArrowEvalPython [add1(id#0L)#2L], [pythonUDF0#11L], 200 - *(1) Range (0, 10, step1, splits16)render方法默認使用flameprof渲染器輸出火焰圖在 IPython 環(huán)境返回IPython.display.HTML否則返回 SVG 源字符串也可傳入自定義渲染函數(shù) spark.profile.render(id2, typeperf) # rendererflameprof by default def do_render(stats): ... # Your custom rendering logic ... ... ... spark.profile.render(id2, typeperf, rendererdo_render)清理結(jié)果 spark.profile.clear(id2, typeperf)源碼佐證UDF 性能剖析的實現(xiàn)WorkerPerfProfilerpython/pyspark/sql/profiler.py在 worker 側(cè)基于cProfile.Profile啟停采集save()時通過pstats.Stats生成可 picklable 的統(tǒng)計并寫入累加器_render_flameprofprofiler.py將pstats渲染為 SVG且_renderers注冊表中默認注冊了(perf, None)與(perf, flameprof)兩條記錄——這正是rendererflameprof by default的由來。使用火焰圖前需安裝flameprof版本不低于 0.4否則會拋出PACKAGE_NOT_INSTALLED錯誤。常見異常與錯誤排查手冊PySpark SQL 層異常AnalysisException——分析 SQL 查詢計劃失敗時拋出典型場景是引用了不存在的列 df spark.range(1) df[bad_key] Traceback (most recent call last): ... pyspark.errors.exceptions.AnalysisException: Cannot resolve column name bad_key among (id)解決改用存在的列名。 df[id] ColumnidParseException——解析 SQL 命令失敗時拋出 spark.sql(select * 1) Traceback (most recent call last): ... pyspark.errors.exceptions.ParseException: [PARSE_SYNTAX_ERROR] Syntax error at or near 1: extra input 1.(line 1, pos 9) SQL select * 1 ---------^^^解決修正 SQL 語法。 spark.sql(select *) DataFrame[]IllegalArgumentException——傳入非法或不合適的參數(shù)時拋出 spark.range(1).sample(-1.0) Traceback (most recent call last): ... pyspark.errors.exceptions.IllegalArgumentException: requirement failed: Sampling fraction (-1.0) must be on interval [0, 1] without replacement解決傳參需滿足取值范圍約束例如采樣比例必須在[0, 1]區(qū)間。 spark.range(1).sample(1.0) DataFrame[id: bigint]PythonException——來自 Python worker 的異常外層能看到 worker 中拋出的異常類型與堆棧如下例中的TypeError import pyspark.sql.functions as sf from pyspark.sql.functions import udf def f(x): ... return sf.abs(x) ... spark.range(-1, 1).withColumn(abs, udf(f)(id)).collect() 22/04/12 14:52:31 ERROR Executor: Exception in task 7.0 in stage 37.0 (TID 232) org.apache.spark.api.python.PythonException: Traceback (most recent call last): ... TypeError: Invalid argument, not a string or column: -1 of type class int. For column literals, use lit, array, struct or create_map function.解決在 UDF 內(nèi)部使用純 Python 邏輯不要混用 DataFrame 列函數(shù)。 def f(x): ... return abs(x) ... spark.range(-1, 1).withColumn(abs, udf(f)(id)).collect() [Row(id-1, abs1), Row(id0, abs0)]StreamingQueryException——StreamingQuery 失敗時拋出多數(shù)情況下它由 Python worker 拋出并包裝為PythonException sdf spark.readStream.format(text).load(python/test_support/sql/streaming) from pyspark.sql.functions import col, udf bad_udf udf(lambda x: 1 / 0) (sdf.select(bad_udf(col(value))).writeStream.format(memory).queryName(q1).start()).processAllAvailable() Traceback (most recent call last): ... org.apache.spark.api.python.PythonException: Traceback (most recent call last): File stdin, line 1, in lambda ZeroDivisionError: division by zero ... pyspark.errors.exceptions.StreamingQueryException: [STREAM_FAILED] Query [id 74eb53a8-89bd-49b0-9313-14d29eed03aa, runId 9f2d5cf6-a373-478d-b718-2c2b6d8a0f24] terminated with exception: Job aborted解決修復(fù) StreamingQuery 中的錯誤并重新執(zhí)行工作流。SparkUpgradeException——因 Spark 升級而拋出典型如 Spark 3.0 起對日期時間格式解析行為的變化 from pyspark.sql.functions import to_date, unix_timestamp, from_unixtime df spark.createDataFrame([(2014-31-12,)], [date_str]) df2 df.select(date_str, to_date(from_unixtime(unix_timestamp(date_str, yyyy-dd-aa)))) df2.collect() Traceback (most recent call last): ... pyspark.sql.utils.SparkUpgradeException: You may get a different result due to the upgrading to Spark 3.0: Fail to recognize yyyy-dd-aa pattern in the DateTimeFormatter. 1) You can set spark.sql.legacy.timeParserPolicy to LEGACY to restore the behavior before Spark 3.0. 2) You can form a valid datetime pattern with the guide from https://spark.apache.org/docs/latest/sql-ref-datetime-pattern.html解決將spark.sql.legacy.timeParserPolicy設(shè)為LEGACY恢復(fù)舊行為或改用符合新規(guī)范的合法時間格式。 spark.conf.set(spark.sql.legacy.timeParserPolicy, LEGACY) df2 df.select(date_str, to_date(from_unixtime(unix_timestamp(date_str, yyyy-dd-aa)))) df2.collect() [Row(date_str2014-31-12, to_date(from_unixtime(unix_timestamp(date_str, yyyy-dd-aa), yyyy-MM-dd HH:mm:ss))None)]pandas API on Spark 常見異常ValueError: Cannot combine the series or dataframe because it comes from a different dataframe當(dāng)一次操作涉及多個不同 DataFrame 的 Series/DataFrame且compute.ops_on_diff_frames處于禁用狀態(tài)默認禁用時會拋出該錯誤。此類操作因需要 join 底層 Spark 幀而代價高昂僅在必要時才應(yīng)開啟該選項 ps.Series([1, 2]) ps.Series([3, 4]) Traceback (most recent call last): ... ValueError: Cannot combine the series or dataframe because it comes from a different dataframe. In order to allow this operation, enable compute.ops_on_diff_frames option.解決在option_context中顯式開啟后執(zhí)行 with ps.option_context(compute.ops_on_diff_frames, True): ... ps.Series([1, 2]) ps.Series([3, 4]) ... 0 4 1 6 dtype: int64PySparkRuntimeError: [RESULT_ROWS_MISMATCH] The number of output rows must match the number of input rowstransform等要求輸入輸出行數(shù)一致的操作返回行數(shù)不一致時拋出 def f(x) - ps.Series[np.int32]: ... return x[:-1] ... ps.DataFrame({x:[1, 2], y:[3, 4]}).transform(f) 22/04/12 13:46:39 ERROR Executor: Exception in task 2.0 in stage 16.0 (TID 88) org.apache.spark.api.python.PythonException: Traceback (most recent call last): ... pyspark.errors.exceptions.base.PySparkRuntimeError: [RESULT_ROWS_MISMATCH] The number of output rows (0) must match the number of input rows (1).解決確保變換函數(shù)保持行數(shù)一致 def f(x) - ps.Series[np.int32]: ... return x ... ps.DataFrame({x:[1, 2], y:[3, 4]}).transform(f) x y 0 1 3 1 2 4Py4J 層異常Py4JJavaError——Java 客戶端代碼中發(fā)生異常時拋出可以看到 Java 側(cè)拋出的異常類型及堆棧如java.lang.NullPointerException spark.sparkContext._jvm.java.lang.String(None) Traceback (most recent call last): ... py4j.protocol.Py4JJavaError: An error occurred while calling None.java.lang.String. : java.lang.NullPointerException ..解決傳入合法的參數(shù)。 spark.sparkContext._jvm.java.lang.String(x) xPy4JError——其他類錯誤時拋出例如 Python 客戶端訪問了一個在 Java 側(cè)已不存在的對象 from pyspark.ml.linalg import Vectors from pyspark.ml.regression import LinearRegression df spark.createDataFrame( ... [(1.0, 2.0, Vectors.dense(1.0)), (0.0, 2.0, Vectors.sparse(1, [], []))], ... [label, weight, features], ... ) lr LinearRegression( ... maxIter1, regParam0.0, solvernormal, weightColweight, fitInterceptFalse ... ) model lr.fit(df) model LinearRegressionModel: uidLinearRegression_eb7bc1d4bf25, numFeatures1 model.__del__() model Traceback (most recent call last): ... py4j.protocol.Py4JError: An error occurred while calling o531.toString. Trace: py4j.Py4JException: Target Object ID does not exist for this gateway :o531 ...解決訪問仍存在于 Java 側(cè)的對象。Py4JNetworkError——網(wǎng)絡(luò)傳輸出現(xiàn)問題時拋出如連接斷開。此時應(yīng)排查網(wǎng)絡(luò)鏈路并重建連接??刂贫褩W粉櫟膬蓚€關(guān)鍵配置Spark 提供兩個配置項控制異常堆棧的展示方式spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled默認 true簡化 Python UDF 與數(shù)據(jù)源Data Sources的 traceback避免輸出冗長的內(nèi)部調(diào)用鏈spark.sql.pyspark.jvmStacktrace.enabled默認 false隱藏 JVM 堆棧只展示 Python 友好的異常信息方便直接定位到 Python 側(cè)的錯誤位置。需要注意上述配置與日志級別設(shè)置相互獨立。日志級別請通過pyspark.SparkContext.setLogLevel控制。總結(jié)一條完整的 PySpark 排查鏈路把以上方法串聯(lián)起來即可形成一套可落地的排查流程進程定位用os.getpid()ps定位 Driver 進程用ps -fe | grep pyspark.daemon定位 executor worker 進程配合top觀察資源占用斷點調(diào)試Driver 側(cè)在腳本頂部插入pydevd_pycharm.settrace并配合spark-submitExecutor 側(cè)通過自定義模塊 spark.python.daemon.module配置包裝 worker 入口spark.python.worker.module也可類似地替換 worker 模塊實現(xiàn)兩端斷點性能剖析Driver 側(cè)用memory_profiler逐行統(tǒng)計內(nèi)存、cProfile統(tǒng)計 CPU 熱點UDF 側(cè)設(shè)置運行時配置spark.sql.pyspark.udf.profiler為memory或perf通過spark.profile的show/dump/render/clear查看、導(dǎo)出、可視化火焰圖并清理結(jié)果異常排除按異常類型AnalysisException、ParseException、IllegalArgumentException、PythonException、StreamingQueryException、SparkUpgradeException、Py4J 系列等對照錯誤信息定位根因必要時調(diào)整spark.sql.legacy.timeParserPolicy、compute.ops_on_diff_frames、spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled與spark.sql.pyspark.jvmStacktrace.enabled等配置。上述所有配置與 API 均可在當(dāng)前倉庫中找到實現(xiàn)依據(jù)配置定義、daemon 加載邏輯、Profile API 實現(xiàn)并結(jié)合 測試用例 與 內(nèi)存剖析測試 進一步驗證使用方式。贊分享大數(shù)據(jù)數(shù)據(jù)分析批處理流處理機器學(xué)習(xí)圖計算【免費下載鏈接】sparkApache Spark - A unified analytics engine for large-scale data processing項目地址https://gitcode.com/gh_mirrors/sp/spark點擊查看免費下載相關(guān)推薦5分鐘快速上手TDengine物聯(lián)網(wǎng)時序數(shù)據(jù)庫的完整部署指南 5分鐘快速上手TDengine物聯(lián)網(wǎng)時序數(shù)據(jù)庫的完整部署指南 你是否正在為海量物聯(lián)網(wǎng)設(shè)備數(shù)據(jù)存儲而煩惱面對每秒數(shù)萬條傳感器數(shù)據(jù)傳統(tǒng)數(shù)據(jù)庫早已不堪重負數(shù)據(jù)庫時序數(shù)據(jù)庫大數(shù)據(jù)物聯(lián)網(wǎng)云原生gVisor 沙箱調(diào)試完全指南從日志、strace 到棧轉(zhuǎn)儲與 pprof 性能剖析gVisor 沙箱調(diào)試完全指南從日志、strace 到棧轉(zhuǎn)儲與 pprof 性能剖析 本文是面向 gVisorApplication Kernel for云原生容器運行時操作系統(tǒng)應(yīng)用安全Cilium 調(diào)試完全指南從 Delve 附加調(diào)試到 toFQDNs 排障、鎖競爭分析與 pprof 性能剖析Cilium 調(diào)試完全指南從 Delve 附加調(diào)試到 toFQDNs 排障、鎖競爭分析與 pprof 性能剖析 本文以 Cilium 官方調(diào)試文檔為核心系統(tǒng)云原生網(wǎng)絡(luò)服務(wù)網(wǎng)格可觀測性網(wǎng)絡(luò)安全eBPF上一篇MyTinySTL中的函數(shù)綁定參數(shù)重排與占位符下一篇Bilibili-EvolvedTypeScript接口與類型別名區(qū)別與使用創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考