Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 2264 сообщений
Cообщения с меткой

mysql - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

ProxySQL — еще один mysql-proxy

Воскресенье, 19 Июня 2016 г. 16:20 (ссылка)

На хабре не раз упоминался данный инструмент для проксирования SQL-запросов, но, к сожалению, я не нашел ни одной статьи описывающей его работы, кроме того документации на русском языке тоже не было найдено. Ну что попробуем заполнить этот пробел. В статье мы рассмотрим структуру ProxySQl, конфигурирование и пример использования.





Что же такое ProxySQL?

Это приложение для проксирования SQL-запросов к базам данных для форков MySQL икаю как MariaDB и Percona(в будущем разработчики обещают добавить поддержку других различных БД). Работает как отдельный демон, все SQL-запросы, которые необходимо спроксировать, обрабатываются, затем по заранее составленным правилам демон подключается к необходимому MySQL-серверу и выполняет его, и уже после этого отдает результат приложению. ProxySQL может так же модифицировать поступающие запросы согласно шаблонам.



Архитектура ProxySQL.

ProxySQL имеет достаточно сложную, но простую для конфигурирования систему, благодаря ней возможно:


  • Осуществлять автоматические изменения в конфигурации, что важно для больших систем. Осуществляется это MySQL-подобный административный интерфейс.

  • Большинство изменений можно вносить в runtime-режиме без перезапуска демона ProxySQL

  • Легко выполнять откаты изменений, если вдруг что-то было сконфигурировано неправильно.





Это достигается путем использования многослойной системы конфигурации, которая делится на 3 слоя:



image



Слой Runtime — Этот слой конфигурации непосредственно используется демоном ProxySQL и содержит всю конфигурационную информацию для проексирования запросов.



Слой Memory — Или слой main представляет собой SQLite3 базу данных, которая находится в памяти, используется для предоставления информации о конфигурации и самого конфигурирования. Конфигурирование осуществляется через стандартный MySQL-клиент SQL-командами.



Слой Диск — Представляет собой обычный SQLite3 файл, в который сохраняются(пользователем) данные внесенные через слой Memory



Конф. файл — файл конфигурации ProxySQL(proxysql.cnf) используется в момент инициализации, содержит информацию о нахождении SQLite3 базы данных, информацию об административном интерфейсе, а так же начальную конфигурацию демона.



Для перемещения конфигураций между слоями существуют несколько административных команд:



Для перемещения конфигураций пользователей(USERS) между Memory(слой 2) и Runtime:

MySQL [(none)]> LOAD MYSQL USERS FROM MEMORY
MySQL [(none)]> LOAD MYSQL USERS TO RUNTIME




Из Runtime в Memory:

MySQL [(none)]> SAVE MYSQL USERS TO MEMORY
MySQL [(none)]> SAVE MYSQL USERS FROM RUNTIME




С диска(слой 3) в память

MySQL [(none)]> LOAD MYSQL USERS TO MEMORY
MySQL [(none)]> LOAD MYSQL USERS FROM DISK




Из памяти(слой 2) на диск(слой3)

MySQL [(none)]> SAVE MYSQL USERS FROM MEMORY
MySQL [(none)]> SAVE MYSQL USERS TO DISK




Из диска(слой 3) в память(слой 2)

LOAD MYSQL USERS FROM CONFIG 




Таким же образом перемещение можно осуществлять и других переменных, список доступных:

QUERY RULES- Запросы для проксирования.

VARIABLES — переменные MySQL-сервера и административных настроек.



Установка

Так как данное приложение достаточно новое и находится на стадии разработки, наилучшим вариантом будет собрать его из исходных текстов, которые можно получить на github: github.com/sysown/proxysql

Для ОС RedHat(CentOS) и Debian(Ubuntu) собраны бинарные пакеты: github.com/sysown/proxysql/releases



Установим пакет для CentOS 7:

rpm -ihv https://github.com/sysown/proxysql/releases/download/v1.2.0i/proxysql-1.2.0-1-centos7.x86_64.rpm




После установки, конф. файл будет располагаться по адресу: /etc/proxysql.cnf

Откроем его в любимом редакторе:



datadir="/var/lib/proxysql"

admin_variables=
{
admin_credentials="admin:admin" # логин и пароль администратора
mysql_ifaces="127.0.0.1:6032;/tmp/proxysql_admin.sock" #хост и порт для административного интерфейса

refresh_interval=2000 #Интервал обновления счетчиков статистики в микросекундах
debug=true
admin-stats_credentials=stats:stats #логин и пароль к админ.интерфейсу для сбора статистики(только чтение)

}
mysql_variables=
{
threads=4 #количество потоков для обработки входящих запросов
max_connections=2048 #максимальное количество соединений, которое прокси может обрабатывать одновременно.
default_query_delay=0
default_query_timeout=36000000
have_compress=true #на данный момент не используется
poll_timeout=2000
interfaces="127.0.0.1:3306;/tmp/proxysql.sock"
default_schema="information_schema"
stacksize=1048576 # размер стека для потоков и соединений с backend-сервером.
server_version="5.1.30"
connect_timeout_server=10000
monitor_history=60000
monitor_connect_interval=200000
monitor_ping_interval=200000
ping_interval_server=10000
ping_timeout_server=200
commands_stats=true
sessions_sort=true
}




datadir — расположение файла базы SQLite3, по умолчанию /var/lib/proxysql

admin_variables — настройки административного интерфейса

mysql_variables — содержит глобальные переменные для севера входящих mysql-запросов.



Серверы и прочие настройки мы добавим через mysql-интерфейс.



Первый запуск и инициализация

Инициализируем настройки.



Инициализация переносит настройки сервера из конф. файла(слой 3) в базу SQLite3 в памяти(слой 2), сбрасывая при этом все настройки, которое хранились в памяти(слой 2) и переименовывая файл на диске(слой 3).

proxysql --initial




Конфигурирование ProxySQL на лету(Runtime).

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



mysql -h 127.0.0.1 -P6032 -uadmin -p

Enter password:

MySQL [(none)]>




Теперь мы находимся в админ. интерфейсе. Посмотрим какие есть тут таблицы:


MySQL [(none)]> show tables;
+--------------------------------------+
| tables |
+--------------------------------------+
| global_variables |
| mysql_collations |
| mysql_query_rules |
| mysql_replication_hostgroups |
| mysql_servers |
| mysql_users |
| runtime_mysql_query_rules |
| runtime_mysql_replication_hostgroups |
| runtime_mysql_servers |
| runtime_scheduler |
| scheduler |
+--------------------------------------+
11 rows in set (0.00 sec)




mysql_servers — содержит список backend-серверов

mysql_users — содержит список всех пользователей, которые имеют доступ к ProxySQL и backend-серверам.

mysql_query_rules — все правила кеширования, перенаправления и замены SQl-запросов, которые проходят через прокси.

global_variables — содержит глобальные переменные(которые мы настраивали в конф. файле) MySQl-сервера ProxySQL и административные настройки.

mysql_replication_hostgroups — список групп хостов, к которым будут прикреплены бекенды, к которым в свою очередь будут применяться правила запросов.

mysql_query_rules — правила проксирования запросов.



Добавим бекенды, для начала убедимся, что таблицыmysql_servers, mysql_replication_hostgroups и mysql_query_rules пусты.



Проверим таблицы:

MySQL [(none)]> SELECT * FROM mysql_servers;
Empty set (0.00 sec)

MySQL [(none)]> SELECT * from mysql_replication_hostgroups;
Empty set (0.00 sec)

MySQL [(none)]> SELECT * from mysql_query_rules;
Empty set (0.00 sec)




Действительно, необходимые таблицы пусты. Перед добавлением нам надо определиться что и куда мы будем проксировать, я добавлю два сервера, на один будет осуществляться запись(INSERT, UPDATE и т.п), а со второго мы будем только читать данные(SELECT), в общем типичная схема master-slave с распределением чтения-записи показным серверам. Для этого мы создадим 2 хост группы.



Добавим backend-серверы:

Первый сервер у нас будем заниматься записью в БД и состоять в хост группе 1:

MySQL [(none)]> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (0,'192.168.100.2',3307);




Второй сервер у нас настроен на slave и с него мы будем только выполнять чтение, поместим его в группу 2:

MySQL [(none)]> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (1,'192.168.100.3',3307);
Query OK, 1 row affected (0.01 sec)

MySQL [(none)]> SELECT * FROM mysql_servers;
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+
| hostgroup_id | hostname | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+
| 0 | 192.168.100.2 | 3307 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 |
| 1 | 192.168.100.3 | 3307 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+
2 rows in set (0.00 sec)





Таблица mysql_replication_hostgroups имеет 2 поля, первое writer_hostgroup — в ней находятся номера групп, в которые входят хосты на запись. В reader_hostgroup — на чтение.

Добавим 2 хостгруппы(1,2) в таблицу mysql_replication_hostgroups:


MySQL [(none)]> INSERT INTO mysql_replication_hostgroups VALUES (1,2);
Query OK, 1 row affected (0.00 sec)

MySQL [(none)]> SELECT * FROM mysql_replication_hostgroups;
+------------------+------------------+
| writer_hostgroup | reader_hostgroup |
+------------------+------------------+
| 1 | 2 |
+------------------+------------------+
1 row in set (0.00 sec)




Теперь перенесем данные о backend-серверах и хост группах из памяти в runtime, чтобы они вступили в силу немедленно:

MySQL [(none)]> LOAD MYSQL SERVERS TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)




и сохраним данные на диск(слой 3):

MySQL [(none)]> SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.00 sec)




Самое время добавить правила проектирования запросов, для этого существует таблица mysql_query_rules:

Таблица имеет следующую структуру:

CREATE TABLE mysql_query_rules (
rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0,
username VARCHAR,
schemaname VARCHAR,
flagIN INT NOT NULL DEFAULT 0,
match_pattern VARCHAR,
negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0,
flagOUT INT,
replace_pattern VARCHAR,
destination_hostgroup INT DEFAULT NULL,
cache_ttl INT CHECK(cache_ttl > 0),
reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL,
timeout INT UNSIGNED,
delay INT UNSIGNED,
apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0
)


rule_id — номер правила

active — правило включено, 0-выключено

username и schemaname — Если не-NULL, то правило выполнится только в случае правильного соответствия username/schemaname для соединения

flagIN, flagOUT, apply — Эти флаги дают возможность создать «цепочку из правил». На практике лично мне еще не приходилось их использовать, так что даю пока оригинал текста из официальной документации, если кто сможет грамотно и понятно перевести, пожалуйста. these allow us to create «chains of rules» that get applied one after the other. An input flag value is set to 0, and only rules with flagIN=0 are considered at the beginning. When a matching rule is found for a specific query, flagOUT is evaluated and if NOT NULL the query will be flagged with the specified flag in flagOUT. If flagOUT differs from flagIN, the query will exit the current chain and enters a new chain of rules having flagIN as the new input flag. This happens until there are no more matching rules, or apply is set to 1 (which means this is the last rule to be applied)

match_pattern — регулярное выражение, будут проксироваться правила, которые попадают под него.

replace_pattern — регулярное выражение для замены проектируемого запроса или его части.

destination_hostgroup — номер хост группы к которой будет применяться правило.

cache_ttl — количество секунд на которе будет кешироваться запрос.

reconnect — пока не используется

timeout — таймаут на выполнения match_pattern или replace_pattern, если запрос занимает больше времени, он убивается.

delay — Задержка до выполнения запроса к backend, полезна в случае, если например запрос SELECT идет сразу после INSERT/UPDATE, чтобы дать время на репликацию.



Добавим 3 правила в таблицу mysql_query_rules

MySQL [(none)]> INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) VALUES(1,1,'^SELECT .* FOR UPDATE$',1,1);
MySQL [(none)]> INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) VALUES(1,1,''^SELECT',2,1);
MySQL [(none)]> INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) VALUES(1,1,'.*',1,1);




Первое правило перенаправляет все запросы SELECT UPDATE на master-сервер

Второе правило перенаправляет се завпросы SELECT slave-сервер

И наконец третье правило перенаправляет все остальные запросы на master-сервер.



Пользователи

Теперь добавим пользователей в таблицу mysql_users. ProxySQL нуждается во всех пользователях, которые присутствуют на всех серверах подключенных к нему. Запрос на добавления пользователя root для обоих хост групп:

MySQL [(none)]> INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('root','password',1);
Query OK, 1 row affected (0.00 sec)
MySQL [(none)]> INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('root','password',0);
Query OK, 1 row affected (0.00 sec)




Перенесем изменения в Runtime и сохранимна диск:

MySQL [(none)]> LOAD MYSQL USERS FROM MEMORY
MySQL [(none)]> LOAD MYSQL USERS TO RUNTIME
MySQL [(none)]> SAVE MYSQL USERS FROM MEMORY
MySQL [(none)]> SAVE MYSQL USERS TO DISK
MySQL [(none)]> LOAD MYSQL QUERY RULES FROM MEMORY
MySQL [(none)]> LOAD MYSQL QUERY RULES TO RUNTIME
MySQL [(none)]> SAVE MYSQL QUERY RULES FROM MEMORY
MySQL [(none)]> SAVE MYSQL QUERY RULES TO DISK




Заключение

После вышеописанных действий мы имеем настроенный ProxySQL на репликации Master-Slave. Разумеется это не все возможности ProxySQL, кроме всего прочего он имеет может осуществлять отличный мониторинг всех backend-ов и, разумеется, самого себя.



Ссылки:

Офф сайт: http://www.proxysql.com/

Офф. Документация: https://github.com/sysown/proxysql/tree/master/doc

Настройка Master-Slave репликации с применением ProxySQL и настройкой из конф.файла: http://unix-admin.su/scalable-mysql-cluster/
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303612/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Как sql-запросом извлечь из базы данных информацию, которой там нет

Среда, 15 Июня 2016 г. 16:25 (ссылка)

Под таким хитрым заголовком скрывается достаточно несложная задача, но сначала небольшое вступление:



Приходят пользователи и просят: «Вот мы внесли данные в базу, а скажите нам, чего не хватает? Какие данные мы ещё не внесли в базу и их не хватает для полного счастья?»

Первая (и скажем честно, весьма глупая) реакция: «Как же я вам найду то, чего нет в базе данных?».



Но отбросим эмоции и применим логику. Ведь, как правило, требуются данные, формирование которых подчиняется некоему правилу — номера квитанций, справок и так далее… И я исхожу из того, что все эти номера и идентификаторы могут быть преобразованы в натуральную последовательность.

То есть задача будет сформулирована следующим образом: в базе данных хранится последовательность натуральных чисел, в которой есть пропуски, и необходимо вывести пропущенные числа для пользователя.

В такой формулировке задача уже выглядит достаточно простой. Более того — возникает желание реализовать эту задачу одним единственным sql-запросом.



Давайте создадим таблицу и заполним какими-нибудь данными.



CREATE TABLE IF NOT EXISTS `Test` (`id` int(6) NOT NULL);
INSERT INTO `Test` (`id`) VALUES (3), (5), (7), (8) , (9) , (11) , (12), (16) , (17) ;


Основная идея следующая: сравнить таблицу с самой собой же и для каждого значения ИКС найти минимальное ИГРЕК (которое всё же больше ИКСа), где (ИКС + 1) и (ИГРЕК — 1) будут нашими границами пропущенных диапазонов чисел. Добавив логичное условие, что, (ИКС + 1) должен быть не меньше (ИГРЕК — 1) получим следующие диапазоны: от 4 до 4, от 6 до 6, от 10 до 10 и от 13 до 15.

Какие есть нюансы:

1) Может быть пропущен первый элемент последовательности (в нашем случае это 1)

2) Неизвестен последний элемент последовательности (а вдруг это 22). Можно, конечно, запрашивать эту информацию у пользователя, но опыт подсказывает, что лучше этого избегать.

3) Диапазон «от 4 до 4» выглядит глючно, надо заменить просто на одно число

4) Результат всё-таки желательно получить значением одной строки, а не набором строк



Учитываем замечания и получаем вариант скрипта под MySQL:



SELECT GROUP_CONCAT( ranges )
FROM (
SELECT
CASE
WHEN id2 IS NULL
THEN CONCAT( id1, '...' )
WHEN id1 = id2
THEN id1
ELSE CONCAT( id1, '-', id2 )
END ranges
FROM (
SELECT id +1 id1, (
SELECT MIN( id ) -1
FROM `Test` t2
WHERE t2.id > t1.id
)id2
FROM `Test` t1
UNION
SELECT 1 , MIN( id ) -1
FROM `Test` t3
)t
WHERE id1 <= id2
OR id2 IS NULL
ORDER BY id1
)tt


и вариант под Oracle:



SELECT LISTAGG (ranges, ', ')
FROM (
SELECT CASE
WHEN id2 IS NULL THEN TO_CHAR (id1) || '...'
WHEN id1 = id2 THEN TO_CHAR (id1)
ELSE TO_CHAR (id1) || '-' || TO_CHAR (id2)
END ranges
FROM (
SELECT id + 1 id1,
(SELECT MIN (id) - 1
FROM TEST t2
WHERE t2.id < t1.id) id2
FROM TEST t1
UNION
SELECT 1, MIN (id) - 1
FROM TEST t3) t
WHERE id1 <= id2 OR id2 IS NULL
ORDER BY id1
) tt


Результатом их выполнения является строка '1-2, 4, 6, 10, 13-15, 18...'

Во-первых, эта строка содержит то, что хотели пользователи.

Во-вторых, результат выглядит понятно для любого пользователя.

И в-главных, запрос выводит данные, которые действительно в базе данных не хранятся!


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303364/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

В эту пятницу пройдет 7-я конференция сообществ DevConf 2016

Вторник, 14 Июня 2016 г. 21:12 (ссылка)

Уже в эту пятницу сообщества Python, Go, Ruby, PHP, Javascript, MySQL, PostgreSQL,Tarantool встретятся на DevConf 2016 — остались последние 60 мест.



В этом году на конференции DevConf 9 секций: golang, php, ruby, python, common, js, devops,

pm, storage




После 17:30 мы проводим открытые митапы сообществ и круглые столы, которые может посетить любой желающий.



18 июня состоятся мастер-классы: Golang, PostgreSQL, Построение

эффективной команды и налаживание процесса разработки, GraphQL & Relay, MySQL и архитектуры социальной сети




18-19 июня проводим хакатон по Yii в ТАСС



Начнем с 2-х новых секций

PM:


  • Миф об очень сложном Highload

  • Devs vs CTO vs CEO

  • Адаптируйся или умри

  • Секреты распределенной разработки, которые я узнал от сотрудников

  • Basecamp (37signals) и Buffer

  • Нет времени разработать самому? Дай возможность другим!

  • Технобренд

  • Double-Loop TDD: TDD "для жизни"

  • Работа над UX в Agile проектах — You Did It Wrong

  • + Мастер-класс (3 часа): Построение эффективной команды и налаживание процесса разработки



Golang:


  • Prometheus мониторинг от души

  • Как приготовить Go микросервис к продакшену

  • Golang в действии: Как нам удается писать highload приложение на

  • (не?)подходящем языке

  • Go + SMTP + RabbitMQ = PostmanQ или как мы рассылаем ~20K писем в минуту

  • Аудиоотпечатки для индексации всей музыки ВКонтакте

  • + Мастер-класс (3 часа): Написание веб-приложения на языке Golang



DevOps:


  • ChatOps: как управлять инфраструктурой из чата

  • Навыки DevOps инженера

  • Автоматизация инфраструктуры. Зачем мы это делаем?

  • Техническая оптимизация сайта для поисковых машин — о чём забывают даже гуру

  • Практические примеры использования Docker

  • Отказоустойчивость 99,999% своими руками

  • Эффективная организация параметров групп и хостов в Ansible



PHP:


  • Развитие ветки PHP-7.*

  • SOLID-принципы с примерами на PHP

  • Использование геолокации в Badoo

  • Безопасность: от базовых принципов до особенностей PHP

  • Гибкая модульная архитектура SaaS платформ на Yii2.

  • API — я расскажу где раскиданы грабли

  • Drupal 8: Теперь со вкусом Symfony

  • + Мастер-класс: Разработка крупного масштабируемого web 2.0 проекта с нуля (соц.сеть на 100 млн пользователей)



Python:


  • Самые частые проблемы и пути решения при росте нагрузки и

  • масштабировании проекта.

  • Типы: Python vs Typescript

  • Решаем сложные задачи в MongoDB просто с Mnj

  • Эволюция управления быстро-растущей разработкой ПО с примерами

  • автоматизации на стеке технологий Django Apps + Docker

  • Обзор архитектуры и технической реализации современного биллинга на

  • базе Django

  • Как и зачем делать свой ORM на Python.

  • Aioriak, зачем?

  • Возможно ли подружить Django ORM и PostgreSQL?

  • Опыт использования событийной архитектуры в SaaS сервисе.



Storage:


  • PostgreSQL для разработчиков приложений

  • Крылья, ноги и хвосты: сильные стороны MySQL и когда PostgreSQL завоюет мир

  • Обзор Tarantool DB

  • MariaDB 10.1 – что нового

  • Новые технологии репликации данных в PostgreSQL

  • Производительность MySQL: что нового?

  • Секционирование больших таблиц в PostgreSQL

  • Новые возможности MySQL 5.7

  • + Мастер-класс (3 часа): Беспроблемная эксплуатация PostgreSQL

  • + Мастер-класс (3 часа): Производительность MySQL и работа с высокими нагрузками



JavaScript:


  • React Native, Relay и GraphQL — опыт в production

  • Что делать с неповоротливым JQuery

  • Парсеры — это спарта

  • МРТ для данных

  • Инфраструктура распределенных приложений на nodejs

  • Декларативное программирование на CSS

  • Как мы адаптировали для смартфонов 100+ сайтов по технологии

  • JavaScript-adaptive

  • Язык описания шаблонов Snakeskin

  • Как tutu.ru делает реинжиниринг работающего продукта на ходу

  • + Мастер-класс (6 часов): GraphQL и Relay



Common:


  • HTTP/2: мифы и факты

  • Эффективное использование RabbitMQ в продакшн

  • Почему язык Lua — это интересно?

  • Язык программирования Rust

  • Страницы AMP. Будь для Google VIP.

  • Великолепное API без REST

  • ACL в ERP/CRM системах: архитектура и реализация на конкретном примере

  • Внедрение тестирования в проект

  • Компрометация и защита веб-приложений от современных хакерских атак



Ruby:


  • Разработка Telegram-ботов на языке Ruby

  • Изоморфные приложения на clojure

  • Нагрузочное тестирование веб-сокетов с помощью Docker

  • Пишем расширение для Ruby на Crystal

  • Иммутабельность и статическая типизация для Ruby программистов

  • Как была сделана система управления доступом к суперкомпьютерам МГУ

  • Как с помощью rails и extjs создавать большие корпоративные приложения

  • Кэширование средствами Rails проектов с архитектурой CQRS



После докладов сообщества проведут митапы по MySQL, Laravel,DevOps, ChatBots.



Организаторы конференции сообщества разработчиков: MoscowPython.ru,PHPClub.ru, RailsClub.ru, MoscowJs.ru



Партнерами в 2016 году стали: ТАСС, Badoo, Postgres Professional,4Gophers, VK, REG.RU, ItSoft, Centos-admin, eLama, CMSMagazine,

Joomla, Drupal, NetCat, Sesmik CMS,TVM.ru, Conf.Guru



Новости и скидки на участие в нашем канале @devconf_ru в Telegram
Original source: habrahabr.ru.

https://habrahabr.ru/post/303292/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Способы генерации числовой последовательности (данных) в MySQL

Среда, 08 Июня 2016 г. 19:57 (ссылка)

Периодически при разработке какого либо проекта требуется сгенерировать данные в таблицах, чтобы потом прогнать по тестам для оценки производительности работы (используются или нет индексы, как долго исполняется запрос при большой выборке и т.д.). Для этого обычно берется реализованная функциональность API (функции) (php, node.js и т.д.) проекта и прогоняются через CLI для заполнения данными таблиц (insert). Неудобство заключается в том, что нельзя это сделать по быстрому.



Особенно, если данных надо генерировать на десятки миллионы строк. При изучении БД PostgreSQL я обнаружил, что здесь уже есть готовая функция generate_series() возвращающая таблицу, которую потом легко можно перенаправлять на вставку данных в другую таблицу. Очень легка и удобна в использовании, позволяющая указать интервал генерации значений. Приведу несколько примеров, для того, чтобы потом перейти к рассмотрению подобной реализации в БД MySQL.



Пример генерации числовой последовательности.



postgres=# SELECT * FROM generate_series(1,10);
generate_series
-----------------
1
2
3
4
5
6
7
8
9
10
(10 rows)



Если сделать дополнительно explain для информации.



postgres=# explain SELECT * FROM generate_series(1,10);
QUERY PLAN
------------------------------------------------------------------------
Function Scan on generate_series (cost=0.00..10.00 rows=1000 width=4)
(1 row)





Пример генерации числовой последовательности с последующей ставкой в таблицу.



postgres=# create table test (number int);
CREATE TABLE
postgres=# \d
List of relations
Schema | Name | Type | Owner
--------+------+-------+----------
public | test | table | postgres
(1 row)



postgres=# insert into test select * from generate_series(1,10);
INSERT 0 10

postgres=# select * from test;
number
--------
1
2
3
4
5
6
7
8
9
10
(10 rows)



Подобные функции в PostgreSQL можно писать самому на уровне SQL и соответственно описывать свои необходимые последовательности. К примеру, номерные знаки автомобилей, документов, кассовых чеков. В документации представлены интересные варианты генерации текста, списка дат и т.д.



Вернемся к БД MySQL. Есть ли подобная функциональность?



Поиск по интернету показал, что данная возможность появилась в БД MariaDB (ответление MySQL) начиная c 10 версии. Реализация выполнена не ввиде функции, а как отдельный дополнительный движок базы данных, по аналогии как innodb, myisam. Способ использования также интересен и очень удобен.



Генерация числовой последовательности от 1 до 5.



MariaDB [metemplate]> SELECT * FROM seq_1_to_5;
+-----+
| seq |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+-----+
5 rows in set (0.00 sec)



Генерация числовой последовательности от 1 до 15, с интервалом 2.



MariaDB [metemplate]> SELECT * FROM seq_1_to_15_step_2;
+-----+
| seq |
+-----+
| 1 |
| 3 |
| 5 |
| 7 |
| 9 |
| 11 |
| 13 |
| 15 |
+-----+
8 rows in set (0.00 sec)



Как Вы уже наверное догадались, первым числом указывается начальное значение, второе максимальное значение, третье — шаг итерации. Аналог простейшего цикла через while. Для примера, на PHP.







[root@localhost ~]# php while.php
0 => 1
1 => 3
2 => 5
3 => 7
4 => 9
5 => 11
6 => 13
7 => 15



Функциональность не ограничивается только генерацией. Можно делать объединения, работать как с нормальными обычными таблицами.



MariaDB [metemplate]> desc example;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| a | int(11) | YES | MUL | NULL | |
| b | int(11) | YES | MUL | NULL | |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.01 sec)



MariaDB [metemplate]> select example.a, example.b from example inner join (select seq from seq_1_to_15) as generate on generate.seq = example.a;
+------+------+
| a | b |
+------+------+
| 1 | 2 |
| 4 | 1 |
| 2 | 7 |
| 9 | 9 |
| 1 | 19 |
| 11 | 12 |
+------+------+
6 rows in set (0.00 sec)





Более детальные примеры можно просмотреть в документации По умолчанию данный движок не подключен и необходимо выполнить команду.



INSTALL SONAME "ha_sequence";




Можно для интереса даже просмотреть таблицу через explain, где в качестве движка указан sequence.



MariaDB [metemplate]> show create table seq_1_to_15\G;
*************************** 1. row ***************************
Table: seq_1_to_15
Create Table: CREATE TABLE `seq_1_to_15` (
`seq` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`seq`)
) ENGINE=SEQUENCE DEFAULT CHARSET=latin1
1 row in set (0.00 sec)





MariaDB [metemplate]> show  index from seq_1_to_15\G;
*************************** 1. row ***************************
Table: seq_1_to_15
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: seq
Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type:
Comment:
Index_comment:
1 row in set (0.01 sec)



MariaDB [metemplate]> desc seq_1_to_15;
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| seq | bigint(20) unsigned | NO | PRI | NULL | |
+-------+---------------------+------+-----+---------+-------+
1 row in set (0.00 sec)



Что же делать с более ранними версиями MySQL (MariaDB)? В этом случае есть своего рода костыльные решения, которые приблизительно, как — то решают данный вопрос, но по сути это совсем не то.



Пример 1.



MariaDB [metemplate]> create table two select null foo union all select null;
MariaDB [metemplate]> create temporary table seq ( foo int primary key auto_increment ) auto_increment=1 select a.foo from two a, two b, two c, two d;
Query OK, 16 rows affected (0.08 sec)
Records: 16 Duplicates: 0 Warnings: 0



MariaDB [metemplate]> select * from seq where foo <= 23;
+-----+
| foo |
+-----+
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
| 21 |
| 22 |
| 23 |
+-----+
15 rows in set (0.00 sec)




Пример 2.



MariaDB [metemplate]> CREATE OR REPLACE VIEW generator_16
-> AS SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL
-> SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL
-> SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
-> SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
-> SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL
-> SELECT 15;
Query OK, 0 rows affected (0.09 sec)



MariaDB [metemplate]> select * from generator_16;
+----+
| n |
+----+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
+----+
16 rows in set (0.01 sec)



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/302926/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Готовим простой блог на микросервисах, пишем свой микрофреймворк на php и запускаем все на Docker с примерами

Вторник, 07 Июня 2016 г. 19:49 (ссылка)

А что если я скажу вам, что новый продукт можно сразу начинать писать на микросервисной архитектуре, а не заниматься распилом монолита? Это вообще нормально? Удобно? Хотите узнать ответ?



Задача: необходимо написать за выходные (время ограниченно 10-15 часами) сферический блог на микросервисах, на php, не используя никаких фреймворков. Можно пользоваться здравым смыслом. А еще забудем о том что такое фронтенд и вспомним что мы жить не можем без виртуализации. Выберем Docker. Интересно? Вперед под кат.



image



Микросервисы



Если вам интересен микросервисный подход, но вы не знаете с чего начать, начните с книги "Building Microservices" Сэма Ньюмена. Постараюсь немного описать основные моменты данного подхода, если у вас будут какие-то дополнения, пишите пожалуйста в комментариях. И вообще по любому поводу пишите, я не претендую на истинность какого-либо из описанных ниже подходов, особенно в Вашем конкретном случае.



Будем рассматривать все на примере вышеупомянутого блога. Безусловно, это задача ради задачи, но хочется отметить что даже в таком варианте, это работать будет и будет работать неплохо (быстро и без проблем).



Суть микросервисов легко понять в сравнении с монолитной архитектурой. Как у нас выглядит обычный движок для блога? Грубо говоря это просто одно приложение. Работа с статьями, комментариями, страницами, пользователями и прочими функциональными единицами заключена в едином пакете исходного кода, который не делится никак.





Где все связи между компонентами — это вызовы внутри кода, какие-то отношения между классами, паттерны и т.п. или даже просто говнокод, если нельзя отделить одно от другого.



Как будет выглядеть наш блог? Да примерно также, если честно.





Единственное отличие, что квадратики с компонентами — это больше не компоненты заключенные в код одного приложения, а стрелочки — это больше не системные вызовы классов внутри этого кода. Теперь — это отдельные компоненты, а стрелочки — обычные запросы по http.



Зачем это нужно? Сразу определимся, что наверное, это нужно не всем. Это должно быть очень удобно, если вы — достаточно крупная компания, способная выделить по команде разработки на каждый сервис. Думаю, даже средним компаниям, если выделить по человеку на каждый сервис будет тоже неплохо. Впрочем, даже если ты один на всю компанию, ты сможешь найти в микросервисах что-то интересное.



Насколько большим должен быть сервис? Границы провести сложно, ошибка будет стоить вам дорого, но, если в кратце, то сервис это некая единица вашей системы, которую вы можете полностью переписать за короткое время. Эмпирически пусть за неделю вы или ваша команда должны справится с сервисом. Основная идея тут — сервисы должны быть небольшие. Они не должны превращаться в кучу монолитов.



Итак, позитивные вещи, которые я смог выделить для себя, в целом все они проходят под одним трендом: Невероятное удобство для разработки:




  • Отказоустойчивость. Так как свзя между сервисами больше не жесткие, сервис может умереть по чьей-то глупости (например сервис комментариев), но в целом на блоге это не скажется никак, кроме того что пропаду комментарии.

  • Язык. Вы можете разработывать новый сервис на чем угодно. В общем выбор языка перестает напоминать поиск серебряной пули, для каждого компонента системы вы можете выбрать тот инструмент, который ей подходит больше всего в текущий момент времени. Почему? Потому что это больше не дорого для компании (сервис маленький), вы всегда можете выкатить старый сервис назад, вы даже можете использовать одновременно одинаковые сервисы написанные на разных языках, чтобы понять, что лучше. Цена ошибки неизмеримо меньше.

  • Маштабируемость. Приложение тормозит и не справляется? Нужен новый огромный сервер для всего приложения, а лучше 10? Забудьте. Теперь вы можете масштабировать сервисы. Просто добавьте побольше сервисов :)

  • В целом высокая скорость работы, как результат всего что выше.



Что должно уметь наше приложение? Так то не очень много.

Четыре страницы:




  • Список постов

  • Открытый пост с комментариями

  • Добавление поста

  • Авторизация



Функционал простой:




  • Авторизованный пользователь может добавить пост

  • Кто угодно может его комментировать.



Docker





Все, не будем больше о теории, давайте пилить приложение. Оно у нас будет на докере. Настолько распределенное приложение разрабатывать на одной машине без виртуализации почти невозможно. Описание работы докера будет представлено обрывками, поскольку выходит за тему данной статьи. Предполагается, что вы о нем что-то знаете.



Кстати, вот ссылка на репу, из которой вы можете скачать и запустить блог, посмотреть что-то по коду ниже. https://github.com/gregory-vc/blog



Сколько будет контейнеров в нашем простейшем блоге? Контейнер, это кстати по сути виртуализация отдельного сервера, который общается по сети с другими контейнерами, правда если проводить жесткую аналогию контейнер=сервер, от некоторых контейнеров нужно будет отказаться, но тем не менее. Для простейшей реализации блога на микросервисах я насчитал 24 контейнера. Давайте посмотрим.




  • Общие контейнеры: база для сервиса авторизации, основная база блога, редис.

  • Сервис-шлюз: php, контейнер для исходного кода, nginx.

  • Сервис для работы с постами: (php, контейнер для исходного кода, nginx) х 2

  • Сервис для работы с комментариями: тоже х 2

  • Сервис авторизации и аутентификации: тоже х 2



Зачем на по две копии некоторых сервисов? Потому что с одной будет не интересно и не понятно.



Файл docker-compose, который развернет все это одной командой выглядит вот так:

https://github.com/gregory-vc/blog/blob/master/host/docker-compose.yml

Из самого интересного рассмотрим настройки php контейнера нашего шлюза.



'php_gate':
image: 'tattoor/blog_php'
container_name: 'php_gate'
volumes_from: ['source_gate']
volumes: ['./logs/php/gate/:/var/log/dev_php']
links:
- nginx_post_1:post1.blog
- nginx_post_2:post2.blog
- nginx_comment_1:comment1.blog
- nginx_comment_2:comment2.blog
- nginx_auth_1:auth1.blog
- nginx_auth_2:auth2.blog
- redis
environment:
- POST_1_HOST=post1.blog
- POST_1_PORT=80
- POST_2_HOST=post2.blog
- POST_2_PORT=80
- COMMENT_1_HOST=comment1.blog
- COMMENT_1_PORT=80
- COMMENT_2_HOST=comment2.blog
- COMMENT_2_PORT=80
- AUTH_1_HOST=auth1.blog
- AUTH_1_PORT=80
- AUTH_2_HOST=auth2.blog
- AUTH_2_PORT=80


Раздел описания контейнера links, это по сути просто редактирование /etc/hosts/



docker exec php_gate cat /etc/hosts
172.17.0.36 auth1.blog 86b8b266477d nginx_auth_1
172.17.0.36 nginx_auth_1 86b8b266477d
172.17.0.21 comment1.blog 836bacb42e78 nginx_comment_1
172.17.0.19 comment2.blog c554a8888801 nginx_comment_2
172.17.0.20 post2.blog 37f81921419c nginx_post_2
172.17.0.7 redis a1932016be87
172.17.0.37 auth2.blog 5715045a213b nginx_auth_2
172.17.0.37 nginx_auth_2 5715045a213b
172.17.0.21 nginx_comment_1 836bacb42e78
172.17.0.19 nginx_comment_2 c554a8888801
172.17.0.22 nginx_post_1 1cc1ef5ab896
172.17.0.22 post1.blog 1cc1ef5ab896 nginx_post_1
172.17.0.20 nginx_post_2 37f81921419c
172.17.0.23 fafe93f31a67


Где по обозначенному хосту мы просто имеем доступ к другому контейнеру через внутреннюю сеть докера.



А раздел environment — это просто обозначение переменных, которые мы сможем достать с вами внутри приложения через getenv(). Сделано так, чтобы файл docker-compose был единой точкой входа для настройки всего приложения.



В то время как структура наших сервисов выглядит как просто директории лежащие рядом,




  • Auth

  • Comment

  • Gate

  • Post



Но, на самом деле, при запуске докера хостов, каждая из этих директорий оказывается внутри отдельного изолированного соответствующего контейнера. Делается это как-то так:



'source_post_1':
volumes: ['../Services/Post:/home/gregory/source/']


То есть, хоть сейчас они и рядом, при запуске не будет возможности из одного сервиса проинклудить класс другого сервиса или что-то типа того. Рядом они исключительно из удобства, в реальной жизни они должны быть каждый в своем репозитории, вообще не касаясь друг друга.



Сервис Gate





Этот сервис будет являтся точкой входа на наш блог, именно он будет рендерить шаблоны, отображать результат и дергать нужные ему сервисы. Кстати существую разные подходы, например можно отказаться от единой точки входа и реализовать все на фронтенде. То есть браузер сам будет ходить в нужные сервисы и собирать результат прямо в браузере. Что сказать, все зависит от вашего конертного случая и там и там есть свои плюсы и минусы.



Итак, у нас есть php и больше ничего. Хотя, давайте возьмем хотя бы composer, куда без него. Создадим еще две директории, одну с нашим микрофремворком, который мы сейчас напишем, вторую для public скриптов, js, и прочих ресурсов.



Выглядит так:




  • My

  • public

  • composer.json



В composer просто укажем, откуда осуществлять autoload, чтобы нам самим с этим не заморачиваться, и подключим сгенеренный autoload в public/index.php



Так, что-то у нас уже есть, давайте определимся что нам вообще еще будет надо?




  • MVC, а значит контроллеры

  • Место для бизнес логики

  • Шаблоны

  • Шаблонизатор



Неплохо, что еще?




  • Немного di, самый простой, ввиде хранилища объектов.

  • Само хранилище

  • Запрос

  • Ответ

  • Роутинг, о да, с него стоит начать.

  • Сессии и прочее по мелочи.



Напишем вот такое хранилище объектов, чтобы не создавать их где попало, а иметь возможность получить доступ (inject) к уже созданным в любой точке приложения со всем нужными зависимостями (dependency). Мы не будем развлекаться с Reflection и прочими интересными штуками, время у нас жестко ограничено.



        Storage::set('Request', new Request());
Storage::set('Router', new Router());
Storage::set('Redirect', new Redirect());
Storage::set('App', new App());


В Di, используя это хранилище просто добавляем все объекты что нам нужны.

В паблике стартуем Di, получаем роутер, регистрируем все урлы что нам пригодятся, получаем приложение и стартуем его.



        $router->get('/logout/', 'AuthController@logout');
$router->get('/404', 'SystemController@notFound');
$router->post('/post/add_request/', 'PostController@add')


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



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



        $current_request = $this->router->getCurrent();
$controller = new $current_request->controller;
$response = $controller->{$current_request->method}();
$response->render();


Каркас есть, теперь нам надо работать с сервисами, создаем директорию с сервисами, создаем класс каждого сервиса, описываем точки доступа к каждому из сервисов. Наследуем их от основного класса сервисов, где реализуем варианты запросов.



https://github.com/gregory-vc/blog/blob/master/Services/Gate/My/Engine/Service.php



    static public function get($method, $params = [])
{
$service = new static;
return $service->executeGet($method, $params);
}

static public function post($method, $params = [])
{
$service = new static;
return $service->executePost($method, $params);
}


Там внутри при запросе выбираем рандомны коннектор из предоставляемых сервисом, как-то так



        $rand_connector = rand(0, $count_connector) % $count_connector;


Делаем запрос, из контроллера и рендерим, вот так:



        $posts = Post::get('all');
return $this->response->html('posts', $posts);


Нам нужно отрендерить, но как? Шаблонизаторов у нас нет. Писать свой? Ну нет. Просто используем php.



        ob_start();
require_once($layout_template);
$contents = ob_get_contents();
ob_end_clean();
$this->content = $contents;


Черезвычайно мощный шаблонизатор размером с 4 строчки.



Сервис post и comment



Что дальше? Теперь мы можем делать запросы и рендерить результат, теперь нам нужно написать сервисы отдающие ответ. Все просто копируем наш новый движок в другие сервисы, меняем урлы и пишем работу с моделями и бд, вместо удаленных сервисов.



Реализуем работу с моделями, стандартно findAll, findBy, add, save:

https://github.com/gregory-vc/blog/blob/master/Services/Auth/My/Engine/Model.php



Итак? Если честно, это почти все, что нам нужно, не считая авторизации.

Мы можем делать запросы gate на любой сервис, с любого другого сервиса на любой другой.



Сервис авторизации

Схема проста: мы имеем юзеров и их доступы на сервере авторизации, мы делаем из шлюза запрос на авторизацию, генерируем токен, возвращаем его шлюзу и еще юзера, кладем юзера и токен в сессию и все. Незабываем посылать токен вместе с запросом на добавление поста, потому что что? Правильно, сервис постов пойдет в сервис авторизации и спросит, а правда ли что этот токен хорош? В зависимости от результата генерим разные эксепшены.



    public function login($user, $password) {
$hash = hash('sha256', $password);
$user = User::findBy([
'login' => $user,
'password' => $hash
]);
if (!empty($user) && is_array($user)) {
$user = current($user);
$user['token'] = bin2hex(random_bytes(30));
User::save($user);
return [
'login' => $user['login'],
'token' => $user['token']
];
} else {
throw new \Exception('Not found user');
}
}


Результат



Вообще, можете скачать и развернуть его одной команой, напомню репозиторий: https://github.com/gregory-vc/blog



Где подходило по смыслу — я вывел для наглядности какой именно нодой был сгенерен тот или иной блок.



Еще меня впечатлило время генерации странички. Это 5-9 мс для странички с постом и несколькими комментариями (!). Да, все это необъективно, да, все это попугаи, да, микросервисы тут не при чем, да, смотря с чем сравнивать. Но. Тот же ларавель генерит свою страничку, вообще без запросов и данных, просто приветствие, за 90 мс, на моей же машине. Это в 10-20 раз дольше.



Я понимаю, что там происходит куда больше всего, не сравнить, но тем не менее, попытаюсь выразить мысль: для конкретно текущей задачи отдельного изолированного микросервиса всего этого и не надо. Для сервиса комментов я выкинул класс работы с сервисами по сети. Для сервиса шлюза я выкинул класс работы с базой. Для каждого конретного сервиса я собрал лишь то, что ему надо. А правильном сервису надо совсем чуть-чуть :)



А главное это невероятный потенциал для масштабирования этого блога под просто невероятные нагрузки. Никто не помешает например потом взять и переписать сервис комментариев на Go.



Проблемы



Сетевые накладные расходы

Не зная о том как работает другой сервис, мы можем вполне попасть в ситауцию, когда, он не то что работает плохо, и портит нам все, он еще и использует наш сервис (!) чтобы нам же отдать наши результаты.


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/302844/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Небольшая особенность CHAR и VARCHAR

Вторник, 07 Июня 2016 г. 13:10 (ссылка)

Предыстория





Есть небольшой сервер, на котором крутится стандартный LAMP. Все началось с того, что подходит ко мне QA и говорит: «Есть тема, мне нужно перепроверить регистрацию пользователей, можешь удалить старый аккаунт?», «Не вопрос» — ответил я. Суть в том, вход у нас сделан только через социалки. Что бы не нарушать целостность базы удалением аккаунта, я решил просто взять и перейменовать UID (пользовательский ID в конкретной социальной сети) в таблице.

Так как UID у всех разный (vk, facebook, google… — числовой UID, linkedin — строковый UID) был использован VARCHAR для хранения. В итоге я добавил символ нижнего подчеркивания `_` к строке, и со спокойной душой отписался: «Проверяй...».



image







Я очень сильно удивился, когда услышал: «А ты точно удалил аккаунт, а то отображается мой старый?».

В ходе мини расследования, было найдено место нестыковки.



    /**
* @param string $providerUserId
* @param string|null $provider
*
* @return ent\UserSocial|null
*/
public function getByProviderUserId($providerUserId, $provider = null)
{
$where = 'providerUserId = ?';

if ($provider) {
$where .= ' AND provider = "' . $provider . '"';
}

$res = $this->fetchObjects($where, [$providerUserId]);

if (empty($res)) {
return null;
}

return $res[0];
}




А именно:

$where = 'providerUserId = ?';




Оказалось добавление `_` — никак не повлияло на выборку, так как UID был числом.

В ходе экспериментов были получены следующие данные:



Исходные данные
-- --------------------------------------------------------

-- Host: localhost

-- Server version: 5.5.49-0+deb8u1 - (Debian)

-- Server OS: debian-linux-gnu

-- HeidiSQL Version: 8.3.0.4694

-- --------------------------------------------------------



/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

/*!40101 SET NAMES utf8 */;

/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;

/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;



-- Dumping database structure for test

CREATE DATABASE IF NOT EXISTS `test` /*!40100 DEFAULT CHARACTER SET latin1 */;

USE `test`;



-- Dumping structure for table test.t

CREATE TABLE IF NOT EXISTS `t` (

`id` int(10) NOT NULL AUTO_INCREMENT,

`string` varchar(50) NOT NULL DEFAULT '',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;



-- Dumping data for table test.t: ~5 rows (approximately)

/*!40000 ALTER TABLE `t` DISABLE KEYS */;

INSERT INTO `t` (`id`, `string`) VALUES

(1, '123456'),

(2, '123456_'),

(3, '123456a'),

(4, '1234567'),

(5, '123456_a');

/*!40000 ALTER TABLE `t` ENABLE KEYS */;



-- Dumping structure for table test.t2

CREATE TABLE IF NOT EXISTS `t2` (

`id` int(10) NOT NULL AUTO_INCREMENT,

`string` char(50) NOT NULL DEFAULT '',

PRIMARY KEY (`id`),

KEY `string` (`string`)

) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;



-- Dumping data for table test.t2: ~5 rows (approximately)

/*!40000 ALTER TABLE `t2` DISABLE KEYS */;

INSERT INTO `t2` (`id`, `string`) VALUES

(1, '123456'),

(2, '1234567'),

(3, '123456a'),

(4, '123456_'),

(5, '123456_a');

/*!40000 ALTER TABLE `t2` ENABLE KEYS */;

/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;

/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;









Тест №1:



mysql> select * from t where `string` = 123456;

+----+----------+

| id | string |

+----+----------+

| 1 | 123456 |

| 2 | 123456_ |

| 3 | 123456a |

| 5 | 123456_a |

+----+----------+

4 rows in set, 2 warnings (0.00 sec)





Тест №2:



mysql> select * from t where `string` = '123456';

+----+--------+

| id | string |

+----+--------+

| 1 | 123456 |

+----+--------+

1 row in set (0.00 sec)





Нужно проверить обычный CHAR (ну и индекс добавим, мало ли что...)

Тест №3:



mysql> select * from t2 where `string` = 123456;

+----+----------+

| id | string |

+----+----------+

| 1 | 123456 |

| 3 | 123456a |

| 4 | 123456_ |

| 5 | 123456_a |

+----+----------+

4 rows in set, 3 warnings (0.00 sec)





Тест №4:



mysql> select * from t2 where `string` = '123456';

+----+--------+

| id | string |

+----+--------+

| 1 | 123456 |

+----+--------+

1 row in set (0.00 sec)





Зайдя к официалам на страничку, я ничего похожего не нашел. В итоге пришлось подправить запрос, что бы UID воспринимался как строка, а не как число.



PS. Теперь когда нужно что-то удалить, я добавляю `_` впереди :)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/302804/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Установка связки Carbon + Graphite + Grafana + Nginx + MySQL для сбора и отображения метрик в Ubuntu

Понедельник, 06 Июня 2016 г. 18:15 (ссылка)

Хочу поделиться опытом установки и настройки сервиса для сбора и отображения метрик Graphite + Grafana.

Искал долго, читал много, нашёл 2 статьи на английском, добавил своё, в итоге получилась данная статья.



Немного предыстории..



Graphite — система для отображения метрик (числовых значений) для любых свойств сервера или домашнего ПК.



Carbon — демон/бэкенд, в который пишутся метрики.



Grafana — более красивая и удобная Web-морда для Grapfite.



И так, приступим.



Установка и настройка Php + Nginx + MySQL



Установка Php + Nginx + MySQL



Тут всё довольно просто.



sudo apt install php5-fpm php5-json php5-mysqli
sudo apt install nginx nginx-extras
sudo apt install mysql-server


Во время установки будет запрос пароля для root-пользователя MySQL.



Установка phpMyAdmin



Для более удобного доступа у базам данных MySQL установим phpMyAdmin.



Скачиваем отсюда последнюю версию



cd /usr/share/
sudo wget https://files.phpmyadmin.net/phpMyAdmin/4.6.2/phpMyAdmin-4.6.2-all-languages.zip
sudo unzip phpMyAdmin-4.6.2-all-languages.zip
sudo rm phpMyAdmin-4.6.2-all-languages.zip
sudo mv phpMyAdmin-4.6.2-all-languages phpmyadmin


Настраиваем Nginx для phpMyAdmin



В файл настроек /etc/nginx/conf.d/pma.conf пишем следующее:



server {
server_name pma.your.site;
listen 80;
location / {
root /usr/share/phpmyadmin/;
index index.php index.html index.htm;
location ~ ^/(.+\.php)$ {
try_files $uri =404;
root /usr/share/phpmyadmin/;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;
include /etc/nginx/fastcgi_params;
}
location ~* ^/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ {
root /usr/share/phpmyadmin/;
}
}
}


И перезапусаем Nginx



sudo service nginx restart


Предварительные настройки MySQL



Заходим по адресу pma.your.site, который Вы прописали в настройках выше, авторизуемся под root пользователем с тем паролем, который Вы установиили во время установки MySQL.



Создадим базу данных graphite и пользователя graphite, и дадим этому пользователю все привелегии на эту базу.



Установка и настройка Graphite + Carbon



Установка Grapfite + Carbon



Тут тоже всё довольно просто:



sudo apt-get install graphite-web graphite-carbon


Настройка Graphite



Редактируем файл конфигурации /etc/graphite/local_settings.py.



SECRET_KEY = 'MY NICE RANDOM SALT'
TIME_ZONE = 'UTC'
USE_REMOTE_USER_AUTHENTICATION = True
DATABASES = {
'default': {
'NAME': 'graphite',
'ENGINE': 'django.db.backends.mysql',
'USER': 'graphite',
'PASSWORD': 'mypassword',
'HOST': '127.0.0.1',
'PORT': ''
}
}


Синхронизация базу данных



Синхронизируем базу данных следцющей командой



sudo graphite-manage syncdb


Настройка Carbon



Редактируем следующие файлы конфигурации



/etc/default/graphite-carbon



CARBON_CACHE_ENABLED = true


/etc/carbon/carbon.conf



ENABLE_LOGROTATION = True


Копируем стандартные настройки агрегации хранилища



sudo cp /usr/share/doc/graphite-carbon/examples/storage-aggregation.conf.example /etc/carbon/storage-aggregation.conf


И перезапускаем Carmon



sudo service carbon-cache start


Установка uWSGI



Для цстановки uWSGI запустите следующие комманды



  sudo apt-get install python-dev
sudo pip install uwsgi


Если в Вашей системе не установлен pip — устанавливаем его



sudo apt-get install python-pip


И выполняем команды выше.



Копируем стандартный файл конфигурации



sudo cp /usr/share/graphite-web/graphite.wsgi /usr/share/graphite-web/graphite_wsgi.py


Создаём файлы логов и сокет для прослушки:



sudo touch /var/run/graphite.sock
sudo chmod 777 /var/run/graphite.sock
sudo touch /var/log/graphite.log
sudo chmod 777 /var/log/graphite.log


Создаём файл кконфигурации:



sudo nano  /etc/init/uwsgi-graphite.conf


И вписываем туда следующие строки:



  env UWSGI_BIN=/usr/local/bin/uwsgi
env PYTHONPATH=/usr/share/graphite-web

expect fork
umask 0000

start on runlevel [2345]
stop on runlevel [!2345]

script
exec $UWSGI_BIN --socket /var/run/graphite.sock --master --need-app \
--catch-exceptions --reload-on-exception --pp $PYTHONPATH \
-w graphite_wsgi:application --buffer-size 32768 -p 4 -O 2 >>/var/log/graphite.log 2>&1 &
end script


И запускаем Graphite



sudo service uwsgi-graphite start


Настройка Nginx для Graphite



Выполняем следующие команды:



sudo touch /etc/nginx/conf.d/graphite.conf
# Log files
sudo touch /var/log/nginx/graphite.access.log
sudo chmod 666 /var/log/nginx/graphite.access.log
sudo touch /var/log/nginx/graphite.error.log
sudo chmod 666 /var/log/nginx/graphite.error.log


Редактируем файл конфигурации /etc/nginx/conf.d/graphite.conf



server {
server_name graphite.your.site;
listen 80;
access_log /var/log/nginx/graphite.access.log;
error_log /var/log/nginx/graphite.error.log;
root /usr/share/graphite-web;
location = /favicon.ico {
return 204;
}
location /content {
alias /usr/share/graphite-web/static;
expires max;
}
location / {
uwsgi_pass unix:/var/run/graphite.sock;
include uwsgi_params;
}
}


Перезапускаем Nginx и переходим по адресу graphite.your.site



Так выглядит Graphite



Тестирование Graphana



Для проверки работоспособности Graphana достаточно выполнить одну простую команду:



echo "test.count 9 `date +%s`" | nc -q0 127.0.0.1 2003;


Ну или запустить цикл:



for i in 4 6 8 16 2; do echo "test.count $i `date +%s`" | nc -q0 127.0.0.1 2003; sleep 6; done


Теперь в Graphana модно наблюдать следующее:



Так выглядит Graphite



Установка и настройка красивой Web-морды Grafana



Установка Grafana



Так выглядят графики в Grafana



Для установки Grafana выполняем следующие команды:



echo 'deb https://packagecloud.io/grafana/stable/debian/ wheezy main' |  sudo tee -a /etc/apt/sources.list
curl https://packagecloud.io/gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install grafana


Настройка MySQL для Grafana



Создадим в MySQL базу данных grafana и дадим все привилегии на неё пользователю graphite, которого мы создали ранее.



Редактируем файл конфигурации /etc/grafana/grafana.ini



[database]
type = mysql
host = 127.0.0.1:5432
name = grafana
user = graphite
password = mypassword

[server]
protocol = http
http_addr = 127.0.0.1
http_port = 3000
domain = grafana.your.site
enforce_domain = true
root_url = %(protocol)s://%(domain)s/

[security]
admin_user = admin #Имя пользователя-администратора
admin_password = your_secure_password # Пароль пользователя-администратора
secret_key = your_random_secret_salt


И запускаем Grafana



sudo service grafana-server start


Настройка Nginx для Grafana



Выполняем следующие команды:



sudo touch /etc/nginx/conf.d/grafana.conf
# Log files
sudo touch /var/log/nginx/grafana.access.log
sudo chmod 666 /var/log/nginx/grafana.access.log
sudo touch /var/log/nginx/grafana.error.log
sudo chmod 666 /var/log/nginx/grafana.error.log


И редактируем файл конфигурации /etc/nginx/conf.d/grafana.conf



server {
server_name grafana.your.site;
listen 80;
access_log /var/log/nginx/grafana.access.log;
error_log /var/log/nginx/grafana.error.log;
location = /robots.txt {
echo "User-agent: *\nDisallow: /\n";
}
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
}
}


Перезапускаем Nginx и переходим по адресу grafana.your.site



Так выглядит страница авторизации Grafana



Вводим логин/пароль администратора, которые Вы установили выше, и попадаем в админ-панель Grafana.



Так выглядит админка Grafana



Перед тем, как создавать дашборды и выводить метрики, нужно настроить источники данныхю



Переходим в раздел Data Source -> Add New



Вводим следующие данные




  • Name: graphite

  • URL: graphite.your.site



Вот пример:



Пример настройки источноика данных Grafana



Теперь переходим на главную страницу, жмём New Dashboard -> New,

Слева будет малозаметная зелёная кнопка, при наведении на которую она выползет из-за края экрана. Нажимаем на неё и затем Add Panel -> Graph



Внизу Вы увилите метрики, которые мы создавали тестовой командой выше, test и count.



Выводим графики



На этом пока что всё, позже я раскажу о плагинах для Grafana.



Больше информации



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





Благодарность



За основу статьи были взяты материалы следующих статей:





Оригинал статьи опубликован на моём блоге


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/302720/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] Различие работы в использовании индексов в условии 'OR' баз данных Mysql и PostgeSQL

Понедельник, 06 Июня 2016 г. 15:48 (ссылка)

Многим известна проблема MySQL в не использовании индексов для двух индексируемых колонок в условии «OR». Если подробнее, в таблице есть несколько колонок с проставленными по ним индексами и затем делается выборка по этим колонкам с использованием условия «OR». Индексы не работают. Я решил исследовать этот момент в сравнении с PostgreSQL, так как в настоящий момент времени поставил для себя цель немного познакомиться в PostgreSQL.



Для иллюстрации выполним следующие SQL запросы для двух разных баз данных. Для начала повторим ситуацию с условием «OR» в MySQL.



1. Создаем тестовую таблицу.



 MariaDB [metemplate]> create table example (a int, b int);


2. Вставляем несколько значений.



MariaDB [metemplate]> select * from example;
+------+------+
| a | b |
+------+------+
| 1 | 2 |
| 4 | 1 |
| 2 | 7 |
| 9 | 9 |
| 19 | 9 |
| 1 | 19 |
| 11 | 12 |
| 16 | 10 |
+------+------+
8 rows in set (0.00 sec)


3. Создаем индексы по двум колонкам.



MariaDB [metemplate]> create index a_idx on example(a);
MariaDB [metemplate]> create index b_idx on example(b);



4. Делаем запрос с выборкой по двум колонкам через условие «OR».



MariaDB [metemplate]> explain select * from example where a=1 or b=1\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: example
type: ALL
possible_keys: a_idx,b_idx
key: NULL
key_len: NULL
ref: NULL
rows: 8
Extra: Using where
1 row in set (0.00 sec)



В данном случае явно видно, что база данных MySQL при выборке не использует ни какой из двух индексов. Стандартное решение в этой ситуации это использовать union, чтобы зафиксировать использование созданных индексов.



MariaDB [metemplate]> explain select * from example where a=1 union  select * from example where b=1\G;
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: example
type: ref
possible_keys: a_idx
key: a_idx
key_len: 5
ref: const
rows: 2
Extra:
*************************** 2. row ***************************
id: 2
select_type: UNION
table: example
type: ref
possible_keys: b_idx
key: b_idx
key_len: 5
ref: const
rows: 1
Extra:
*************************** 3. row ***************************
id: NULL
select_type: UNION RESULT
table:
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
Extra:
3 rows in set (0.00 sec)



5. Делаем аналогичную таблицу с данными в базе данных PostgeSQL и пробуем сделать аналогичный случай с условием «OR».



metemplate=# explain select * from example where a=1 or b=1;
Seq Scan on example (cost=0.00..42.10 rows=21 width=8)
Filter: ((a = 1) OR (b = 1))


Индексы не срабатывают, пробуем ранее используемых подход union.



metemplate=# explain select * from example where a=1 union  select * from example where b=1;
HashAggregate (cost=73.83..74.05 rows=22 width=8)
-> Append (cost=0.00..73.72 rows=22 width=8)
-> Seq Scan on example (cost=0.00..36.75 rows=11 width=8)
Filter: (a = 1)
-> Seq Scan on example (cost=0.00..36.75 rows=11 width=8)
Filter: (b = 1)



Индексы не используются.



Наслышавшись о том, что PostgeSQL работает более эффективно с индексами нежели MySQL заподозрил о том, что

видимо PostgeSQL мало данных в таблице и поэтому генерирую больше данных.



metemplate=# insert into example values (generate_series(1,10000), generate_series(1,100000));


При таких объемах индексы используются и действительно, PostgreSQL умеет работать с «OR» условием.



metemplate=# explain select * from example where a=1;
Bitmap Heap Scan on example (cost=4.34..39.96 rows=10 width=8)
Recheck Cond: (a = 1)
-> Bitmap Index Scan on a_idx (cost=0.00..4.34 rows=10 width=0)
Index Cond: (a = 1)


metemplate=# explain select * from example where a=1 or b=1;
Bitmap Heap Scan on example (cost=8.61..47.58 rows=11 width=8)
Recheck Cond: ((a = 1) OR (b = 1))
-> BitmapOr (cost=8.61..8.61 rows=11 width=0)
-> Bitmap Index Scan on a_idx (cost=0.00..4.34 rows=10 width=0)
Index Cond: (a = 1)
-> Bitmap Index Scan on b_idx (cost=0.00..4.27 rows=1 width=0)
Index Cond: (b = 1)

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/302706/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] Чем PostgreSQL лучше других SQL баз данных с открытым исходным кодом. Часть 2

Понедельник, 30 Мая 2016 г. 12:49 (ссылка)


Друзья, представляем вашему вниманию вторую часть перевода «Чем PostgreSQL лучше?». Надеемся, она вызовет такое же горячее обсуждение в комментариях, как и первая часть. А также с радостью продолжим с вами дискуссию лично на PG Day'16 Russia, до которой осталось совсем немного!



В слогане PostgreSQL заявляется, что это «Самая продвинутая база данных с открытым исходным кодом в мире». В первой части этой серии мы рассмотрели хранение данных — модель, структуры, типы и ограничения по размеру, — чтобы дать вам несколько причин, почему Постгрес подтверждает свои слова делом. Во второй части мы поговорим о манипуляциях с данными и поиске, включая индексирование, виртуальных таблицах и возможностях запросов. В этой серии мы выясняем, что выгодно отличает PostgreSQL от других баз данных с открытым исходным кодом, а именно — от MySQL, MariaDB и Firebird.





Читать дальше →

https://habrahabr.ru/post/302160/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<mysql - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda