Хранение файлов в MySQL и их быстрая раздача

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

Но у такого классического похода множество недостатков:

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

Больше о проблемах, возникающих при хранении файлов отдельно от БД можно почитать в презентации SQL Antipatterns, раздел Phantom Files, страница 60. Кстати, автор презентации предлагает решение — хранить файлы прямо в БД, в поле типа BLOB. Правда следует замечание, что это должно быть взвешенное решение в каждом конкретном случае. Ведь при таком способе хранения файлов вебсервер должен при каждом запросе вызывать некий скрипт, который будет извлекать файл из БД и отдавать пользователю, что неминуемо отрицательно скажется на производительности.
Для поиска решения данной проблемы был проведен мозговой штурм и придумано несколько вариантов решения проблемы:

1. Перед удалением записи делать SELECT с тем же условием и получать имена файлов, которые надо удалить. Проблема в том, что если удаляемых файлов много, эта операция может занять некоторое время и по хорошему на это время надо блокировать таблицу на чтение и запись, а во многих случаях это недопустимо.
2. Перед удалением устанавливать у удаляемых записей метку «подлежит удалению», получить все записи с этой меткой и удалить файлы, связанные с этими записями, и наконец удалить все записи с этой меткой. Запросы, работающие с этой таблицей следует доработать, чтобы они не выбирали записи с установленным флагом. Недостатки — необходимость правки множества запросов, к тому же у нас в проекте записи на удаление отбираются достаточно сложным SELECT, которые нельзя переделать в один UPDATE.
3. Первые два способа пытаются решить проблему «потерянных» файлов при удалении записей в БД, которая возникает при «классическом» способе хранения файлов, однако они не решают остальных проблем такого подхода, поэтому мы попытались придумать решения, использующие положительные моменты хранения файлов прямо в БД и избавиться от недостатков, присущих этому подходу.
4. Использовать триггеры. К сожалению, MySQL не имеет в своем языке поддержки команд работы с файлами, такие команды пришлось бы реализовывать самостоятельно, ковыряясь в исходниках MySQL. Из минусов — файлы должны храниться на том же хосте, что и БД, необходимость доработки MySQL, таких готовых решений мы не нашли.
5. Хранить файлы в БД, но отдавать их напрямую вебсервером, без участия PHP. Реализовать это можно, написав модуль к вебсерверу (nginx например) который позволял бы отдавать файлы напрямую из MySQL или применив драйвер файловой системы MySQLfs. Такой подход решает все перечисленные выше проблемы, но его недостаток — дополнительные накладные расходы на хранение файлов в MySQL.
6. Специализированный Storage Engine для MySQL, хранящий записи как файлы.

Остановимся более подробно а последнем пункте. Ведь что собой представляет файловая система — это специализированная БД, которая по ключу «имя файла» позволяет получить запись — его содержимое. То есть можно реализовать свой механизм хранения данных для MySQL, в котором каждая запись будет иметь три поля:

CREATE TABLE `data_storage`.`files` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`path` VARCHAR( 255 ) ,
`data` BLOB
) ENGINE = FILES

Вставлять данные в такую таблицу можно только в поле `data`, при этом они просто сохраняются в файл, уникальное имя ему при этом генерируется автоматически (используя в качестве префикса поле `id`) — например 764533, а в поле `path` автоматически подставляется правильный путь, по которому MySQL положил наши данные — например ‘/mnt/storage/mysqldata/76/45/33/764533_myfile.jpg’. Таким образом к данным, сохраненным в такой таблице можно обращаться как к простым файлам, и при этом MySQL будет поддерживать целостность данных. Таким образом этот способ хранения файлов лишен практически всех недостатков классического подхода (кроме ограничения доступа, но и его можно сделать используя простой скрипт и заголовок X-Accel-Redirect nginx) и в то же время никак не уменьшает производительность при отдаче файлов клиентам.
Проблема за малым — не удалось найти готовой реализации такого движка хранения данных для MySQL, хотя идея общем то простая. Возможно кто-то из хабролюдей подскажет ссылку на готовую реализацию такого storage engine, идея ведь плавает на поверхности, и ее точно кто-то уже мог реализовать.

Автор: Sheder
Источник: shedar.habrahabr.ru

Небольшой FAQ по iptables

Разрешаем производить только 4 коннекта к 22 порту в течении 60 секунд:

iptables -I INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m recent --set
iptables -I INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP


Как удалить iptables правило по номеру

iptables -L INPUT --line-numbers
iptables -D INPUT номер
iptables -t nat -L POSTROUTING --line-numbers
iptables -t nat -D POSTROUTING номер


Как ограничить пропускную полосу для пакетов помеченных меткой через MARK

Сделать MARK, и загнать все такие трансферы в какой-либо класс шейпера. Т.е. если например помеченные пакеты — все их отнести к классу 1:51 где скорость ограничена от 32К до 64К:

tc filter add dev eth1 parent 1:0 protocol ip prio 100 handle 51 fw classid 1:51
tc class add dev eth1 parent 1:2 classid 1:51 htb rate 32Kbit ceil 64Kbit
tc qdisc add dev eth1 parent 1:51 handle 51 sfq perturb 10


Как запретить пользователям качать большие файлы
— Собираем поддержку connbytes в patch-o-matic.
— Добавляем правило в firewall, например:

iptables -A FORWARD --connbytes 100000 -j REJECT

— теперь все TCP сессии более 100 Кбайт будут «обрезаны», необходимо добавить исключения для протоколов типа ssh, обычные «долгоживущие» чаты и т.п.

Борьба с Kazaa и прочим вредным трафиком путем вырезания пакетов по маске

— собираем поддержку «string» в patch-o-matic.
— смотрим на протокол Kazaa, в заголовках содержится:

HTTP/1.0 503 Service Unavailable.Retry-After: 3..X-Kazaa-Username: BlazeTre

— добавляем в firewall строчку — iptables -A FORWARD -m string —string «X-Kazaa-» -j REJECT

Как в Linux перебросить соединение через NAT во внутреннюю сеть (1)

Первый путь — пробрасывание только порта:

1) iptables -t nat -A PREROUTING -p tcp -d EXT_R_IP --dport 10000 -j DNAT --to-destination LOCAL_IP:80
2) iptables -A FORWARD -i eth0 -d LOCAL_IP -p tcp --dport 22 -j ACCEPT

Второй вариант — выброс всей машины наружу (если есть свободные адреса):

1) ifconfig eth0:0 NEW_IP netmask NETMASK broadcast BROADCAST
2) route add NEW_IP gw GW netmask 0.0.0.0 metric 1 dev eth0:0
3) iptables -t nat -A PREROUTING -p tcp -d NEW_IP -j DNAT --to-destination LOCAL_IP
4) iptables -A FORWARD -i eth0 -d LOCAL_IP -j ACCEPT

Обозначения: EXT_R_IP — внешний IP роутера, LOCAL_IP — внутренний IP машины, которую хочешь выбросить NEW_IP — новый IP на который хочешь посадить машину, которая имеет локальный LOCAL_IP NETMASK, BROADCAST, GW — внешние netmask, broadcast и gateway


Пример настройки NAT с привязкой к IP под Linux

iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -d 0/0 -o eth0 -j SNAT --to-source 212.23.98.45

или (без привязки к IP)

ipchains -A forward -j MASQ -s 192.168.0.0/16 -d 0.0.0.0/0

или (через iproute2)

ip rule add from 10.0.1.0/24 nat 254.147.38.14

Другой способ трансляции адресов:<

iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -d 0/0 -j MASQUERADE


Как ограничить через iptables максимальное число одновременных соединений с одного IP.

# Максимум 10 одновременных соединений к 80 порту с одного IP
iptables -A INPUT-p tcp --dport 80 -m iplimit --iplimit-above 10 -j REJECT
# Блокируем на стадии SYN
iptables -I INPUT -p tcp --syn --dport 80 -j DROP -m iplimit --iplimit-above 10
# 20 соединений на сеть класса С
iptables -p tcp --dport 80 -m iplimit --iplimit-above 20 --iplimit-mask 24 -j REJECT


Как посмотреть статистику по PREROUTING цепочкам в iptables.
> Делаю: >

iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.22.33:3128 &gt;

По iptables -L ничего не показывается.
Используйте:

iptables -t nat -L


Как настроить пакетный фильтр для фильтрации по содержимому пакетов
Следующие правила блокируют прохождение пакетов, данные в которых содержат подстроку virus.exe и ведут лог пакетов с строкой secret внутри:

iptables -A INPUT -m string --string "secret" -j LOG --log-level info --log-prefix "SECRET"
iptables -I INPUT -j DROP -p tcp -s 0.0.0.0/0 -m string --string "virus.exe"
# Block Code Red
iptables -I INPUT -j DROP -p tcp -m string --string "cmd.exe"
# Block Nimda
iptables -I INPUT -j DROP -p tcp -m string --string "root.exe"
iptables -I INPUT -j DROP -p tcp -m string --string "default.ida"


Как настроить NAT (транслятор адресов) для нормальной работы с FTP и ICQ в Linux
iptables:

modprobe iptable_nat
modprobe ip_conntrack_ftp
modprobe ip_nat_ftp
modprobe ip_nat_irc

ipchains:

modprobe ip_masq_ftp
modprobe ip_masq_raudio
modprobe ip_masq_irc
modprobe ip_masq_icq


Можно ли отфильтровывать пакеты (вести лог) в зависимости от UID пользователя ?>
Для FreeBSD:

ipfw add count tcp from any to not 192.168.1.0/24 uid 231

uid user (или gid group) — под правило попадают все TCP или UDP пакеты посланный или принятые пользователем user (группой group).
В Linux в ядрах 2.4.x в iptables можно использовать модуль owner.

Ограничение трафика через iptables (1)

iptables --new-chain car
iptables --insert OUTPUT 1 -p tcp --destination-port 25 -o eth1 --jump car
iptables --append car -m limit --limit 20/sec --jump RETURN
iptables --append car --jump DROP

Источник

Удаление всех писем в почтовом ящике Exchange 2003

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

Это можно сделать несколькими способами.

1) Удалить почтовый ящик пользователя, затем снова создать его.

Но этот вариант не совсем удобен, если много пользователей.

2) Воспользоваться утилитой exmerge.

Скачать её можно тут

Почитать как ей воспользоваться можно тут

Если пользовательские почтовые ящики занимают значительный обьём, то Вы можете предварительно их почистить встроенными средствами Exchange.

Создайте новую политику в ESM (Exchange System Manager)

ESM -> Recipients -> Recipient Policies — Default Policy — new policy — mailbox managment settings

Настройте это правило. Применить его для необходимого сервера. И после этого воспользуйтесь exmerge.

Так же рекомендуется поставить на mailbox starge галку cyrcular logging и перезапустить службы Exchange, после чего снять эту галку и снова перезапустить службы.

Очистка сохраненных паролей на сетевые ресурсы в Windows

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

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

Однако вы можете изменить, или удалить сохраненные данные, и в этой заметке я покажу вам как это сделать:

    Нажмите Start>Control Panel.
    В панеле управления перейдите в категорию User Accounts (в XP) или User Accounts and Family Safety (в Vista), и потом нажмите User Accounts.
    В XP, нажмите на ваш аккаунт пользователя Windows и на следующем окне в левой панели настроек логина нажмите на ссылку Manage my network passwords. В Vista, нажмите ссылку Manage your network passwords. Вы увидите окно Сохранение имен пользователей и паролей.
    Если вы уже имеете сохраненные записи, вы увидите список компьютеров. Вы можете выбрать нужную запись и нажать кнопку Remove.
    Нажмите кнопку Add. В XP появится диалоговое окно Logon Information Properties, в Vista — Stored Credentials Properties (in Vista).
    В поле Server (в XP) или Log on to (Vista), введите имя компьютера в сети, к которому необходимо подключаться.
    В поле User name введите аккаунт пользователя, имеющий доступ к указанному компьютеру. Используйте запись в правильном формате, к примеру computernam\accoutname.
    В поле Password введите пароль для выбранного пользователя.
    В Vista нажмите A Windows logon credential.
    Нажмите OK.

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

Просмотр байтовых счетчиков трафика на интерфейсе во FreeBSD и Linux

По умолчанию «netstat -i» во FreeBSD показывает только число пакетов, чтобы посмотреть размер в байтах
нужно использовать опцию «-b», упоминание которой удалось найти после трех прочтений man страницы.

   netstat -inb

Для наглядного просмотра, можно использовать опцию «-h», которая сокращает байтовый вывод до Кб, Мб или Гб.

   netstat -inbh

Интенсивность передачи трафика удобно просматривать через:

   systat -ifstat

или

   netstat -iw1

Для просмотра интенсивности передачи трафика в Linux удобно использовать команду ifstat

В Linux байтовые счетчики интерфейсов можно просмотреть через:

   cat /proc/net/dev

Другую полезную статистику по работе сетевой подсистемы можно найти в файлах /proc/net/ip_conntrack, /proc/net/stat/rt_cache, и /proc/net/stat/arp_cache.