با من همراه باشید | پر بودن دیسک سنتری و خالی کردن آن

سلام، سلام، بعد از ماه‌ها یه کوچولو وقت اضافی گیر آوردم و دارم توی ویرگول مینویسم؛ اوایل متن یه خورده داستان سرایی داریم، بخاطر همین اگه میخواید فقط بعد فنی مطلب رو ببینید باید یکم برید پایین تر تا به تیتر اول برسید :))، من به تازگی به تیم زیرساخت هولدینگ پگاه (شرکت مادرِ تپسل، مدیااد، فانتوری، متریکس و چندین محصول دیگه) اضافه شدم و به عنوان یه نیرویی که قراره کلی چیزای جدید یاد بگیره، کلی انگیزه دارم برای مسیر جدیدی پیش روم قراره گرفته.

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

بعد از گذشت دو هفته، در جلسه Weekly (که توی این جلسه برنامه و تسک‌های 2 هفته آینده هرکدوم از اعضای تیم رو مشخص می‌کنیم) بحث‌های زیادی مطرح شد و تسک‌های مختلف به هرکدوم از بچه‌ها اساین شد، میون صحبت‌ها بحث از پر بودن درصد زیادی از دیسک Sentry شرکت شد.

سنتری چیه؟ نرم‌افزاری هستش که به شما کمک میکنه که با اضافه کردن چند خط کد به پروژه ای که داری، تمام اررورهای پروژه رو هل بدی سمت خودش و اون برات سازمان دهی‌شون کنه و همینطور با کلی ابزار خفن (مثل integration با Gitlab) کمک میکنه که بعد از مراحل Production از سمت کاربر‌ها Feedback بگیری و کد اصلی رو بهینه کنی و باگ‌ها و مشکلات رو برطرف کنی. که هم به صورت Self-Hosted و opensource کار میکنه و هم میتونین از سایت خودش استفاده کنین و پلن متناسب با کارتون رو خریداری کنید.

https://sentry.io/

شروع بعد فنی داستان

تا اینجا گفتیم که سرور سنتری شرکت Diskش پر شده بود و میخواستیم راه خالی کردنش رو پیدا کنیم.

حالا مشکل چی بود؟ خب اینجا شروع سختی داستان بود، چون بچه‌ها میخواستن سطح علمی من رو بسنجن، قرار بر این شد به‌جز دسترسی SSH سرور و محل نصب سنتری به من هیچ اطلاعات دیگه ای داده نشه 😁

با سپهر که از بچه‌های تیم بود صحبت کردیم.یه مقداری راهنمایی کرد و اطلاعاتی که بالا گفتم رو پاس داد سمت من. اطلاعات چی بود؟ اینکه سنتری ما به صورت docker-composeی نصب شده، فایل‌ها و بقیه موارد هم توی پوشه /opt هست و ما نهایتا دیتای 2 هفته اخیر رو میخوایم نه بیشتر ضمنا اگه بخوای به صورت معمول با خود سنتری cleanup کنی، سی پی یو سرور 100 درصد میشه و سنتری به صورت کلی داون میشه پس اینکار رو هم نمیشه انجام داد.

اولین قدم این بود که بفهمیم کلا چندگیگ مصرف شده و چندگیگ خالی داریم برای اینکار از دستور

df -h /

استفاده کردم و مشخص شد که 93 درصد فضا پر هست و عملا 19 گیگ بیشتر نداریم.

Storage Usage/About 93 Percent
Storage Usage/About 93 Percent

فرض رو بر این گرفتیم که میخوایم دیتا رو پاک کنیم فقط، برای اینکار لازم بود بدونیم که چه چیزی این فضارو گرفته و کلا سنتری کجا دیتارو نگه میداره، راه اول این بود که بریم توی اینترنت سرچ کنیم و به راحتی کامپوننت‌های سنتری رو پیدا کنیم و به جواب برسیم. ولی خب همه نرم‌افزارها مثل سنتری با ادب و Fully Documented نیستن که، ازونجایی که من همیشه دنبال تجربه کردن هستم، تصمیم گرفتم با روش اصولی پیداش کنم.

بالاتر گفته بودم که سنتری شرکت ما به صورت داکری اومده بود بالا و راهش این بود که ببینم کدوم volume بیشترین حجم رو گرفته. یکم سرچ و تحقیق کردم به یه مطلب جالب داخل سایت medium برخوردم.

https://medium.com/homullus/how-to-inspect-volumes-size-in-docker-de1068d57f6b

توی این آموزش اومده بود که با استفاده از دستور:

$ docker system df -v
...
Local Volumes space usage:
VOLUME NAME                                  SIZE
sentry-self-hosted_sentry-smtp-log           1.609kB
sentry-self-hosted_sentry-zookeeper-log      939.5MB
sentry-clickhouse                            36.73GB
....
sentry-postgres                              145.8GB
sentry-redis                                 550.9MB
sentry-self-hosted_sentry-kafka-log          0B
sentry-self-hosted_sentry-smtp               1.236kB
...

می‌شه اطلاعات تمامی volumeهارو به همراه حجمشون به دست آورد. بین volumeها Postgres توجهم رو جلب کرد! 62.5 درصد از حجم دیسک توسط پستگرس اشغال شده بود، می‌شد نتیجه گرفت که دیتای سنتری داخل پستگرس ذخیره میشه.

اگه میخواید بدونید دیتابیس PostgreSQL چی هست. به وبسایتش سر بزنید:

https://www.postgresql.org/

پس تا اینجا نتیجه میگیریم که باید دیتابیس PostgreSQL رو خالی کنیم و تمامی دیتاهای قدیمی رو تا 14 روز قبل پاک کنیم. (اینجا بگم که من تجربه زیادی از کارکردن با postgres نداشتم و فقط یه دیدگاه اولیه ای نسبت بهش داشتم)

میدونستم که برای اجرای کوئری و پاک کردن دیتاها باید وارد کنسول کانتینتر postgres بشم و به کنسول خود دیتابیس وصل بشم. برای اینکار اجرای 2 تا دستور کافی بود.

$ docker exec -it sentry-self-hosted-postgres-1 bash
root@d75asdfdsa3:/# psql -U postgres
psql (9.6.24)
Type &quothelp&quot for help.

postgres=#
Logging into PostgresSQL Console
Logging into PostgresSQL Console

ایول! الان به کنسول postgres وصل شدیم و فقط مونده لیست دیتابیس هارو بگیریم. وارد دیتابیس موردنظرمون بشیم و تیبل مربوط به Eventهای سنتری رو پاک کنیم (البته تا اینجای کار نمیدونستم آیا پاک کردن این Eventها ممکنه باعث کرش کردن sentry بشه یا نه، برای همین با کمک سید (یکی دیگه از اعضای تیم) یک Clone از سرور گرفتیم تا دستورات رو اول توی یه محیط Safe تست کنیم و بعد وارد سرور اصلی و Production کنیم)

برای گرفتن لیست دیتابیس‌ها عبارت

postgres=# \l

رو وارد کنسول postgres میکنیم:

Database List from PostgreSQL Console
Database List from PostgreSQL Console

همونطور که مشاهده میکنید اینجا 3 تا دیتابیس داریم. من از روی غریزه دیتابیس اولی رو انتخاب کردم و تصمیم گرفتم داخل اون یکم گشت‌و‌گزار کنم.

برای انتخاب دیتابیس از دستور زیر استفاده میکنیم:

postgres=# \c postgres
You are now connected to database &quotpostgres&quot as user &quotpostgres&quot.
postgres=#

خب، الان وارد دیتابیس شدیم، وقتشه که لیست Table هارو بگیریم و ببینیم کدومشون حجم بیشتری رو گرفته:

PostgreSQL list of tables
PostgreSQL list of tables

این دستور یک لیست از Tableهای توی دیتابیس بهمون میده، ولی این اطلاعات کافی نیست، باید بفهمیم هر جدول چه فضایی رو اشغال کرده. داخل اینترنت یکم سرچ کردم و در نهایت به کوئری زیر رسیدم:

select table_name, pg_relation_size(quote_ident(table_name))
from information_schema.tables
where table_schema = 'public'
order by 2

کوئری رو داخل دیتابیس وارد کردم و نتیجه زیر رو بهم نشون داد:

Disk Usage for each table
Disk Usage for each table

همونطور که میبینید جدول nodestore_node، حدودا 130 گیگ فضا اشغال کرده و یعنی تمامی اطلاعات داخل این جدول هست. وقتشه که یکم پاکسازیش کنیم.

اول باید بفهمیم این جدول چه columnهایی داره که براساس اون کوئری SELECT و سپس DELETE رو اجرا کنیم.

برای اینکار از دستور زیر استفاده میکنیم:

\d+ table_name
nodestore_node table columns
nodestore_node table columns

خب column کلیدی ما پیدا شد. timestamp! بر اساس این column میتونیم دیتای داخل جدول رو فیلتر کنیم و اطلاعات اضافی رو پاک کنیم. اول چندخط اول این column رو خروجی میگیریم که ببینیم دیتا رو از چه تاریخی داریم. با استفاده از دستور:

SELECT timestamp
        FROM nodestore_node
        ORDER BY timestamp limit 5;

که خروجی زیر رو بهمون میده:

این یعنی من اطلاعات 2 ماه رو داخل سرور دارم درحالی که اطلاعات 2 هفته رو بیشتر نمیخوام.

دست به کار میشیم برای حذف اطلاعات، من از دستور زیر برای پاک کردن 1 میلیون رکورد استفاده کردم:

DELETE
FROM nodestore_node
WHERE id = any(array(
        SELECT id
        FROM nodestore_node
        WHERE timestamp <= '2022-10-15 00:00:00.000000+00' ORDER BY timestamp Limit 1000000));

که داخل دستور بالا تاریخ داده شده، خواستم 1 میلیون تا از رکوردهارو پاک کنم و ببینم چقدر فضا خالی میشه.

راستشو بخواید من این دستور رو با سرچ کردن و یا تجربه قبلی ننوشتم. توی گشت گذارم داخل سورس sentry داخل گیت‌هاب، بخش cleanup رو یکم خوندم و دیدم که پایتون دستور بالا رو داخل پستگرس اجرا میکنه، لینکش رو هم میزارم اینجا:

https://github.com/getsentry/sentry/blob/f4ca58925908adfc20ee8371b5a883857dcee23c/src/sentry/db/deletion.py#L48:L62

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

df -h /

وضعیت دیسک رو گرفتم که ببرم به بچه ها نشون بدم ولی دیدم عه!!! هیچی خالی نشده...

دوباره مجدد کلی سرچ و تحقیقات کردم، نتیجه بر این شد که دیتابیس پستگرس، بعد از پاک کردن رکوردها اون هارو به صورت Dead همچنان نگه میداره و برای پاک کردن نهاییشون باید از دستور

vaccum full

استفاده کنم، این دستور رو اجرا کردم، بعد از چند دقیقه دیسک سرور 100 درصد پر میشد و خطای دیسک میخورد، و می‌گفت که فضا ندارم. یکم تحقیق کردم مجدد و فهمیدم موقعی که ما دستور وکیوم رو اجرا میکنیم. پستگرس یک کپی از رکوردهای Live ما درست میکنه و سپس هرچی از قبل بوده رو پاک می‌کنه، یعنی ما به اندازه فضای خالی فعلی دیسک فقط میتونیم دیتا ذخیره کنیم. پس بیخیال آزمون و خطا شدم و دستور پاک کردن رو بدون لیمیت وارد کردم و 26 میلیون از 27 میلیون رکورد دیتابیس پاک شد، سپس با دستور وکیوم رکوردهای مرده دیتابیس رو هم پاک کردم و فضا خالی شد.

الان فقط تست کردن سنتری مونده، یکم توی سنتری چرخیدم و همه چیز رو تست کردم، رکوردهای قبلی همچنان Titleشون داخل سنتری بود ولی دیتا پاک شده بود و اررور زیر رو میداد:

نتایج به نظر موفقیت‌آمیز میومدن، نتیجه رو با یکی از بچه‌های تیم به اشتراک گذاشتم و پس از اوکی گرفتن نهایی عملیات بالا رو روی سرور اصلی (نه clone) نهایی کردیم و این تسک رو به نتیجه رسوندیم.