The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"Раздел полезных советов: MySQL - квотирование баз  под FreeB..."
Вариант для распечатки  
Пред. тема | След. тема 
Форумы Разговоры, обсуждение новостей (Public)
Изначальное сообщение [ Отслеживать ]

"Раздел полезных советов: MySQL - квотирование баз  под FreeB..."  +/
Сообщение от auto_tips (ok) on 27-Окт-05, 22:55 
Хитрости квотирования MySQL.

<p>Каждую базу MySQL хранит в отдельном каталоге внутри datadir.
MySQL работает под своим пользователем и соответственно создает файлы баз под им же. Соответственно квотирование в данном случае не возможно. Необходимо  заставить его создавать файлы баз, влaдельцем которых будет конкретный квотируемый  пользователь. Сделать это можно выставив бит SUID (4000) на каталог базы.

<p>Для начала:
<pre>

     в ядре:
        options SUIDDIR

     в /etc/fstab:
        добавляем в список опций suiddir
</pre>

<p>В MySQL создаем базу.  Находим каталог базы в datadir. По умолчанию он будет mysql:mysql.

<pre>

   Меняем владельца:
     chown sql-user databasedir
     теперь наш каталог sql-user:mysql
  
   Меняем права:  
       chmod 4070 databasedir
</pre>

<p>Такая настройка заставит систему создавать файлы от имени владельца каталога (sql-user) причем сам пользователь не будет иметь к нему доступа. К нему будет  иметь полный доступ MySQL (от группы mysql).
  
<p>Теперь мы можем использовать квоты как для обычных файлов.
При превышении квот MySQL будет генерить ошибку full disk что является нормальным явлением и корректно отрабатывается MySQL, хотя сопровождается некоторыми проблемами: при запросе на добавление в базу, превысившую квоты, запрос повисает, повисают также последующие запросы, которые можно снять только их убийством или освобождением  дополнительного места на диске. При дефолтных настройках это сразу вызовет проблему,  так как такие запросы займут все сетевые соединения. Поэтому необходимо ОБЯЗАТЕЛЬНО
ограничить максимальное количество подключений одного пользователя MySQL. В /etc/my.cnf:
<pre>

   max_connections  = 500 (всего коннектов)
   max_user_connections = 30 (максимум для одного пользователя)
</pre>

<p>Также возможно следующие - MySQL может пометить как поврежденные при останове сервера или  когда временные файлы займут слишком много места на диске (второе судя по мануалам, не проверял). Лечится репаиром соотвествующих таблиц.

<p>Убить повисшие процессы может только root базы если они достигли max_user_connections.

<p>Не работает с таблицами innodb, так последние хранятся в одном месте независимо от базы.

<p>Коментируйте.

URL:
Обсуждается: https://www.opennet.ru/tips/info/909.shtml

Высказать мнение | Ответить | Правка | Cообщить модератору

 Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от const86 (ok) on 27-Окт-05, 22:55 
Возможен ли такой же фокус с postgres'ом? Видал там некие tablespace, но не углублялся в суть...
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

2. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от ртфлы on 28-Окт-05, 06:25 
В postgre будут нормальные user quota. Правда, только в 7.6
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

3. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от vvvua email on 28-Окт-05, 14:29 
А откуда такая инфа?
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

4. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от const86 (ok) on 28-Окт-05, 17:25 
Всё в постгресе хорошо, да только вот квот нет и с разными кодировками никак... "Радует" только, что в других БД не лучше.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

5. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Pahanivo email(??) on 02-Ноя-05, 13:40 
Ну какбы сдесь квотирование использует тот факт что мускул хранит базы в разных каталогах файлухи. Если постгрис это умеет и коректно отрабатывает ошибку типа "полный диск" то фокус пройдет так фактически к базе привязка весьма условная.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

6. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от stellar (??) on 25-Мрт-06, 11:52 
В который раз поражаюсь аффффтарам с Опеннета.

Это отвратительное решение. Потому что как только место для базы кончится, MySQL крякнет и с большой вероятностью запорет таблицу(ы) в базе.

Если Вам надо иметь проблемы с регулярным восстановлением базы у клиентов -- дерзайте.

Вдобавок оно не работает с InnoDB.

В результате Вы получите кривое решение, которое ничего, кроме головной боли не принесет.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

7. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Pahanivo email(??) on 06-Апр-06, 08:48 
Никто не сказал что решение идеальное ))
Просто как вариант.
У тебя есть другое решение? Поделись!
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

8. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Abigor email(??) on 02-Май-06, 08:27 
а у меня вот что говорит
# chown -vR management:mysql management/
chown: management: Invalid argument
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

9. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Pahanivo (??) on 02-Май-06, 10:48 
chown R management:mysql management
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

10. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Abigor email(??) on 02-Май-06, 11:22 
>chown R management:mysql management

chown R management:mysql management
chown: R: Invalid argument

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

11. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Pahanivo (??) on 02-Май-06, 12:17 
>>chown R management:mysql management
>
>chown R management:mysql management
>chown: R: Invalid argument


Sorry )) -R ))
> man chown )

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

12. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от voron email(??) on 08-Июл-06, 16:07 
http://projects.marsching.org/mysql_quota/
The MySQL Quota-Tool helps you to set a size limit on MySQL databases.

It works by checking the size of each database and revoking the INSERT- and CREATE-priveleges for the databases, which exceed the given size limit.
When the size of the database falls below the given limit, the INSERT- and CREATE-priveleges are granted again.

не мегакрасивое решение, но зато без фатальных последствий для пользователя, базы и тп.

хотя лучшим решением наверно будет комбинация 2-х решений, чтобы какой-нить запрос вроде load data( которым можно гигабайты заливать), не завалил диск

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

13. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Pahanivo email(??) on 25-Авг-06, 15:02 
>http://projects.marsching.org/mysql_quota/
>The MySQL Quota-Tool helps you to set a size limit on MySQL
>databases.
>
>It works by checking the size of each database and revoking the
>INSERT- and CREATE-priveleges for the databases, which exceed the given size
>limit.
>When the size of the database falls below the given limit, the
>INSERT- and CREATE-priveleges are granted again.
>
>не мегакрасивое решение, но зато без фатальных последствий для пользователя, базы и
>тп.
>
>хотя лучшим решением наверно будет комбинация 2-х решений, чтобы какой-нить запрос вроде
>load data( которым можно гигабайты заливать), не завалил диск

Возможно комбинация будет лучше, но прикинте скока гемора чтобы завети одну паршивую базу ))
Блин, столько лет существует мускул - почему не могут это сделать средствами сервака?

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

14. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Exe on 11-Ноя-06, 14:26 
кто вам сказал что innodb обязательно все базы в одном файле? учите маны, они рулез.
хинт: innodb_file_per_table
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

15. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Jack email(??) on 03-Мрт-07, 07:22 
А вот в 5.0.X поведение MySQL сервера не очень понятное. При правах на директорию БД 070, где 7 - права для группы в которую входит псевдопользователь от которого работает MySQL, сервер не видит эту БД. Т.е. 'show databases' - не находит базу. А вот запрос 'use my_db' - Успешен и уже внутири этой БД возможно осуществлять все операции с таблицами. Может кто знает с чем это связано, и как версию 5.0.Х приточить к использованию квотирования описанному в исходной статье.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

16. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от stellar (??) on 21-Мрт-07, 12:14 
Повторяю: Квотирование средствами файловой системы - отвратительное решение. Потому что как только место для базы кончится, MySQL с большой вероятностью запорет таблицу(ы) в базе.

Если Вам надо иметь проблемы с регулярным восстановлением базы у клиентов -- дерзайте.

Вдобавок оно не работает с InnoDB.

В результате Вы получите кривое решение, которое ничего, кроме головной боли не принесет.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

19. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от ol (??) on 26-Фев-08, 15:00 
>[оверквотинг удален]
>место для базы кончится, MySQL с большой вероятностью запорет таблицу(ы) в
>базе.
>
>Если Вам надо иметь проблемы с регулярным восстановлением базы у клиентов --
>дерзайте.
>
>Вдобавок оно не работает с InnoDB.
>
>В результате Вы получите кривое решение, которое ничего, кроме головной боли не
>принесет.

ну хоть 10 раз повтори
у тебя есть другое решение? вот и не умничай )))

лично я квоты поставил в два раза больше чтобы серв не свалился, а по крону проверяю размер базы и шлю на мыло пользователям сообщения, что это им боком может выйти, пусть пишут если база нужна больше или чистят..

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

20. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Pahanivo (??) on 22-Мрт-08, 19:41 
Тебя все прекрасно поняли дорогой. Но предположим вариант:
у тебя на серваке мало места свободного осталось и помимио мускула висит пара процессов общитывающих трафик, которые весьма критичны к свободному пространству. А юзер любит заливать в базу бааальшие порции инфы.
Вот теперь вопрос: что критичнее - база юзера, которую можно поднять из бекапа или неучтенный трафик и соотвесвенно проепаные деньги за которые тебя еще и вздрючат?
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

17. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от abrikos (??) on 05-Июн-07, 06:41 
а если написать скрипт проверяющий размер базы и при привышении отменять привилегии на insert ?
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

18. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от Pahanivo (??) on 13-Июн-07, 09:17 
>а если написать скрипт проверяющий размер базы и при привышении отменять привилегии
>на insert ?

тоже вариант

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

21. "MySQL - квотирование баз  под FreeBSD"  +/
Сообщение от chesnok (ok) on 02-Сен-09, 00:07 
на п0нTаL0o0n-хостинге у бородачей работает скрипт:

#!/usr/bin/perl
use lib qw(/site/perl/lib /site/perl/sys);
use strict; use AGAVA::Hosting::Config; use AGAVA::DBI; use AGAVA::Hosting::HostingData;
use Data::Dumper; use AGAVA::Hosting::Utils;

BEGIN {
     open(STDERR, ">>/home/r/register.h17.ru/log/disk_usage_mysql_quota.pl.log");
}

#exit 1;
#lock();
my $cfg = new AGAVA::Hosting::Config;
my $dbh = AGAVA::DBI->connect(AGAVA::Hosting::Config->new());
my $dbh1 = AGAVA::DBI->connect(AGAVA::Config->new($cfg, $cfg->get('MYSQL_DB_CONF'))) or return undef;
my $sth;
my $adomain = $cfg->get('DEFAULT_ADOMAIN');
my $adomain1 = $adomain;
$adomain =~ s/\./\\./;
my $hd = AGAVA::Hosting::HostingData->new();

my $take_update = 0;

trace("Start disk_usage_mysql_quota [ ***** ]");

my $count;
my $count1;
my $count2;
my $count0;
my $count3;
my %disc_quota = undef;
my %mega_hash_nah1 = undef;
open (FH, "< /etc/passwd") or die ("err1 !!!");
while (<FH>)
{
        if($_ =~ /^(.*):\*:(\d+):\d+:.*\.$adomain:\/home\/.{1}\/.*\.$adomain:.*$/)
        {
                $mega_hash_nah1{$2} = $1;
        }
}
close FH;

my $repquota_cmd = $cfg->get('REPQUOTA_CMD');
my $first_uid = $cfg->get('START_UID');
my $last_uid = $cfg->get('LAST_UID');

open(my $repquota_fh, "$repquota_cmd |");
while (my $line = <$repquota_fh>)
{
        my ($uid,undef,$sz,undef,$max_sz,undef,$nm,undef,$max_nm) = split(/\s+/,$line);
        if (($first_uid <= $uid) and ($last_uid >= $uid))
        {
                my $name;
                if ($name = $mega_hash_nah1{$uid})
                {
                        $disc_quota{$name} = {used => $sz, allow => $max_sz};
                }
        }
}
close $repquota_fh;
$sth = $dbh->prepare("select name,domain,db,inodes,du_limit from hpersons where status <> 'a'");
$sth->execute();

while (my $data = $sth->fetchrow_hashref)
{
        $count0++;
        if (defined($data->{name}) and defined($data->{domain}))
        {
                if ($data->{db})
                {
                        my $done_changes = 0;
                        my $quota = $disc_quota{$data->{name}};
                        my $used = 0;
                        my $quota_cmd = sprintf($cfg->get('DB_SIZE_CMD'),$data->{name});
                        open(my $rc_quota_cmd, "$quota_cmd |");
                        my $rc = <$rc_quota_cmd>;
                        close $rc_quota_cmd;
                        my ($used,@tmp) = split(/\s+/,$rc);
                        if ($used eq "NO_DB")
                        {
                                my $sth2 = $dbh->prepare('update hpersons set db = ? where name = ?');
                                $sth2->execute(0,$data->{name});
                                $count2++;
                        }
                        unless ($used =~ /\d+/) { $used = 0;}
                        $used = $used + $quota->{used};

                        #warn " -- $used -- \n";
                        my $sth2 = $dbh->prepare('update hpersons set quota = ? where name = ?');
                        $sth2->execute($used,$data->{name});
                        $count1++;

                        if($used <= $quota->{allow})
                        {
                                $done_changes = 1;

                                if($take_update)
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='Y', Create_priv='Y', Update_priv='Y' WHERE Db='$data->{name}'");
                                }
                                else
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='Y', Create_priv='Y' WHERE Db='$data->{name}'");
                                }

                                $hd->i_add_quota($data->{name},$data->{du_limit},$data->{inodes});
                        }
                        elsif($used >= $quota->{allow})
                        {
                                $done_changes = 1;

                                if($take_update)
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='N', Create_priv='N', Update_priv='N' WHERE Db='$data->{name}'");
                                }
                                else
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='N', Create_priv='N' WHERE Db='$data->{name}'");
                                }
                                #trace("block [ ".$data->{name}." ] : used [ $used ] : allow [".$quota->{allow}."]");
                                $hd->i_add_quota($data->{name},'1024',$data->{inodes});
                                $count3++;
                        }

                        if($done_changes)
                        {
                                $dbh1->do("FLUSH PRIVILEGES");
                        }
                }
                else
                {
                        my $tmp = $disc_quota{$data->{name}};
                        my $sth2 = $dbh->prepare('update hpersons set quota = ? where name = ?');
                        $sth2->execute($tmp->{used},$data->{name});
                        $count++;
                }
        }
}
trace("End disk_usage_mysql_quota [ ***** ]");

$dbh->disconnect;
$dbh1->disconnect;
#unlock();
sub trace
{
    my $msg = shift;
    warn "[ ".localtime()." ] $msg \n";
}


#print $count0."\n";
#print $count."\n";
#print $count1."\n";
#print $count2."\n";
#print $count3."\n";
[ithelp8@entropy17 ~]$
[ithelp8@entropy17 ~]$
[ithelp8@entropy17 ~]$
[ithelp8@entropy17 ~]$ clear
[ithelp8@entropy17 ~]$ cat /site/Hosting/scripts/disk_usage_mysql_quota.pl
[ithelp8@entropy17 ~]$ clear
[ithelp8@entropy17 ~]$ cat /site/Hosting/scripts/disk_usage_mysql_quota.pl
#!/usr/bin/perl
use lib qw(/site/perl/lib /site/perl/sys);
use strict; use AGAVA::Hosting::Config; use AGAVA::DBI; use AGAVA::Hosting::HostingData;
use Data::Dumper; use AGAVA::Hosting::Utils;

BEGIN {
     open(STDERR, ">>/home/r/register.h17.ru/log/disk_usage_mysql_quota.pl.log");
}

#exit 1;
#lock();
my $cfg = new AGAVA::Hosting::Config;
my $dbh = AGAVA::DBI->connect(AGAVA::Hosting::Config->new());
my $dbh1 = AGAVA::DBI->connect(AGAVA::Config->new($cfg, $cfg->get('MYSQL_DB_CONF'))) or return undef;
my $sth;
my $adomain = $cfg->get('DEFAULT_ADOMAIN');
my $adomain1 = $adomain;
$adomain =~ s/\./\\./;
my $hd = AGAVA::Hosting::HostingData->new();

my $take_update = 0;

trace("Start disk_usage_mysql_quota [ ***** ]");

my $count;
my $count1;
my $count2;
my $count0;
my $count3;
my %disc_quota = undef;
my %mega_hash_nah1 = undef;
open (FH, "< /etc/passwd") or die ("err1 !!!");
while (<FH>)
{
        if($_ =~ /^(.*):\*:(\d+):\d+:.*\.$adomain:\/home\/.{1}\/.*\.$adomain:.*$/)
        {
                $mega_hash_nah1{$2} = $1;
        }
}
close FH;

my $repquota_cmd = $cfg->get('REPQUOTA_CMD');
my $first_uid = $cfg->get('START_UID');
my $last_uid = $cfg->get('LAST_UID');

open(my $repquota_fh, "$repquota_cmd |");
while (my $line = <$repquota_fh>)
{
        my ($uid,undef,$sz,undef,$max_sz,undef,$nm,undef,$max_nm) = split(/\s+/,$line);
        if (($first_uid <= $uid) and ($last_uid >= $uid))
        {
                my $name;
                if ($name = $mega_hash_nah1{$uid})
                {
                        $disc_quota{$name} = {used => $sz, allow => $max_sz};
                }
        }
}
close $repquota_fh;
$sth = $dbh->prepare("select name,domain,db,inodes,du_limit from hpersons where status <> 'a'");
$sth->execute();

while (my $data = $sth->fetchrow_hashref)
{
        $count0++;
        if (defined($data->{name}) and defined($data->{domain}))
        {
                if ($data->{db})
                {
                        my $done_changes = 0;
                        my $quota = $disc_quota{$data->{name}};
                        my $used = 0;
                        my $quota_cmd = sprintf($cfg->get('DB_SIZE_CMD'),$data->{name});
                        open(my $rc_quota_cmd, "$quota_cmd |");
                        my $rc = <$rc_quota_cmd>;
                        close $rc_quota_cmd;
                        my ($used,@tmp) = split(/\s+/,$rc);
                        if ($used eq "NO_DB")
                        {
                                my $sth2 = $dbh->prepare('update hpersons set db = ? where name = ?');
                                $sth2->execute(0,$data->{name});
                                $count2++;
                        }
                        unless ($used =~ /\d+/) { $used = 0;}
                        $used = $used + $quota->{used};

                        #warn " -- $used -- \n";
                        my $sth2 = $dbh->prepare('update hpersons set quota = ? where name = ?');
                        $sth2->execute($used,$data->{name});
                        $count1++;

                        if($used <= $quota->{allow})
                        {
                                $done_changes = 1;

                                if($take_update)
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='Y', Create_priv='Y', Update_priv='Y' WHERE Db='$data->{name}'");
                                }
                                else
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='Y', Create_priv='Y' WHERE Db='$data->{name}'");
                                }

                                $hd->i_add_quota($data->{name},$data->{du_limit},$data->{inodes});
                        }
                        elsif($used >= $quota->{allow})
                        {
                                $done_changes = 1;

                                if($take_update)
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='N', Create_priv='N', Update_priv='N' WHERE Db='$data->{name}'");
                                }
                                else
                                {
                                        $dbh1->do("UPDATE db SET Insert_priv='N', Create_priv='N' WHERE Db='$data->{name}'");
                                }
                                #trace("block [ ".$data->{name}." ] : used [ $used ] : allow [".$quota->{allow}."]");
                                $hd->i_add_quota($data->{name},'1024',$data->{inodes});
                                $count3++;
                        }

                        if($done_changes)
                        {
                                $dbh1->do("FLUSH PRIVILEGES");
                        }
                }
                else
                {
                        my $tmp = $disc_quota{$data->{name}};
                        my $sth2 = $dbh->prepare('update hpersons set quota = ? where name = ?');
                        $sth2->execute($tmp->{used},$data->{name});
                        $count++;
                }
        }
}
trace("End disk_usage_mysql_quota [ ***** ]");

$dbh->disconnect;
$dbh1->disconnect;
#unlock();
sub trace
{
    my $msg = shift;
    warn "[ ".localtime()." ] $msg \n";
}


#print $count0."\n";
#print $count."\n";
#print $count1."\n";
#print $count2."\n";
#print $count3."\n"

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Индекс форумов | Темы | Пред. тема | След. тема




Спонсоры:
Слёрм
Inferno Solutions
Hosting by Ihor
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2019 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру