This Might Be Useful

Распределение SQL-запросов между серверами в кластере

В web-проектах с большой посещаемостью рано или поздно возникает ситуация, когда мощности одного сервера недостаточно для обработки запросов. В этом случае создается кластер. И перед программистом встает вопрос: как корректно направлять разные запросы на разные серверы? На писать же везде условия. Да и передавать разные линки в mysql_query() не очень-то удобно. Именно поэтому я предлагаю простое решение этой проблемы.

В данном случае мы рассматриваем случай, когда кластер построен следующим образом: есть центральный master-сервер, на который идут запросы на запись, и есть slave-серверы, на которые происходит репликация с мастера и которые предназначены только для чтения.

PHP:
  1. define('db_host', 'master_host'); // скорее всего, это будет удаленная машина
  2. define('db_user', 'master_user');
  3. define('db_pass', 'master_pass');
  4. define('db_name', 'master_db');
  5.  
  6. define('db_host_slave', 'slave_host'); // скорее всего, это будет localhost
  7. define('db_user_slave', 'slave_user');
  8. define('db_pass_slave', 'slave_pass');
  9. define('db_name_slave', 'slave_db'); // с большой вероятностью совпадает со значением master_db
  10.  
  11. function smart_sql_query($sql) {
  12.   global $dbi, $dbi_slave, $sql_cnt;
  13.  
  14.   $sql = trim($sql);
  15.   $sql_cnt++;
  16.   if (preg_match("/^SELECT/si", $sql)) {
  17.     return mysql_query($sql, $dbi_slave);
  18.   } // запрос на чтение
  19.   else {
  20.     return mysql_query($sql, $dbi);
  21.   } // запрос на запись
  22. } // smart_sql_query
  23.  
  24. global $dbi, $dbi_slave, $sql_cnt;
  25. $sql_cnt = 0;
  26.  
  27. $dbi = mysql_connect(db_host, db_user, db_pass, true) or die('ERROR: Sorry, master database is down.');
  28. mysql_select_db(db_name, $dbi) or die('Sorry, master database structure is corrupted');
  29.  
  30. $dbi_slave = mysql_connect(db_host_slave, db_user_slave, db_pass_slave, true) or die('ERROR: Sorry, slave database is down.');
  31. mysql_select_db(db_name_slave, $dbi_slave) or die('Sorry, slave database structure is corrupted');

В коде же просто вызываем smart_sql_query(), который уже сам решит, куда слать запрос.

Понятное дело, что smart_sql_query() можно модифицировать таким образом, чтобы она разруливала запросы более сложным образом, показывала debug output и т.д.

Только хочу сразу предостеречь всех от наступания на те грабли, которые в свое время больно били меня. При такой схеме функцию mysql_insert_id() надо использовать крайне осторожно, так как если забыть передать ей линк, она вернет неверные данные.

· Добавление папок в контекстное меню Send To
· Отключение ненужных сервисов
· Отдаем pdf-файл браузеру. Да так, чтобы MSIE его тоже принимал.
· Отключение встроенного архиватора zip
· Основы масштабирования (web-проектов)

- Коментировать
- Trackback

18 Responses to “Распределение SQL-запросов между серверами в кластере”


  1. d1pr3d Says:

    ябы еще preg_match("/^SELECT/si", $sql) заменил на strposi($sql, 'SELECT')!==false :-)

  2. Filosoff Says:

    1) stripos ;)
    2) а ежели например в update-запросе будет фигурировать поле под названием select (или, например, selection)? это же не только ключевое слово...

  3. d1pr3d Says:

    1) ну естественно ;)
    2) но там всеравнов начале строки проверяется, такчто это относится только к указанному случаю ;-)

  4. d1pr3d Says:

    а если придерживаться написания ключевых слов в SQL запросах в верхнем регистре, то букву i от strpos можно убрать, но эт уже совсем рискованно ;-)

  5. Filosoff Says:

    d1pr3d @ 23.03.2007, 13:57 #

    но там всеравнов начале строки проверяется, такчто это относится только к указанному случаю ;-)

    в смысле? проверяется просто вхождение подстроки в строку. а в данном случае необходимо, чтобы это слово было именно в самом начале строки и никак иначе. тогда уж надо проверять stripos($sql, 'SELECT') === 0
    да, и еще. stripos - это только PHP5.

  6. d1pr3d Says:

    да, с нулём лоханулся, *раздолбай*, изначально написал правильно, вобщем обычно :))

    stripos это только PHP5, и в этом для меня нет ничего плохого, я не сторонник писать код с уклоном на старые версии, если только не предусматривается хостится на устаревших серверах. Лучше с админом договориться :) Хотя сам использовал бы именно strpos, i добавил только дабы больше соответствовать регулярному выражению в примере.

  7. dimzon541 Says:

    }}#
    define('db_host_slave', 'slave_host'); // скорее всего, это будет localhost

    Вот это как раз таки неправильно! Если не хватает производительности первым делом надо разносить сервер приложений и БД по разным машинам!
    А вообще самым первым делом внимательно изучить запросы, построить индексы, использовать для выполнения запросов prepared statement
    Откровенно говоря за весь свой стаж DB-кластера использовал только failover а вот сервера приложений через NLB гоняли...

  8. Filosoff Says:

    ну вот недавно делали большой проект, который давал серьезную нагрузку на mySQL. сейчас это все уже работает. стоит один master-сервер для DB и две ноды, на которых стоят slave-DB и web и между которыми балансируется нагрузка. при такой схеме при росте нагрузки легко и просто можно добавлять еще ноды, тем самым повышая производительность всего кластера.

  9. dimzon541 Says:

    А с самой БД "поиграть" не пробовали? В смысле оптимизации запросов и.т.п.

  10. Filosoff Says:

    dimzon541 @ 23.03.2007, 19:50 #

    А с самой БД "поиграть" не пробовали? В смысле оптимизации запросов и.т.п.

    пробовали. но планируется действительно большая нагрузка. серверы там тоже совсем не простые :)

  11. Cosair Says:

    Мммм... Я, наверное, не так понял...
    Если в одну базу идет запись/апдейт и пр., а из другой идет только чтение, то между этими базами должна быть какая-то синхронизация, так?
    Если так, то как такое сделать-то? Если нет, то, м... откуда возьмутся данные в базе, из которой идет чтение, если вся запись идет в другую базу? о.О
    В общем, как мне кажется, должна быть синхронизация, тогда, опять же, как такое сотворить? :-)

  12. Corsair Says:

    Мдя, пора подвязывать кодить сутками :/ Уже в нике ошибку делаю :/

  13. Filosoff Says:

    Cosair @ 24.05.2007, 18:01 #

    Если в одну базу идет запись/апдейт и пр., а из другой идет только чтение, то между этими базами должна быть какая-то синхронизация, так?
    ...
    В общем, как мне кажется, должна быть синхронизация, тогда, опять же, как такое сотворить? :-)

    Конечно должна быть синхронизация. На это это и кластер.
    В статье написано:

    Filosoff @ 25.05.2007, 06:45 #

    В данном случае мы рассматриваем случай, когда кластер построен следующим образом: есть центральный master-сервер, на который идут запросы на запись, и есть slave-серверы, на которые происходит репликация с мастера и которые предназначены только для чтения.

    Другими словами, синхронизация (точнее - репликация) делается средствами, например, mySQL.

  14. Corsair Says:

    2Filosoff, мм, то бишь просто какой-то отдельный скрипт, запущенный кроном, который копирует данные из одной базы в другую? ;-)

  15. Filosoff Says:

    Corsair @ 25.05.2007, 13:56 #

    2Filosoff, мм, то бишь просто какой-то отдельный скрипт, запущенный кроном, который копирует данные из одной базы в другую? ;-)

    нет, что ты. все real time. я же говорю, средствами mySQL :)

  16. Corsair Says:

    Filosoff @ 25.05.2007, 14:01 #

    нет, что ты. все real time. я же говорю, средствами mySQL :)

    Тогда я вообще ничерта не понимаю, наверное рановато мне еще :))

  17. dimzon541 Says:

    Corsair @ 25.05.2007, 17:21 #

    Тогда я вообще ничерта не понимаю, наверное рановато мне еще :))

    http://www.onlamp.com/pub/a/onlamp/2005/06/16/MySQLian.html

  18. Corsair Says:

    Спасибо! ;-)
    Давно сюда не заглядывал, но т.к. нужно готовиться к XSSу (еще нужно и почитать с чего его едят и все такое) вспомнил про эту статью, double thank you за последнюю ссылку)

Leave a Reply

code