Mahi in Tech
Open in Telegram
688
Subscribers
-124 hours
+297 days
+2930 days
Posts Archive
688
وقتی صحبت از پیادهسازی Rate Limiting (مخصوصا مدلهایی مثل Token Bucket یا Leaky Bucket) میشه، معمولا اولین چالش، مدیریت State هست؛ اینکه همزمان باید تعداد توکنهای باقیمونده و زمان آخرین Refresh رو نگه داریم و حواسمون به Race Condition هم باشه.
الگوریتم GCRA (Generic Cell Rate Algorithm) که توی سیستمهای توزیعشده استفاده میشه، این مسئله رو با یک ترفند ریاضی خیلی ساده حل کرده: حذف مفهوم توکن و جابجایی همهچیز به بردار زمان.
ایده اصلی اینه: به جای اینکه چک کنیم کاربر چند تا توکن داره یا شمارنده رو ریست کنیم، یک متغیر عددی به اسم TAT (Theoretical Arrival Time) نگه میداریم؛ یعنی «زمان تئوریک رسیدن درخواست بعدی».
منطق کارکرد به چه صورته؟
فرض کنید لیمیت سیستم، ۱ درخواست در ثانیه باشه و به کاربر اجازه دادید تا سقف ۳ درخواست هم ترافیک ناگهانی (Burst) داشته باشه:
هر بار که یک درخواست تایید میشه، TAT به اندازهی فاصلهی زمانی مجاز بین درخواستها، به آینده هل داده میشه.
اگر کاربر چند درخواست پشت سر هم بفرسته، TAT جلوتر و جلوتر میره. در واقع داریم میزان «جلو افتادن» جریان درخواستها از نرخ مجاز رو اندازه میگیریم، و تا وقتی فاصلهی بین زمان فعلی و TAT از محدودهی مجاز Burst بیشتر نشده باشه، درخواستها تایید میشن.
اگر این فاصله از محدودهی مجاز عبور کنه، کاربر درجا خطای 429 میگیره و مهمتر اینکه TAT هم برای درخواست ردشده تغییر نمیکنه.
به محض اینکه کاربر چند ثانیه دست نگه داره، زمان فعلی به TAT نزدیکتر میشه و عملاً ظرفیت Burst بهصورت خودکار آزاد میشه؛ بدون اینکه هیچ Job پسزمینهای نیاز باشه یا کدی برای ریست کردن شمارندهها اجرا بشه.
در سادهترین حالت، منطق چیزی شبیه به اینه:
if now < TAT - tolerance:
reject
else:
TAT = max(now, TAT) + interval
accept
و قبل از آپدیت، بررسی میکنیم که آیا TAT در محدودهی مجاز قرار داره یا نه. نکتهی مهم اینه که مقدار دقیق این محدوده به نحوهی تعریف Burst/Tolerance در پیادهسازی بستگی داره.
چرا این مدل جذابه؟
۱. استیت تکمقداری: کل وضعیت هر کاربر فقط یک عدد ساده (Timestamp) هست که توی ردیس میتونه به صورت یک String ساده ذخیره بشه.
۲. اجرای اتمیک و جلوگیری از Race Condition: خود GCRA بهتنهایی Race Condition رو حذف نمیکنه؛ چیزی که این مشکل رو حل میکنه، اجرای اتمیک کل منطق Check + Update هست. مثلا میتونیم این کار رو با یک اسکریپت چند خطی Lua داخل Redis انجام بدیم، بدون اینکه چند دستور جداگانه بین Read و Write داشته باشیم.
۳. مدیریت تمیز TTL: چون زمان موردنیاز برای نگه داشتن State قابل محاسبه است، میتونیم TTL کلید رو بر اساس زمانی تنظیم کنیم که TAT و محدودهی Burst دیگه برای تصمیمگیری لازم نیستن. در نتیجه، کلیدها بهصورت خودکار expire میشن و نیازی به Job یا فرآیند جداگانه برای پاکسازی State نداریم.
در نهایت، جذابیت اصلی GCRA این هست که به جای نگه داشتن چند متغیر مثل Token Count، Last Refill و Timestamp، کل State رو به یک مفهوم زمانی تبدیل میکنه.688
توی سیستمهای High-Load، یکی از چالشهای همیشگی اینه که خیلی سریع بفهمیم یک دیتای خاص وجود داره یا نه. اگر بخوایم برای هر چک کردن ساده بهطور مستقیم سراغ دیتابیس بریم یا حتی به صورت کامل روی Cache حساب کنیم، هم منابع زیادی درگیر میشه و هم Latency بالا میره.
یکی از رویکردهای بهینه و جذاب برای حل این مسئله، استفاده از Bloom Filter هست.
بلوم فیلتر یک Data Structure احتمالاتی 🥴 هست که با کمترین میزان مصرف مموری و سرعت خیرهکننده، بهمون میگه یک آیتم وجود داره یا نه.
سناریوی واقعی: انتخاب یوزرنیم در تلگرام
تلگرام صدها میلیون کاربر داره. وقتی شما موقع ثبتنام داری یوزرنیم تایپ میکنی، به ازای هر کاراکتری که میزنی باید چک بشه که این یوزرنیم آزاد هست یا نه. اگر تلگرام بخواد برای هر تایپ شما یک کوئری به دیتابیس اصلیش بزنه، دیتابیس در عرض چند ثانیه از حجم درخواستها نابود میشه!
راهحل چیه؟ تلگرام تمام یوزرنیمهای ثبتشده رو میده به یک Bloom Filter که توی رم قرار داره. وقتی شما یوزرنیم جدید رو تایپ میکنی، بلوم فیلتر در کسری از میلیثانیه چک میکنه. اگر بگه «این یوزرنیم بهطور قطع وجود نداره»، تلگرام همون لحظه تیک سبز رو بهت نشون میده و دیگه کاری به دیتابیس نداره (صرفهجویی عظیم در منابع). اما اگر بلوم فیلتر بگه «ممکن هست وجود داشته باشه»، تلگرام تازه اونجا میره از دیتابیس میپرسه که "مطمئنی این یوزرنیم پر شده؟" تا وضعیت دقیق رو بهت بگه. (که البته تلگرام چنین کاری نمیکنه و مثال بود=))
حالا این بلوم فیلتر چطور کار میکنه؟
پشت صحنه، Bloom Filter در واقع فقط یک آرایه طولانی از Bitهاست که اول کار همهشون صفر هستن. در کنارش، چند تا تابع Hash مستقل و سریع هم داریم.
وقتی میخوایم یک دیتای جدید رو به سیستم اضافه کنیم، این دیتا رو به توابع Hash میدیم. خروجی این توابع، ایندکسهایی از همون آرایه بیتهاست. بعد میریم اون ایندکسها رو برابر با ۱ قرار میدیم.
موقع جستجو دوباره همون دیتای ورودی رو هش میکنیم و ایندکسها رو چک میکنیم:
۱. اگر حتی یکی از اون بیتها صفر باشه، سیستم با قطعیت ۱۰۰٪ میگه این دیتا «بهطور قطع وجود نداره».
۲. اگر همه بیتها ۱ باشن، سیستم میگه این دیتا «احتمالا وجود داره».
چرا میگیم احتمالا؟ چون ممکنه اون بیتها قبلا بهخاطر هش شدنِ دیتای دیگهای ۱ شده باشن (همون پدیده Hash Collision). یعنی ما توی Bloom Filter خطای False Positive داریم، اما False Negative اصلا نداریم.
البته که این ساختار محدودیتهای خودش رو هم داره؛ بهطور مثال حذف کردن یک آیتم از بلوم فیلتر در پیادهسازیهای استانداردش یهجورایی غیرممکنه؛ چون با صفر کردن یک بیت، ممکن هست دیتای دیگهای که از همون بیت استفاده میکرده رو هم خراب کنیم.
در نهایت، در ازای پذیرش اون احتمال کمِ False Positive، سیستمی به دست میاد که میتونه وجود میلیونها رکورد رو فقط با چند مگابایت RAM در لایه Application چک کنه و زیرساخت دیتابیس شما رو از شر درخواستهای بیهوده نجات بده.
688
Repost from Persian GitHub
نسخه جدید Oblivion منتشر شد!
هسته کلاینت کاملا تغییر کرده و Aether جایگزین هسته قبلی شده؛ با پشتیبانی از MASQUE H2/H3، WARP، GOOL و قابلیت Chain با Psiphon.
برای شبکههای محدود هم روی Scan و Obfuscation کار زیادی شده تا اتصال پایدارتر و سادهتر باشه.
https://github.com/bepass-org/oblivion/releases/tag/v8
🐙 @RepoFA
688
Repost from N/a
ما میدونیم (یا نمی دونیم) که LLM ها بدون حافظه ان. یعنی توی هر پیام جدید سیستم باید کل تاریخچه گفتگو رو از اول برای مدل بخونه تا بتونه یه کلمه جدید تولید کنه ( واسه همینه که توی چتای طولانی، کندتر عمل میکنه و به مراتب هرینه اش بالاتر میره).
قبلا میومدن و برای حل این مشکل از تکنیکی به اسم Prompt Caching استفاده میکردن، یعنی محاسبات قبلی ( KV Cache) رو ذخیره میکردن تا هزینه کمتر شه. ولی خب این کش فقط روی همون مدلی کار میکرد که پیداش کرده بود! 👀
اینا رو گفتم تا برسیم به اینکه انویدیا جدیدا چه کرده-
یه متد طراحی کرده که میشه KV Cache رو مستقیما به یه مدل دیگه منتقل کرد!
مرحله Prefill (همونجایی که کل تاریخچه گفتگو رو از اول میخونه) رو کلا دور می زنه و حافظه قبلی رو با فرمت مختص به خودش ترجمه میکنه.
ولی چطوری؟( ممنون~ شما چطوری؟)
-نگاشت خطی: فهمیدن که حتی بین مدلای متفاوت لایه شباهت ساختاری وجود داره
-ترکیب لایه ها: برای هر لایه در مدل مقصد، 8 لایه برتر از مدل مبدا رو ترکیب میکنن تا شباهت به 79 درصد برسه.
-دستکاری RoPE: چرخش های موقعیتی توکن ها رو موقتا برمیدارن، تبدیل ریاضی رو انجام میدن و بعد چرخش مدل جدید رو روش پیاده میکنن.
نتایج چطور بوده؟
• ۲.۷ تا ۲۵ برابر سریعتر از پردازش مجدد متن!
• حفظ ۷۳ تا ۹۸ درصد از دقت مدل مقصد.
این مدل فعلا روی مدل های هم خانواده تست شده ولی فعلا یه بن بست بزرگ رو شکسته توی انتقال حافظه.
688
+1
کپشنی ندارم، فقط تعداد استارها رو ببینید =))
چهار تا فایل Markdown
vs
کرنل لینوکس
688
اگه این روزها از Coding Agentها استفاده میکنید (که احتمالاً همهمون دیگه داریم میکنیم :) )، احتمالا اسم Graphify به گوشتون خورده؛ ابزاری که به ایجنت وصل میشه، کدبیس شما رو به یک گراف متنی تبدیل میکنه و با دادن دید کلی به ایجنت، باعث کاهش مصرف توکن میشه.
با پیشنهاد یکی از دوستان، مدتی هست به جای Graphify رفتم سراغ Codebase Memory MCP، و خب حداقل از نظر من تجربه بهمراتب بهتری بوده.
علاوهبر اینکه پروژه رو خیلی سریعتر ایندکس میکنه، مصرف توکنش حتی از Graphify هم کمتره و به لطف MCP بودنش، خیلی تمیز و بیدردسر با ایجنت همگام میشه. تازه UI گرافش هم خوشگلتره 😅
https://github.com/DeusData/codebase-memory-mcp
688
این سرویس از پارسال تا الان پیشرفت قابل توجهای داشته، تستش کنید حتما (با پرامپت مناسب).
من که لذت بردم.
البته هنوز Claude Design رو امتحان نکردم، ولی خب این Stitch به نسبت اینکه رایگان هستش خروجیهای قابل قبولی میده.
688
+1
دو روز پیش همینطوری رندوم داشتم نرخ لپتاپهای مختلف رو چک میکردم، که تب رو روی عکس سمت راست بستم و رفتم.
امروز تصادفی این تب رو مجدد باز کردم که با عکس سمت چپ مواجه شدم 😆
688
یک نمونهی خیلی ساده با CSharp که به کمک OpenCV یک واترمارک مشخص و محدود رو توی تصویر پیدا میکنه، و با یک overlay دیگه جایگزینش میکنه.
github.com/MahdiyarGHD/WatermarkSwapper
688
داشتم ریپوهای گیتهابم رو یه نگاهی میانداختم، که چشمم به این ریپو خورد که مال حدود ۴ ۵ سال پیشه 😄 اون زمان تازه بکاند و PHP کار میکردم و AI ای هم در کار نبود :)) اوج خلافام کپی کردن از stackoverlow بود و چقدر زود گذشت. عمرا فکر میکردم ۴ ۵ سال دیگه توی چنین بدبختی و وضعیتی دست و پا بزنیم.
github.com/MahdiyarGHD/KnightTour
این هم حدودا مربوط به یک سال بعدشه:
github.com/MahdiyarGHD/ToigBot
دیتابیسش فایل جیسونه 😁 و چقدر هم خوب کار میکرد. حالا هی بیا سیستم دیزاین کن 🙂↔️
688
البته طبق معمول تحریم هستیم و باید با شمارهی غیر ایران لاگین کنیم (با هزینهی 0.25$ از نامبرلند 🫤).
688
ظاهرا Nvidia دسترسی به API بیش از ۷۰ مدل زبانی (مثل Mistral ،Gemma ،DeepSeek ،Kimi و Qwen) رو بهصورت رایگان و بدون محدودیت خاصی فراهم کرده:
build.nvidia.com/models
688
Repost from نوشتههای ترمینالی
این مطلب رو سال ها پیش گذاشته بودم در مورد این که چطور با پروژه های سنگین برنامه نویسی، خودمون رو به چالش بکشیم و چیز جدید یاد بگیریم.
این مطلب قسمت دوم هم داره که لینکش رو در ادامه میگذارم. مورد علاقه مورد web browser متنیه. توضیحاتشو میتونید بخونید.
https://austinhenley.com/blog/morechallengingprojects.html
688
توی سیستمهای توزیعشده، هماهنگ نگه داشتن دادهها بین نودهای مختلف همیشه یکی از چالشهای مهم و البته جذاب بوده. مخصوصاً وقتی چند نود بهصورت همزمان امکان Write داشته باشن و انتظار بره دادهها در نهایت روی همه نودها به وضعیت یکسانی برسن.
یکی از رویکردهای قابل استفاده برای حل این مسئله، پیادهسازی Replication در لایه Application و بر بستر Event Streaming هست. در چنین معماریای، تغییرات داده بهجای اینکه مستقیماً از طریق مکانیزمهای Replication دیتابیس منتقل بشن، بهصورت Event منتشر و توسط سایر نودها مصرف میشن.
برای این کار، میشه تغییرات دیتابیس شامل Add, Update و Soft Delete رو در لحظه Commit شناسایی کرد و از طریق الگوی Outbox برای انتشار آماده کرد. از سمت مقابل نیز Consumerهایی مسئول دریافت این رویدادها، اعمال مکانیزمهای Idempotency و مدیریت خطاها از طریق DLQ خواهند بود تا تغییرات در مقصد بهصورت قابل اعتماد اعمال بشن.
در سناریوهای Multi-Master اینچنینی، اولین چالش جدی معمولاً مدیریت Conflict دادههاست. زمانی که چند نود بهطور مستقل روی یک رکورد تغییر ایجاد میکنن، باید مکانیزمی برای تعیین نسخه نهایی وجود داشته باشه. یکی از سادهترین و در عین حال رایجترین راهکارها، Last-Write-Wins (LWW) هست که در آن آخرین تغییر ثبتشده بر اساس زمان وقوع، بهعنوان نسخه معتبر در نظر گرفته میشه.
چالش مهم بعدی به شناسههای داده برمیگرده. در معماریهایی که چند نود بهصورت مستقل داده تولید میکنن، استفاده از Primary Keyهای Auto-Increment معمولاً به تداخل منجر میشه. به همین دلیل استفاده از شناسههای Globally Unique اهمیت پیدا میکنه. GUID v7 یکی از گزینههای جذاب برای این سناریوهاست؛ چون علاوه بر یکتا بودن، به دلیل داشتن Timestamp داخلی، قابلیت Sort شدن داره و نسبت به GUIDهای سنتی رفتار بهتری از نظر ایندکسگذاری ارائه میکنه.
ممکنه این سؤال مطرح بشه که چرا بهجای چنین رویکردی از Replication نیتیو دیتابیس استفاده نشه؟ پاسخ اینه که در بسیاری از موارد، مسئله صرفاً انتقال داده بین چند دیتابیس مشابه نیست. گاهی نیاز داریم کانفلیکتها در لایه Application مدیریت بشن، دادهها قبل از اعمال شدن دچار Transformation بشن یا حتی نودها از تکنولوژیهای ذخیرهسازی متفاوتی استفاده کنن.
مزیت دیگهی این رویکرد، وجود یک Log پایدار از تمام تغییرات سیستم هست. با استفاده از Kafka، رویدادها برای مدت مشخصی نگهداری میشن و هر Consumer میتونه مستقل از سایر اجزا وضعیت خودش رو بازیابی کنه. در نتیجه اگر نودی برای مدت طولانی از دسترس خارج بشه، پس از بازگشت میتونه از آخرین Offset پردازششده ادامه بده و خودش رو با وضعیت فعلی سیستم همگام کنه.
از طرفی، Eventهایی که برای Replication تولید میشن معمولاً کاربردشون به همینجا محدود نمیمونه. همون جریان رویداد میتونه توسط سرویسهای دیگه برای Cache Invalidation، Analytics، Audit Logging، Search Indexing یا انواع پردازشهای جانبی مصرف بشه. به همین دلیل، مکانیزم همگامسازی عملاً به بخشی از زیرساخت Event-Driven کل سیستم تبدیل میشه.
پیادهسازی چنین معماریای قطعاً بدون هزینه نیست و پذیرش Eventual Consistency هم چالشهای خودش رو به همراه داره. اما در ازای این پیچیدگی، سیستمی به دست میاد که نودها میتونن مستقل عمل کنن، کانفلیکتها بهصورت کنترلشده مدیریت بشن و همگامسازی دادهها بدون وابستگی مستقیم به نوع دیتابیس یا ساختار استقرار انجام بشه.
688
pypi.org
151.101.128.223
docs.github.com
185.199.109.154
www.fastly.com
151.101.65.57
repo.almalinux.org
151.101.3.52
اگر امکان پینگ گرفتن ندارید این مقادیر رو امتحان کنید.
688
Repost from Patt's Channel
الان رو فستلی خیلی از سایتها رو باز کردن، سایفون از فستلی هم میتونه برای اتصال استفاده کنه، کافیه تو اپ شیرو خورشید برای اندروید یا se7en pro برای ویندوز (یا کانفیگهای mitm+psiphon)یک دامنه سفید پشت فستلی قرار بدید:
github.githubassets.com
docs.github.com
www.fastly.com
pypi.org
repo.almalinux.org
...
برای ip هم هر دامنه ای که قرار دادید ازش ping بگیرید و ip که بهتون دادو قرار بدید، دقت کنید ip و sni باید مچ هم باشن یعنی هر sni که قرار دادید ip همونو باید وارد کنید.
هم به دلیل محدودیت های سایفون و هم به دلیل تعداد بالای کاربران سرعت متوسطی بهتون میده این روش.
