مشاوره و پشتیبانی #پایگاه داده #هوش تجاری

۱۳ مطلب با موضوع «پایگاه‌داده :: Oracle Data Guard» ثبت شده است

تعویض پسورد SYS در محیط DataGuard

خب اگه شما پسورد کاربر SYS رو با دستور ALTER USER SYS IDENTIFIED BY NEWPASSWORD در دیتابیسprimary عوض کنید SYNC از طرف سرور Primary متوقف می‌شود و آرشیولاگهای جدید به سمت دیتابیس Standby فرستاده نمی‌شودند. در این حالت شما خطای زیر رو در فایل alertlog می‌بینید:

------------------------------------------------------------------
Check that the primary and standby are using a password file
and remote_login_passwordfile is set to SHARED or EXCLUSIVE,
and that the SYS password is same in the password files.
returning error ORA-16191
------------------------------------------------------------------

این به این دلیله که شما از دستور ALTER USER برای تعویض پسورد کاربر SYS استفاده کرده‌اید و پسورد شما هم در فایل پسورد و هم در دیتادیکشنری به درستی در سرور Primary آپدیت شده ولی در سرور Standby تغییرات اعمال نشده‌اند.

شما با دستور زیر می‌تونید پسورد SYS رو در سرور Standby آپدیت کنید:

orapwd file=$ORACLE_HOME/dbs/orapwSID password=newpassword;

فراموش نکنید که فایل قبلی رو حذف کنید (توصیه میشه فقط اسم فایل رو عوض کنید تا اگه به مشکلی خوردید بتونید از فایل قبلی استفاده کنید، من خودم آخر فایلها یه پسوند old اضافه میکنم.)

نکته: حواستون باشه اصلاً مهم نیست پسورد SYS سمت Primary رو عوض کردید یا Standby در آخر باید این پسوردها یکی باشن

۰۵ بهمن ۹۵ ، ۱۱:۰۷ ۱ نظر
مهدی غفاری

ORA-03113: end-of-file on communication channel

بعد از تغییراتی روی زیرساخت ماشین‌های کلاستر rac با ۲ نود (دیتابیس 11.2.0.4.0) به مشکلی برخوردم که در نوع خودش برام جالب بود در حقیقت یکی از instanceهای کلاستر بدون مشکل startup می‌شد ولی instance دوم به هیچ عنوان open نمی‌شد و خطای زیر رو نشون میداد:

ORA-03113: end-of-file on communication channel
Process ID: 20194
Session ID: 1655 Serial number: 5

بعد از چک کردن فایل log دیتابیس مربوط

WARNING: The 'LOG_ARCHIVE_CONFIG' init.ora parameter settings
are inconsistent with another started instance. This may be
caused by the 'DB_UNIQUE_NAME' init.ora parameter being specified
differently on one or more of the other RAC instances; the
DB_UNIQUE_NAME parameter value MUST be identical for all
instances of the database.

خب اینجا بود که فهمیدم باید یه سری به پارامتر log_archive_config بزنم بعد از بررسی این پارامتر فهمیدم که مقدار null برای اون set شده و همچنین db_unique_name یکسان داریم که از این بابت مشکلی نیست.

برای ریست کردن این پارامت از دستور زیر در وضعیت mount استفاده کنید

alter system set log_archive_config='dg_config=(nodg_config)' scope=both sid='*';

با دستور زیر می‌تونید پیکربندی دیتاگاردتون رو چک کنید:

SQL> Select * from v$dataguard_config;

DB_UNIQUE_NAME

------------------------------
dwh
dwh_stby
و اگه کانفیگ دیتاگاردتون هنوز موردنیازه دستور رو طبق نیاز خود سفارشی کنید:
alter system set log_archive_config='dg_config=(dwh,dwh_stby)' scope=both sid='*';
۱۹ آبان ۹۵ ، ۰۰:۲۵ ۱ نظر
مهدی غفاری

رفع مشکل Warning: ORA-16826: apply service state is inconsistent with the DelayMins property

امروز تو یکی از سایتهام به مشکل زیر در DGMGRL خوردم

DGMGRL for Linux: Version 11.2.0.4.0 - 64bit Production
Copyright (c) 2000, 2009, Oracle. All rights reserved.

Welcome to DGMGRL, type "help" for information.
Connected.
DGMGRL> show configuration;
Configuration - primary
Protection Mode: MaxAvailability
Databases:
orcl - Primary database
orcldg - Physical standby database
Warning: ORA-16826: apply service state is inconsistent with the DelayMins property

Fast-Start Failover: DISABLED
Configuration Status:

WARNING

ادامه مطلب...
۰۷ مهر ۹۵ ، ۱۱:۵۸ ۰ نظر
مهدی غفاری

نگاهی بر معماری Oracle Data Guard - قسمت اول

تو این مجموعه پست‌ها میخوایم نگاهی مقدماتی بر اوراکل دیتاگارد از روی اسلایدهای اوراکل داشته باشم:

 

بعد از کامل کردن این سری از اسلایدها شما قراره:

  • کامپوننت‌ها و اجزای دیتاگارد رو بشناسید
  • اختلاف بین physical standby و logical standby رو بدونید
  • فواید پیاده‌سازی دیتاگارد رو بشناسید

نکته: کلاً وقتی دیتاگارد راه میندازیم یعنی ۲ تا سرور داریم یکی سرور اصلی primary و یکی سرور دیتاگارد که بهش standby می‌گیم (چون همیشه آماده به خدمته)

ادامه مطلب...
۲۳ مرداد ۹۵ ، ۱۷:۱۸ ۱ نظر
مهدی غفاری

Fast-Start Failover و Observer

در این مطلب می‌خواهیم اندک توضیح بیشتری راجع به Failover ارائه بدیم، همچنین می‌خواهیم راجع به امکان جدید Observer صحبت کنیم:

در مطلب قبل گفتیم که در زمانی که سرور primary شما به مشکل بخوره (چند تا از مشکلاتی که معمولاً پیش میاد: سرور primary شما shutdown abort شده یا یکی از دیسک‌های سرور به مشکل خورده باشه، یا یکی از datafileهای شما offline شده باشه، یا اینکه log writer نتونه روی redoها تغییرات رو بنویسه و هر مشکلی که به هر دلیلی کاربران نتونن با دیتابیس اصلی کار کنن) تو این حالت‌ها ما نیاز به Failover داریم.

حالا یه ابزاری داریم که می‌تونه خارج از ساختار primary و standby قرار بگیره این ابزار Observer نام داره.

Observer می‌تونه وضعیت‌های مشکل در سرور primary (مثل چند وضعیت اختلالی که در بالاتر توضیح دادیم) رو کنترل کنه

Observer می‌تونه خارج از سایت‌ standby و primary باشه یا اینکه فقط در primary یا standby یا به صورت یک سرور جدا باشه باشه (محل قرارگیری Observer بستگی به طراحی سایت شما یا disaster site شما و بیزینسی که داره از اپلیکیشن متصل به دیتابیس استفاده میکنه داره)

همونطور که گفتیم این ابزار وضعیت‌های اختلال سرور اصلی رو کنترل میکنه و در صورت به وقوع پیوستن اختلال دستور Failover رو صادر میکنه و به این ترتیب سرور standby بلافاصله توی مدار قرار میگیره و شروع به سروریس‌دهی به کاربران میکنه (اتوماتیک استارت Failover توسط Observer)

۲۰ خرداد ۹۴ ، ۱۹:۴۷ ۱ نظر
مهدی غفاری

Data Guard Broker

خب تو توضیحاتی که توی مطالب قبلی داشتیم گفتیم که Data Guard Broker "یک چارچوب مدیریتی توزیع شده است که ایجاد، نگهداری و نظارت بر تنظیمات Data Guard را متمرکز کرده و برعهده دارد."

مثلاً وقتی شما می‌خواید یک سرور standby‌ اضافه کنید یا اینکه می‌خواهید یکسری از پارامترها را تغییر دهید یا اینکه می‌خواهید کانفیگ‌های حال حاضر وضعیت Data Guard تون رو بررسی کنید خب Data Guard Broker این نقش رو به عهده داره همچنین Data Guard Brokerفایلهای خودش رو هم روی دیتابیس و هم روی سیستم‌عامل داره.

وظابف Data Guard Broker:

  • اضافه کردن Standby Database به پیکربندی Data Guard موجود: شما می‌توانید تا ۹ تا سرور standby تو محل‌های مختلف داشته باشید.
  • مدیریت پیکربندی Data Guard در هر کدام از دیتابیس‌های (primary, standby) موجود: شما با استفاده از کانفیگ‌های موجود می‌تونید این پیکربندی رو مدیریت کنید.
  • انجام switch over و fail over با استفاده از یک دستور: در حقیقت یکی از مهمترین و پرکاربردترین وظایف Data Guard Broker است. شما با استفاده از switch over می‌توانید رول‌های (primary, standby) را باهم عوض کنید. switch over میتونه برای ارتقای سخت‌افزاری باشه یا برای هر دلیل دیگه‌ای استفاده بشه. با استفاده از fail over هم می‌توانید اگر سرور primaryتون به مشکل خورد با دستور fail over به راحتی می‌تونید سرور standby رو توی مدار قرار بدید.
۲۰ خرداد ۹۴ ، ۱۶:۰۳ ۰ نظر
مهدی غفاری

حالت‌های پیکربندی Protection Modes

در مطالب پیش گفتیم که در بحث Active Data Guard ما ۲ حالت Sync و Async برای سرویس Apply داریم.

حالا می‌خوایم ببینیم که ما Protection Mode مون رو یا حالت محافظت از دیتامون رو تو چند حالت می‌تونیم قرار بدیم؟

  • Maximum Performance

در این حالت شما براتون کارایی و Performance بیشتر براتون اهمیت داره حالا ممکنه براتون سوال پیش بیاد که Performance دقیقاً چه ارتباطی با Active Data Guard داره؟

در حقیقت ارتباطش تو قسمتی معنی پیدا میکنه که شما منتظر apply بودید یعنی تا زمانی که اطلاعات روی سرور standby به صورت apply شده نبود این تغییرات بر روی سرور اصلی commit نمی‌شد.

نکته: همین حالت ممکنه تو حجم Transaction های بالا باعث کندی بشه

خب اگه ما بخوایم این موضوع در نظر بگیریم که نخوایم سرور primaryمون بدون commit‌ باشه تو این حالت apply service امون رو Async در نظر می‌گیریم  و تو Maximum Performance می‌گیم که دیگه لازم نیست منتظر apply بمونی شما دیتا رو commit کنن و هر زمانی که RFS تغییرات رو دریافت کرد و روی standby log file ها نوشت بعد دیتا رو sync کن

پس تو این وضعیت برای ما فقط Performance اهمیت داره

  • Maximum Protection

این موضوع برعکس موضوع Maximum Performance هستش در این حالت برای ما دیتا اهمیت داره یعنی ما نمی‌خوایم هیچ دیتایی از دست بره خب تو مطالب قبل راجع به sync و async به اندازه کافی گفتیم. در حقیقت تو قسمتی که sync بود گفتیم که تا زمانی که apply service روی سرور standby تغییرات رو apply نکرده تغییرات در سرور اصلی commit نمی‌شود یعنی acknowledge که برای commit میره اونور منتظر apply می‌مونه.

خب ما توی پیکربندی protection mode یه حالتی هستش که وضعیت protectionمون یا از دست ندادن دیتامون برامون اهمیت داره که تو این حالت حتماً باید apply serviceمون تو وضعیت sync باشه

خب توی این حالت یه پارامتری داریم به اسم Timeout که اینو در نظر می‌گیره که شما یک مقدار زمانی رو صبر کن اگر دیدید سرور standbyتون نتونسته apply کنه سرور primary رو بیا shutdown کن

پس به علت اینکه ممکنه تغییرات روی سرور standby‌ انجام نشه و شما دیتا رو از دست بدید به همین دلیله که یک مدت کوتاهی رو صبر میکنه اگه ببینه رو سرور standby شما apply انجام نمیشه میاد دیتابیس اصلی شما رو shutdown میکنه

  • Maximum Availability

خب در برخی مواقع در حالت قبلی ما نمی‌خوایم سرورمون shutdown بشه یعنی اینکه ممکنه سرور اصلی ما دیسک‌های خودشو داشته باشه همچنین سوای اینکه کاربرها دارن کار می‌کنن و حالا ممکنه طول بکشه تا دیتاها روی standby اعمال بشه می‌گیم که این قضیه که سرور اصلی‌مون shutdown نشه برامون خیلی اهمیت داره 

در حقیقت solution اوراکل برای این قضیه Maximum Availability است.

Maximum Availability میاد میگه که من Maximum Protectio رو به طور کامل تو حالت عادی دارم یعنی Sync رو تو حالت عادی انجام میدم و دیتا رو تا زمانی که توی سرور standby من apply نکردم تغییرات رو commit رو روی سرور اصلی انجام نمیدم.

اما همچنین اگه اختلالی بین ارتباط primary و standby به وجود اومد دیگه منتظر apply نمی‌مونم دیتا رو commit میکنم و زمانی که این ۲ تا ارتباطشون باهم برقرار شد از طریق apply log که در مرحله قبل توضیح دادم دیتا رو میاد روی سرور standby با استفاده از Archive Redo Log فایل apply میکنه

۲۰ خرداد ۹۴ ، ۱۳:۳۹ ۰ نظر
مهدی غفاری

عملکرد Data Guard در صورت Gap

خب ممکنه برای شما این سوال پیش بیاد که اگه Data Guard شما روش gap بیوفته یا اینکه سرور primary شما با سرور standby شما ارتباطش دچار اختلال بشه و نتونن همدیگه رو ping کنن در این حالت چه اتفاقی برای دیتاهای شما رخ میده؟

در اصل می‌خوایم ببینیم که سناریوی Data Guard و Active Data Guard برای این حالت چه راه‌حلی ارائه میده؟

خب مفاهیم LNS و RFS رو در پست‌های قبل توضیح دادیم.

به تصویر بالا اگر دقت کنید در حقیقت یک حالت عادی رو در آن مشاهده می‌کنید که LNS‌ میاد و از Redo Buffer روی RFS می‌نویسه و اونم روی Standby Redo Logها می‌نویسه منتها اگر gap به وجود بیاد شما باید به حالت زیر دقت کنید:

در این حالت تا زمانی که sync در حالت عادی اتفاق نیافتاده است یعین LNS نتونه از روی Redo Buffer بخونه Active Data Guard در حقیقت میاد کنترل میکنه از روی کنترل فایلهای سرور standby میاد میبینه که در حقیقت ما چقدر لگ داریم اگر لگ ما به اندازه‌ای بود که اطلاعات روی redo ها یا روی redo buffer ها وجود نداشته باشه میاد سراغ Archive Redo Log فایلهای سرور اصلی و از روی این آرشیوها پروسس RFS میاد روی Archive Redo Logهای سرور standby شما اون دیتا رو می‌نویسه (به شکل بالا دقت کنید)

و به این ترتیب دیتاها apply میشه روی خود سرور standby

نکته: این اتفاق تا زمانی که اطلاعات شما دیگه توی Archiveهای سرور اصلی نباشه و روی redo buffer یا همون online redo Logها باشه و این دقیقاً بستگی داره به وضعیت Sync یا Async شما

اگر دقت کرده باشید زمانی که وضعیت standby را sync‌کنید یک tranport lag داریم و یک apply lag که Transport Lag مربوط به انتقال لاگ فایل هست و Apply Lag مربوط به apply شدن تغییرات روی سرور standby برای مفهومی بهتر در شکل زیر این ۲ مفهوم را در این سناریو مشخص کرده‌ام:

۱۷ خرداد ۹۴ ، ۱۸:۲۸
مهدی غفاری

سرویس‌های DataGuard

خب همانطور که در مطالب قیل گفتیم DataGuard مدیریت سرورهای Primary و Standby و روابط بین این ۲ رو داره و خب می‌تونه دارای چند سرویس باشه:

  • LogTransportServices = این سرویس وظیفه انتقال تغییرات از سرور primary به سرورهای Standby رو داره
  • ApplyServices = این سرویس وظیفه apply کردن تغییرات رو با استفاده از پروسسی به نام RFS بر روی StandbyLogFile ها داره
  • RoleManagementServices = این سرویس نقش سرویس‌ها رو مشخص می‌کنه در حالت عادی شما یک سرور primary دارید و یک سرور standby ولی زمانی که switchover اتفاق می‌افته نقش این ۲ سرور باهم عوض میشه یعنی سرور primary میشه سرور standby و سرور stanby میشه primary

نکته: اگر سروها failure باشند سرور primary دیگه وجود نداره و سرور standby نقش سرور اصلی رو بازی میکنه.

LogTranport به روش Sync

خب همانطور که گفتیم اولین سرویس ما Log TransportServices هست. LogTransportServices میتونه به ۲ روش دیتا رو منتقل کنه به سرور standby (بستگی به سناریو شما برای active dataguard)

  • روش Sync = یعنی سرور standby شما هیچ تفاوتی با سرور اصلیتون نداره

مثال: کاربرهای شما وقتی تغییراتی روی tableهای دیتابیستون میدن تا زمانی که اطلاعات commit نشه توسط باقی کاربران این تغییرات قابل مشاهده نیست پس هر تغییری نیازمند commit است. این قضیه رو بذارید کنار مفهوم redo log buffer یعنی نغییراتی که توی دیتا به وجود اومده و هنوز روی دیسک نوشته نشده و اطلاعات هنوز داخل بافر SGA است.

خب این تغییرات باید به سرور standby‌ منقل بشه پس یه پروسسی به اسم LNS (Log Network Services میاد و تغییرات رو به سمت سرور standby منتقل می‌کنه. یه پروسس دیگه به اسم RFS (Remote File Server میاد این تغییرات رو از LNS دریافت می‌کنه و روی standby redo log file ها تغییرات رو می‌نویسه و همزان بعد این موضوع این تغییرات بر روی سرور standby میاد و apply میشه.

خب زمانی که apply شد RFS به LNS میگه من تغییرات رو apply‌ کردم و میره سراغ log writer روی سرور اصلی

log writer میاد و یه ack به سمت primary میفرسته و میگه من تغییرات رو روی سرور standby به صورت apply درآوردم شما می‌تونید commit جدید کنید پس هزمان با commit‌تغییرات روی online redo log فیالهای سرور اصلی نوشته میشه. پس نتیجه می‌گیریم که تا زمانی که سرور primary اطمینان از apply شدن تغییرات روی سرور standby یا حداقل نوشته شدن روی یکی از standby log file ها دستورات جدید کاربران commit نمی‌شوند.

به همین علته که سرور standbyاتون هیچ تغییری با سرور primaryاتون نداره یعنی در اصطلاح apply back شما 0 ثانیه است. به همین دلیل شما تو سناریوی sync شما هیچ دیتایی رو از دست نمی‌دید. 

  • روش Async = توضیحات این روش همانند روش sync است فقط تفاوتش در اینه که Redo Buffer شما اول سراغ Log Writer می‌رود Log Writer اطلاعات را روی Online Redo Log File ها می‌نویسه و از روی اون LNS دیتا رو میخونه

در حقیقت تفاوت روش Async با sync در این است که در این روش Commit Act Knowledge منتظر Apply شدن روی سرور Standby نمی‌مونه و دستورات (در حقیقت همون تغییرات) هر چه که هست commit میشه و همزمان هم LNS اطلاعات رو از Online Log File ها میخونه و روی (RFS (remote file server می‌نویسه و RFS هم منتقل می‌کنه به یکی از Standby Log Fileها

اگر بخواهیم به زبانی ساده‌تر این قضیه را روش کنیم به این صورت است که شما در sync اطلاعات رو از روی buffer می‌خونید و توی Async شما اطلاعات رو از online redo log file ها می‌خونید.

به شکل زیر دقت کنید:

۰۳ خرداد ۹۴ ، ۱۷:۳۵ ۰ نظر
مهدی غفاری

معماری Oracle Active DataGuard

در مطالب قیل توضیح دادیم که تکنولوژی Oracle Active Data Guard یکی از روش‌هایی که ما می‌تونیم با استفاده ازش سریعاً از قطعی جلوگیری کنیم. خب قبل از اینکه معماری Active Data Guard رو توضیح بدیم باید یکسری تعاریف رو باهم مرور کنیم:

  • RMAN = یکی از راه‌های بازیابی‌اطلاعات در بحث high availability استفاده از RMAN است. RMAN ابزار Recovery Manager اوراکل است که استفاده‌های بسیاری دارد. با استفاده از این ابزار شما می‌توانید اطلاعات را بک‌آپ‌گیری و بازیابی کنید، حتی می‌تونید یک TableSpace خاص رو یا یک DataFile خاص رو ازش بک‌آپ بگیرید. اگر خرابی در دیتا به وجود اومده باشه شما با این ابزار می‌تونید خرابی دیتا رو بازیابی کنید.
    RMAN از بک‌آپ دیسک‌ها و Archive Logها برای ریستور و ریکاوری استفاده می‌کنه. همچنین شما با استفاده از ابزار RMAN می‌تونید سرور standby بسازید که بحث اصلی ما در Active Data Guard همین standby است.
  • سرور Standby = سروری که در زمانهایی که سرور اصلی (primary) شما به مشکل می‌خوره و قطع میشه(مثل خرابی فایلهای اصلی دیتابیس، نفض فنی، به مشکل خوردن ارتباط کاربران با سرور اصلی به هر دلیل و یا یک قطعی برنامه‌ریزی شده) پس این سرور میتونه جایگزین سرور اصلی بشه
  • DataGuard = به مجموعه سرور primary و standby و ارتباط بین این ۲ تکنولوژی Data Guard می‌گویند. که یک دیتابیس اصلی داره که تراکنش‌های کاربران مثل خواندن و نوشتن و ... در آن انجام میشه و یک یا چند دیتابیس standby که اطلاعات از سرور اصلی باهاشون sync میشه (البته sync هم انواع مختلفی داره که به موقع به هر کدوم می‌پردازیم)
  • Active DataGuard = از نسخه ۱۱ به بعد این تکنولوژی معرفی شد. تفاوت Active DataGuard با DataGuard اینه که شما در تکنولوژی DataGuard اوراکل سرور standby تا زمانی که سرور primary در مدار باشه عملاً استفاده‌ای نداشت و فقط دیتا باهاش sync میشد و سرور standby در وضعیت mount به سر می‌برد. منتها در نسخه ۱۱ با ارائه Real Time Apply شما می‌تونید وضعیت دیتابیستون رو در حالت open قرار بدید و از سرور stanby استفاده کنید (گزارش بگیرید یا حتی با استفاده از RMAN بک‌آپ‌هاتون رو از این سرور بگیرید و یا این سرور standby اگه در وضعیت logical می‌تونید حتی روش Index تعریف کنید و ساختار فیزیکی متفاوتی از سرور اصلی در آن داشته باشید.
  • DataGuard Broker = یک چارچوب مدیریتی توزیع شده است که ایجاد، نگهداری و نظارت بر تنظیمات DataGuard رو به عهده داره

مزیت سرور Standby یا RMAN

سرور standby در کمترین زمان ممکن می‌تونه جایگزین سرور اصلی بشه و به دلیل اینکه اطلاعات در عصر حاظر برای سازمانها بسیار مهم است و همچنین دسترسی سریع کاربران به اطلاعات بسیار حائز اهمیت است راهکار Oracle Active DataGuard برای سازمانها پیاده‌سازی میشه

انواع سرور Standby

همانطور که قبلاً گفتیم سرور Standby می‌تونه چند نوع باشه:

  1. Physical
  2. Logical

اگه از 11g به بعد بخوایم در نظر بگیریم سرور physical سروری است که ساختار فیزیکی آن کاملاً مشابه سرور اصلی است. منتها در حالت readonly است و شما فقط می‌تونید ازش select بگیرید و دیگه insert و یا تغییرات ساختاری در دیتابیس وجود نداره

اما سرور Logical سروری است که در وضعیت r/w قرار داره و حتی میتونه ساختار فیزیکی‌اش با سرور اصلی متفاوت باشه. یعنی می‌تونید روش index بسازید یا حتی جدول جدید بسازید و یا حتی schema های جدید بر روی آن بسازید و دیتا روش insert کنید منتها sync آن با سرور اصلی یکطرفه است یعنی تغییراتی که شما روی سرور Logical می‌دید روی سرور Primary اعمال نمی‌شود.

در شکل زیر یک سررو primary‌ داریم که با استفاده از Async یا Sync میاد Redo ها رو روی سرور Physical Standby می‌نویسه

و با استفاده از SQL میاد کپی داده‌ها را در Logical Standby می‌نویسه در حقیقت به همین خاطره که بهش می‌گن Logical Standby

نکته: کپی داده با استفاده از Redo یک مفهوم فیزیکی است و کپی با SQL یک مفهوم منطقی است. به همین خاطر بهش Logical Standby گفته می‌شود.

۰۲ خرداد ۹۴ ، ۱۳:۲۳ ۲ نظر
مهدی غفاری