لینک کوتاه مطلب : https://hsgar.com/?p=6831

الگوی شمارنده شکافدار

این یک الگوی پایگاه داده رایج برای افزایش an است INT ستون زمانی که رویدادی رخ می دهد، مانند دانلود یا مشاهده صفحه.

شما می توانید با این الگو خیلی پیش بروید تا زمانی که این نوع رویدادها به طور موازی اتفاق بیفتند و در یک ردیف منازعه را تجربه کنید. هنگامی که چندین تراکنش در تلاش برای به روز رسانی شمارنده هستند، شما اساساً این تراکنش ها را مجبور به اجرای سریال می کنید، که برای همزمانی بد است و می تواند باعث بن بست شود. شما همچنین می توانید افزایش چشمگیر در زمان پرس و جو را در هنگام وقوع انفجارهای مشابه مشاهده کنید.

با اجرای موارد زیر می‌توانید بررسی کنید که آیا در حال مشاجره هستید:

SHOW ENGINE INNODB STATUSG

در خروجی، اطلاعاتی در مورد اعطای قفل خواهید دید:

---TRANSACTION 79853106, ACTIVE 5 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1128, 1 row lock(s)
MySQL thread id 24, OS thread handle 6281670656, query id 107 localhost root updating
UPDATE slotted_counters SET count = count + 1 WHERE id = 1
------- TRX HAS BEEN WAITING 5 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2 page no 4 n bits 184 index PRIMARY of table `github`.`downloads` trx id 79853106 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 000004c27630; asc     v0;;
 2: len 7; hex 020000017d0ce9; asc     }  ;;
 3: len 4; hex 8000007b; asc    {;;
 4: len 4; hex 800001c8; asc     ;;
 5: len 4; hex 80000019; asc     ;;
 6: len 4; hex 8230df9b; asc  0  ;;

می بینید که این تراکنش مدت زمان قابل توجهی را برای به دست آوردن یک قفل برای افزایش شمارنده در این سطر منتظر مانده است. با سایر معاملات رقیب در تضاد است.

MySQL پایگاه داده اصلی است GitHub.comو در آن زمان، زمانی که تعدادی از افراد PlanetScale در آنجا کار می‌کردند، ما مجبور بودیم این نوع شمارش را متفاوت انجام دهیم. ما تصمیم گرفتیم از یک جدول جداگانه با طرحی مشابه این استفاده کنیم:

CREATE TABLE `slotted_counters` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `record_type` int(11) NOT NULL,
  `record_id` int(11) NOT NULL,
  `slot` int(11) NOT NULL DEFAULT '0',
  `count` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `records_and_slots` (`record_type`,`record_id`,`slot`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
  • record_type – نوع شمارنده (به ما امکان می دهد جدول را عمومی نگه داریم)
  • record_id – هر چیزی را که می‌شماریم شناسایی می‌کند، برای مثال می‌تواند به شناسه مخزن نگاشت شود
  • slot – شکافی که قرار است آن را افزایش دهیم
  • count – تعداد هر شکاف

یک پرس و جو افزایشی معمولی به صورت زیر است:

INSERT INTO slotted_counters(record_type, record_id, slot, count)
VALUES (123, 456, RAND() * 100, 1) 
ON DUPLICATE KEY UPDATE count = count + 1;

ایده اینجا این است که به جای افزایش یک ردیف برای شمارنده، اکنون در حال انتخاب یک شکاف و افزایش تعداد در آن شکاف هستیم. این بدان معناست که به‌جای چکش‌کاری یک ردیف، به‌روزرسانی‌ها را در 100 ردیف پخش می‌کنیم و احتمال اختلاف را کاهش می‌دهیم.

زمانی که موارد بالا را اجرا کردیم INSERT چند بار می‌توانیم ردیف‌های شمارنده را ببینیم:

mysql> select * from slotted_counters;

+----+-------------+-----------+------+-------+
| id | record_type | record_id | slot | count |
+----+-------------+-----------+------+-------+
|  1 | 123         |       456 |    2 |     1 |
|  2 | 123         |       456 |   52 |     1 |
|  3 | 123         |       456 |   55 |     1 |
|  4 | 123         |       456 |    0 |     3 |
|  7 | 123         |       456 |   48 |     1 |
|  8 | 123         |       456 |   20 |     1 |
|  9 | 123         |       456 |   56 |     1 |
| 10 | 123         |       456 |   18 |     1 |
| 11 | 123         |       456 |   22 |     1 |
| 12 | 123         |       456 |   58 |     1 |
| 13 | 123         |       456 |   23 |     1 |
+----+-------------+-----------+------+-------+
11 rows in set (0.00 sec)

گرفتن شمارش برای record_id 456 به همین سادگی است SELECT پرس و جو:

SELECT SUM(count) as count FROM slotted_counters
WHERE (record_type = 123 AND record_id = 456);

اکنون می‌توانیم درخواست‌هایی داشته باشیم که افزایش‌های شمارنده را به صورت موازی اجرا می‌کنند، بدون اینکه باعث اختلاف و ایجاد همزمانی شوند.

چند راه مختلف وجود دارد که می توانید این الگو را پیاده سازی کنید، اما این به معماری برنامه شما بازمی گردد. یکی از راه ها این است که پرس و جو کنید slotted_counters جدول برای جمع کردن داده ها و به روز رسانی یک ستون ذخیره شده با بقیه داده ها.

لینک منبع

ارسال یک پاسخ

آدرس ایمیل شما منتشر نخواهد شد.