اگر توسعهدهندهای هستید که با دادههای گراف سروکار دارید، دیگر نیازی نیست ساعتها وقت خود را صرف نوشتن فراخوانیهای دستی HTTP یا کلنجار رفتن با پروتکلهای دیتابیسهای دیگر کنید. در ۹ سپتامبر ۲۰۲۶، تیم ArcadeDB مجموعهای از کلاینتهای بومی برای پایتون و تایپاسکریپت/جاوااسکریپت منتشر کرد که پلی مستقیم و ایمن (Type-safe) به این پایگاهداده چندمدلی ایجاد میکند.
تا پیش از این، تعامل با ArcadeDB از طریق Node یا Python به معنای پذیرش محدودیتهای یک API مدل REST یا استفاده از زیرمجموعهای از پروتکلهای دیتابیسهای دیگر بود. این وضعیت باعث میشد توسعهدهندگان بیش از آنکه روی دادهها تمرکز کنند، درگیر مدیریت لایه انتقال داده شوند و در محیطی «غیربومی» فعالیت کنند. همانطور که در تحلیلهای قبلی ما دربارهی بهینهسازی لایههای دسترسی به داده اشاره کردیم، حذف اصطکاک در لایه انتقال، سرعت توسعه را بهشدت افزایش میدهد. در واقع، این درایورها مانند یک مترجم همزمان و متخصص عمل میکنند که بهجای اینکه شما هر جمله را تکهتکه ترجمه کنید، کل مفهوم را بهطور مستقیم و بدون خطا به زبان مقصد منتقل میکند.
ماتریس درایورها
به نقل از گزارش رسمی arcadedb.com، مخزن جدید arcadedb-drivers شامل چهار بسته مجزا است که بر اساس پروتکل انتقال و زبان برنامهنویسی دستهبندی شدهاند. هر چهار بسته تحت لایسنس Apache-2.0 منتشر شدهاند و در حال حاضر در نسخه ۰.۱.۰ هستند که نشاندهنده این است که این ابزارها در مرحله توسعه شدید قرار دارند:
- پایتون (HTTP): بسته
arcadedb-driver(نصب از طریقpip install arcadedb-driver) - پایتون (gRPC): بسته
arcadedb-driver-grpc(نصب از طریقpip install arcadedb-driver-grpc) - تایپاسکریپت/JS (HTTP): بسته
@arcadedb/driver(نصب از طریقnpm install @arcadedb/driver) - تایپاسکریپت/JS (gRPC): بسته
@arcadedb/driver-grpc(نصب از طریقnpm install @arcadedb/driver-grpc)
این درایورها بهطور خاص برای نسخه ۲۶.۹.۱ سرور ArcadeDB هدفگذاری شدهاند. در فایل README هر بسته، یک جدول سازگاری وجود دارد که نسخههای درایور را به نسخههای سرور متصل میکند. کلاینتهای پایتون به نسخه ۳.۱۰ یا بالاتر نیاز دارند، در حالی که کلاینتهای تایپاسکریپت نیازمند Node ۲۰+ هستند و بهصورت ESM-only عرضه شدهاند؛ به این معنا که باید از دستور import بهجای require استفاده شود.
انتخاب بین HTTP و gRPC
ArcadeDB دو نوع پروتکل انتقال را ارائه میدهد زیرا حجمهای کاری مختلف، ویژگیهای عملکردی متفاوتی را میطلبند. درایور HTTP نقطه شروع توصیه شده برای اکثر کاربران است. این درایور در هر محیطی کار میکند، به حداقل وابستگیها (مانند fetch یا httpx) نیاز دارد و تنها گزینه برای کدهایی است که در مرورگر اجرا میشوند. این رویکرد بهینهسازی در لایههای انتقال یادآور تغییرات اخیر در SDK پایتون OpenAI است که برای بهبود مدیریت کلاینتهای HTTP به httpx2 مهاجرت کرد. این گزینه برای ترافیکهای معمولی درخواست-پاسخ، توابع بدون سرور (Serverless) که با مشکل راهاندازی سرد (Cold Start) — شبیه به گرم شدن موتور ماشین در یک صبح زمستانی قبل از حرکت — روبرو هستند و محیطهایی که توسعهدهندگان میخواهند از زیرساختهای HTTP موجود مانند پروکسیها، گیتویها و سیستمهای Tracing استفاده کنند، ایدهآل است.
در مقابل، درایور gRPC برای ارتباطات سرور-به-سرور طراحی شده است، جایی که توان عملیاتی (Throughput) گلوگاه اصلی است. این درایور بهطور خاص برای موارد زیر بهینه شده است:
- خواندن مجموعههای بزرگ داده از طریق استریم (Streaming)
- درج دستهای (Bulk-insert) دادهها از طریق اتصالات طولانیمدت
- ترافیکهای شدید، مستمر و با توان عملیاتی بالا
- استریم دوطرفه بومی (Native bidirectional streaming)
یک نکته حیاتی این است که درایور gRPC در مرورگر قابل استفاده نیست. دلیل این محدودیت آن است که GrpcServerPlugin سرور، صرفاً یک grpc-java روی HTTP/2 است که بر پایه Netty ساخته شده و فاقد هندلر gRPC-Web، پروتکل Connect یا آداپتور servlet است. بنابراین، تبهای مرورگر نمیتوانند فریمهای خام HTTP/2 gRPC مورد نیاز سرور را ارسال کنند و کدهای مرورگر حتماً باید از درایور HTTP استفاده کنند.
اتصال و اجرای کوئریها
برای کسانی که با HTTP شروع میکنند، درایورهای پایتون هر دو الگوی همگام (Synchronous) و ناهمگام (Asynchronous) را ارائه میدهند. رویکرد همگام از ArcadeDBServer و basic_auth استفاده میکند، در حالی که نمای ناهمگام با استفاده از AsyncArcadeDBServer و asyncio دقیقاً همان متدها را بازسازی میکند. هر دو بهعنوان Context Manager عمل میکنند زیرا مالک یک کلاینت httpx با استخر اتصالات (Connection Pool) هستند که باید در پایان آزاد شود.
یک جزئیات عملیاتی مهم: اگر مقدار timeout را ننویسید، بهجای بازگشت به پیشفرض پنج ثانیهای httpx در پایتون، تایماوت بهطور کامل غیرفعال میشود. توسعهدهندگان باید یک httpx.Timeout را پاس دهند تا اطمینان حاصل کنند که درخواستها محدود میمانند.
در تایپاسکریپت، این فرآیند از طریق createClient و basicAuth ساده شده است. برای احراز هویت، هر دو زبان از توکنهای Bearer (مانند توکنهای نشست حاصل از /api/v1/login) از طریق جایگزینی احراز هویت پایه با bearer_auth یا bearerAuth پشتیبانی میکنند.
به دلیل چندمدلی بودن ArcadeDB، پارامتر language در فراخوانیهای کوئری نقش کلیدی دارد. چه از "sql" استفاده کنید، چه از "cypher" یا "gremlin"، از یک فراخوانی کوئری واحد استفاده میشود و درایور نسبت به زبان انتخابی بیتفاوت است.
پاکت نتایج «برشخورده» (Truncated)
هیچکدام از درایورهای HTTP یک آرایه ساده از ردیفها را برنمیگردانند. در عوض، آنها یک QueryEnvelope را بازمیگردانند که شامل آرایه result، مقدار limit (حد)، تعداد ردیفهای returned (بازگشتی) و یک مقدار بولی به نام truncated است.
این طراحی مشکلی رایج در محیطهای عملیاتی را حل میکند: وقتی سریالساز سرور به سقف ردیفهای مجاز میرسد، یک پاسخ ناقص دقیقاً شبیه به یک پاسخ کامل اما کوتاه به نظر میرسد. برای مثال، یک آرایه ۵۰۰۰ ردیفی که زودتر از موعد متوقف شده است، از آرایهای که صرفاً رکوردهای تطبیقیافتهاش تمام شده، قابل تشخیص نیست. اگر truncated برابر با true باشد، توسعهدهنده میفهمد که باید کوئری را با فیلتر محدودتر یا لیمیت بالاتر تکرار کند.
با این حال، اگر نتیجه از سقف سخت تعریف شده در arcadedb.server.httpQueryMaxResultRows فراتر رود، سرور بهجای برش دادن نتایج، درخواست را با خطای ۴۱۳ (Payload Too Large) رد میکند. در این حالت، تنها راه پیش روی توسعهدهنده استفاده از فیلترهای محدودتر است.
مدیریت تراکنشها
تراکنشها با استفاده از اصطلاحات بومی هر زبان مدیریت میشوند. پایتون از Context Managerها استفاده میکند (with srv.db("mydb").transaction() as tx:)، در حالی که تایپاسکریپت از الگوی Callback بهره میبرد (await db.transaction(async (tx) => { ... })).
یک قانون کلیدی برای هر دو زبان این است که تمام فراخوانیهای تراکنشی باید از طریق هندل تراکنش (tx) انجام شوند و نه از طریق شیء دیتابیس بیرونی. هر فراخوانی که از طریق هندل بیرونی در حالی که یک تراکنش باز است انجام شود، بهطور خودکار و بهصورت مستقل Commit شده و کل تراکنش را دور میزند.
قرارداد Commit و Rollback از سه بند پیروی میکند:
۱. اگر بلوک کد بدون خطا خارج شود، تراکنش Commit میشود.
۲. اگر بلوک کد استثنایی (Exception) ایجاد کند، تراکنش Rollback میشود. اگر خودِ عملیات Rollback نیز شکست بخورد، این شکست بهعنوان __cause__ (در پایتون) یا err.cause (در تایپاسکریپت) ضمیمه میشود.
۳. اگر خودِ عملیات Commit شکست بخورد، ابتدا یک Rollback با «بهترین تلاش» (Best-effort) صادر میشود تا از باز ماندن نشست در سمت سرور تا زمان انقضای arcadedb.server.httpTxExpireTimeout جلوگیری شود.
استریم با کارایی بالا با gRPC
برای مجموعهدادههای عظیم، درایورهای gRPC جایگزین صفحهبندیهای (Paging) مکرر HTTP میشوند و یک استریم واحد را جایگزین میکنند. این درایورها بهجای URL از فرمت بومی host:port استفاده میکنند. چون طرحی (Scheme) برای تجزیه وجود ندارد، کاربران باید صراحتاً insecure=True را تنظیم کنند یا برای TLS از grpc.ssl_channel_credentials() استفاده کنند.
ویژگی raw دسترسی به Stub تولید شده برای کل ArcadeDbService را فراهم میکند و باعث میشود هر RPC در قرارداد در دسترس باشد. برای سادهسازی کارهای رایج، کلاینتها Wrapperهایی برای stream_query ، insert_stream و transaction اضافه کردهاند.
تابع streamQuery در تایپاسکریپت، دستههای ردیفهای سرور را به یک تکرار ردیف-به-ردیف تبدیل میکند. کاربران میتوانند از سه حالت بازیابی استفاده کنند:
- CURSOR (پیشفرض): کوئری یکبار اجرا شده و نتایج هنگام پیمایش استریم میشوند. این حالت برای محدود کردن مصرف حافظه در مجموعههای بزرگ نتایج بهترین است.
- MATERIALIZE_ALL: ابتدا کل مجموعه نتایج در سرور بارگذاری و سپس در دستههای مختلف ارسال میشود. این حالت برای اسنپشاتهای پایدار مناسب است.
- PAGED: کوئری با LIMIT/SKIP برای هر دسته مجدداً اجرا میشود. این حالت زمانی مفید است که سازگاری (Consistency) هر دسته باید مستقل باشد.
عملیات درج از طریق insert_stream بهینه شده است که یک iterable ناهمگام از دستههای ردیف را میپذیرد. درایور بهطور خودکار مدیریت پیچیده حسابداری را انجام میدهد: حفظ یک ID نشست پایدار، افزایش chunk_seq از عدد ۱، تنظیم دیتابیس در اولین دسته (Chunk) و علامتگذاری آخرین دسته با last: true.
امنیت و لایه انتقال
درایورهای gRPC یک قانون امنیتی سختگیرانه در مورد رمزهای عبور اعمال میکنند. چون password_auth رمزها را بهصورت متن ساده در متادیتای gRPC میفرستد، اگر create_client با کانالی جفت شود که گواهینامه انتقال (Transport Credentials) ندارد، خطای InsecureChannelError صادر میشود. برای دور زدن این مورد، توسعهدهنده باید صراحتاً insecure=True را پاس دهد. توکنهای Bearer این محدودیت را فعال نمیکنند زیرا بهعنوان رمز عبور تلقی نمیشوند.
معماری قرارداد-محور (Contract-First)
برای جلوگیری از «پوسیدگی خاموش» (Silent Rot) که در درایورهای دستنویس رایج است، ArcadeDB از طراحی قرارداد-محور استفاده میکند. دایرکتوری contracts/ در مخزن، مشخصات OpenAPI برای HTTP و فایل .proto برای gRPC را در خود جای داده است. این فایلها مستقیماً از ArcadeDB دریافت میشوند و بهصورت دستی نگهداری نمیشوند. این رویکرد مشابه سیستم MonkeyCode است که برای جلوگیری از ناسازگاری در اپلیکیشنهای قدیمی، قراردادهای API را بهصورت خودکار بهروزرسانی میکند.
هر Build شامل یک «دروازه انحراف» (Drift Gate) است؛ اگر کد تولید شده با بازتولید تازه از قرارداد سرور همخوانی نداشته باشد، Build شکست میخورد. این تضمین میکند که کلاینت هرگز نسخهای از سرور را توصیف نمیکند که دیگر وجود ندارد. این معماری به تیم اجازه میدهد تا زبانهای جدید را صرفاً با نوشتن یک پیکربندی Generator اضافه کنند، بهجای اینکه دوباره سورسکد سرور را بخوانند.
علاوه بر این، تمام انتشارها توسط انسانها از طریق CI workflow dispatch تحریک میشوند. بستههای npm دارای گواهیهای Provenance هستند و بستههای PyPI از Trusted Publishing استفاده میکنند تا توکنهای طولانیمدت را از زنجیره حذف کنند.
تحلیل: انتقال بار یکپارچهسازی
این حرکت نشاندهنده تغییری در نحوه برخورد دیتابیسهای چندمدلی با تجربه توسعهدهنده (DX) است. با خودکارسازی تولید درایورها از طریق قراردادها، ArcadeDB با API خود بهجای مجموعهای از نقاط انتهایی (Endpoints) سست، بهعنوان یک مشخصات سخت محصول برخورد میکند. این کار «مالیات یکپارچهسازی» را برای توسعهدهندگانی که پیش از این مجبور به نگهداری کتابخانههای Wrapper سفارشی بودند، کاهش میدهد.
برای کاربر نهایی، برد واقعی قابلیت استریم gRPC است. در دیتابیسهای گراف، جایی که کوئریها اغلب لیستهای مجاورتی عظیم یا عمیقاً تودرتو را برمیگردانند، توانایی استریم ردیفها بدون سربار صفحهبندی HTTP، یک ضربکننده عملکرد (Performance Multiplier) قابل توجه برای خط لولههای مهندسی داده است.
گامهای بعدی
این درایورها در حال حاضر در مرحله توسعه شدید هستند (v0.1.0). اگرچه APIهای فعلی قصد دارند دائمی باشند، اما برخی ممکن است قبل از نسخه ۱.۰ تغییر کنند. به توسعهدهندگان توصیه میشود نسخهها را پین کنند و Changelog را زیر نظر بگیرند.
زبانهای بیشتری در برنامه است و مخزن از همین حالا برای ظهور دایرکتوریهای go/ و سایر زبانها در کنار پوشههای پایتون و تایپاسکریپت ساختاریافته است. کاربران میتوانند از طریق Issues و Pull Requestها در github.com/ArcadeData/arcadedb-drivers مشارکت کنند.
گام بعدی شما
- اگر از ArcadeDB استفاده میکنید، درایورهای جدید را جایگزین فراخوانیهای دستی REST کنید تا خطاهای Type-mismatch کاهش یابد.
- برای خط لولههای داده (Data Pipelines) با حجم بالا، حتماً از درایور gRPC و حالت
CURSORبرای جلوگیری از اشباع حافظه استفاده کنید. - نسخههای درایور را در فایل
requirements.txtیاpackage.jsonپین کنید، زیرا نسخه ۰.۱.۰ احتمال تغییرات API را دارد.
اما داستان بهینهسازیهای زیرساختی در این دیتابیس به اینجا ختم نمیشود؛ برای درک نحوه مدیریت حافظه در گرافهای عظیم، تحلیل ما دربارهی موتور ذخیرهسازی ArcadeDB را بخوانید.




گفتگو