Pull to refresh

Comments 31

в конечном виде в формате MatchSpec, для NowStamp=1000, Timeout=0 выглядит как

[{{'_','_','_','$1'},[{'<','$1',{'-',1000,0}}],[true]}]


Oh, shii…
Самый «shii» что fun2ms реализована через parse_transform и это самый fun нельзя более нигде определить.
Да на самом деле не сложно, но в скобочках путаешься)
Читается как «Вернуть true для каждой записи в таблице, у которой последний элемент меньше -1000»
Я просто уже несколько раз пытаюсь начать изучать erlang, но как только вижу такое, то сразу же это желание улетучивается :)
Такое, как видите, не обязательно писать руками. Зачастую ужасный код пишут программисты, а не навязывают языки программирования.
Не лучше ли ограничивать интенсивность запросов с помошью веб-сервера?
В простейшем случае, возможно, лучше.
Но если, например, Вы хотите ограничивать скорость избирательно, Вам потребуются данные из приложения.

Кроме того, описанное приложение выполняет общую задачу. С его помощью можно ограничивать скорость обслуживания чего угодно.
Я смотрел Mochiweb, Yaws и Webmachine

Последняя мне показалась слишком сложной (навороченной) по функционалу. Ну и Webmachine — это просто надстройка над Mochiweb.
Yaws не понравился на начальном этапе, поэтому дальше не смотрел.

Если есть другие достойные альтернативы — говорите.
UFO just landed and posted this here
Спасибо за наводку, обязательно посмотрю!
А он умеет все что умеет Mochiweb? Никаких подводных камней?
UFO just landed and posted this here
Спасибо, но ведь Вы по какой-то причине используете именно его, а не Mochiweb?

По README они вроде все хороши, но под нагрузкой, и в условиях (аврала) | ( истерики (руководства)|(инвесторов)) проявляются различные особенности.
Есть несколько вопросов по коду.
1) Зачем ordered_set? + Зачем Вы имя именованной ets загоняете еще в макрос?
2) В чем был смысл оформления алгоритма в виде отдельного приложения?
Эрланг я только осваиваю и некоторые вещи делаю по наитию или по подобию в других языках.

1) Имя таблицы в макросе — чтобы при необходимости его было можно быстро поменять в одном месте.
1) ordered_set — уникальные ключи + быстрый поиск. Возможно я не знаю лучшего варианта, подскажите
2) Для того, чтобы не заморачивать клиента созданием таблиц и супервизорством над процессом. Также для того, чтобы разобраться с созданием приложений. Как мне видится, менять настройки в конфиге для отдельного приложения тоже проще. Принципиальной непреодолимой причины не было.
ИМХО, всё правильно сделал. Разве что ordered_set не очень понятно оправдан ли. Он нужен только если нужно получать отсортированные выборки. Для уникальных ключей подойдет и просто set.
Мне кажется, что быстрый поиск тут менее важен, чем медленная вставка.
Тем более где у Вас поиск по ключу? При set вставка будет за константное время (из документации, по тестам не совсем), для ordered_set за логарифмическое. На больших объемах данных становится очень заметно.

+ со временем при больших таблицах могут возникнуть проблемы для remove_old_limiters/0. ets:select_delete, да и все ets:select* выполняются атомарно. До тех пока поиск не произведется никакие управление другому потоку передано не будет. Возможно, имеет смысл посмотреть в сторону ets:first() ets:next(). Удаление происходит реже чем вставка, потому мне кажется, можно в отдельном потоке обходитьь и всю таблицу. Но для реальных условий надо тестировать.

+ мне кажется для реальных условий совсем не помешает иметь пул таких приложений, но с одной ets. Для создания пула можно воспользоваться github.com/devinus/poolboy.

poolboy уже на заметке, Ваш комментарий — лишний балл в его пользу.

По поводу типа таблицы — еще проведу эксперименты, как будет время. По идее, в текущей реализации таблица может серьезно вырасти только при огромном числе одновременных пользователей. Что уже само по себе может быть проблемой :)
А не будет проблем при использовании нескольких машин? Как быть с распределённостью?
Я сам пока не имел удовольствия писать распределенные приложения.
Тем не менее, если запускать raterlimiter на каждой ноде, я не вижу проблем.
Я имею в виду ситуацию, когда при первом заходе данные пользователя пишутся в одну корзину на одной машине, а при последующем запросе — уже во вторую на другой.
В такой ситуации нужно либо держать rate_limiter только на одной машине (просто), либо шардить ETS таблицу по IP адресу (немного сложнее). Ну и использовать rpc модуль если клиент пришел на одну ноду а его rate_limiter на другой. В общем, в Erlang это не большая проблема по сути — строк на 100-200 кода.
Но может добавить latency.

В книжке «OTP In action» похожая система описана, кстати.
Есть ли смысл в этом случае использовать Mnesia? Будет ли какой-то профит? И появятся ли новые проблемы?
Mnesia — проблемы будут. Она выгодна, когда чтений значительно больше чем записей. Да и тормозит она. Но по-моему все равно все сведется к тому же.
Проблемы будут на хороших нагрузках. Но, возможно, на реально хороших нагрузках лучше писать ограничитель как модуль для ядра.
А как в этом случае с автоматическим балансингом? Мы ведь его нарушим? Шардинг должен получиться равнозначный по нагрузке, чтобы этого не случилось. Если представить DDOS, который будет попадать только на один шард, то он ведь перегрузит ноду.
Да, я понимаю.
Если у Вас N машин, и клиент равновероятно попадает на любую из них — можно просто понизить лимит в N раз на каждой машине :)
и, по закону подлости… клиент 3 раза обработается на одной и той же машине…
Законы подлости тут уже не при чем. Тут статистика и настройки, которые делаете именно Вы.
Не будет ли блокировок, если много процессов будут писать/читать ETS сразу?
dirty_read? Будут потери, но тут это не сильно важно.
Sign up to leave a comment.

Articles