Правила съема жилья: Метод Трудом.РФ

Друзья! На связи снова Трудом.РФ, сайт по распознаванию частных объявлений и выявлению посредников при аренде жилья. В этом посте я расскажу что у нашей системы под капотом.

146979500018261205

Мы ставим перед собой цель упростить процесс аренды для честных квартиросъемщиков и максимально защитить их от рисков и лишних переплат, как когда-то защитили себя и своих друзей, а всё что из этого получится зависит от Вас, друзья…

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

Раз: Снять квартиру без посредников своим трудом

Два: Как обманывают на досках объявлений

Поехали!

Как в первом приближении выглядит задача по определению частных объявлений – получаем с некоторой периодичностью новые объявления с ресурса, получение их номеров и сравнение с тем, что есть в базе. Кажется, что все довольно просто, однако, как обычно дьявол кроется в деталях. Возникает множество проблем и нюансов. Вот некоторые из них:

  1. Ресурсы ограничивают число запросов к ним. Если производить запрос слишком часто, Авито в первый раз банит на 15 минут, второй раз на час, и т.д.
  2. Объявлений очень много. Только с одного Авито по Москве в день публикуется более 4000 объявлений, с ЦИАН – более 3000 объявлений. Надо уметь их быстро обрабатывать.
  3. Для получения номера телефона, требуются дополнительные действия – сымитировать нажатие на кнопку/распознать картинку и т.п.
  4. Фильтрации только по номеру не хватает – мошенники и риелторы далеко не дураки и используют огромное количество симок и также специальные сервисы.
  5. Как правило, объявления, которые являются заведомо мошенническими, все равно появляются в выдаче, несмотря на модерацию. Однако, модератор может заблокировать объявление потом.
  6. Хорошие предложения уходят быстро, и их так же быстро надо удалять из своей базы.

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

Во время учебы в институте, у нас как минимум раз в год, проводилась конференция компании Microsoft, на которой они рассказывали о своих новых технологиях (помню времена, когда они пиарили покойные ныне Silverlight и XNA). Тогда же давали доступ к программе DreamSpark. По данной программе студентам российских вузов предоставляется доступ к лицензионному ПО (в наше время это были Windows Server 2008R2, SQL Server 2008, Visual Studio 2010 Professional) при условии использования его в образовательных целях. Данная программа доступна абсолютно всем российским студентам. В некоторых ВУЗах (например в нашем МАИ) была доступна расширенная программа – MSDN Academic Alliance. В ней список ПО гораздо шире.

Всё в Ажуре!

Так сложилась, что в мир .NET нас затянули не эти конференции, а первые места работы. Да и в самих конференциях мы особо не участвовали. Когда встал вопрос о выборе стека и архитектуры, я вспомнил про еще одну программу Microsoft – BizSpark. Эта программа для стартапов и малого бизнеса. Требования к компании минимальны – даже не требуется юридической регистрации. В программы предоставляется доступ к огромному количеству лицензионного ПО, а также 5 подписок по 150$ на их облачный сервис Azure(в своей среде мы называем его просто ажур). Вообще, рассказ про программы тянет на отдельный пост. Мы подали заявку и в течение недели нам ее утвердили и предоставили все данные.

Таким образом, мы получаем 750$ (5 подписок по 150$) в месяц на хостинг. Программа действует 3 года, то есть в общей сумме Microsoft за все время участия в программе подсобит нам примерно 27 000$

1469795703110331074

На самом деле не всё так как может показаться на первый взгляд. Дело в том, что выделяемый бюджет можно тратить лишь на продукты и услуги самих Microsoft и, естественно, нельзя обналичить или, например, вложить в рекламу или в сторонние сервисы.

1469795726166767713

Плюс у нас есть два не самых новых компа в качестве серверов в нашем маленьком ДЦ в квартире. Сейчас на них выполняются в основном служебные задачи.

Сервера по-домашнему и исходный кот проекта)

1469795774171697202

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

Общая структура

Система была разбита на несколько компонентов (сервисов):

1. Spider (паук) – краулер. Этот компнонент занимается тем, что получает страницу результатов поиска доски объявлений и из нее выделяет отдельные объявления. Он довольно простой – его задача просто получить ссылку на объявление и базовые данные – тип объявления (посуточная/длительная аренда), количество комнат, адрес. Получив ссылку, он отправляет ее дальше.

2. Scanner (сканер) – задача компонента открыть страницу одного объявления и вытащить максимум информации об объявлении – описание, фотографии, номер телефона, условия проживания, этаж и т.п.

3. OCR – веб-сервис, который распознает номер телефона с картинки и возвращает текст

4. Processor – центральный компонент. Сначала он получается данные от паука. Проверяет, публиковалось ли это объявление ранее или нет. Если объявление не публиковалось – он передает его сканеру, для получения полных данных. После того как сканер обработал объявления, проводится геокодирование (по адресу получает координаты дома), получаются ближайшие станции метро, анализируется цена объявления, проверяется есть ли у человека другие публикации, проверяется реальные ли данные указаны в информации о доме, проводится лексический анализ объявления. После выполнения всех действий, объявление добавляется в базу. И становится в очередь на периодическую проверку (пингования).

5. Pinger (пингер) — задача этого компонента проверять, доступно ли еще объявление. Он с некоторой периодичностью загружает страницу объявления и проводит анализ ответа. Если объявление было заблокировано модератором доски – перед нами мошенник и его номер идет в черный список. Если объявление было удалено, оно просто отмечается как удаленное в базе.

6. SMMTracker – маленький сервис который обеспечивает интеграцию с социальными сетями. У нас есть такая фишка на сайте – доступ за репост во Вконтакте. Т.е. человек, который не знает кодового слова, может просто поделиться записью из нашей группы, и он сможет использовать ссылку на свой профиль в качестве кодового слова. Задача этого компонента отследить новые репосты и добавить кодовое слово в базу.

Как видите, у нас много компонентов, и их надо как-то связать. Мы используем два способа связи – очереди и веб-сервисы. OCR-сервис является веб-сервисом, остальные компоненты общаются через очереди.

“В очередь, сукины дети, в очередь!”.

1469795936181078584

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

  1. Spider получает список документов и добавляет их в очередь «documents»
  2. Scanner читает очередь «scan-request», получает подробный документ и отправляет результат в «scan-result»
  3. Pinger читает из очереди «ping-request», результат добавляет в «ping-result».
  4. Processor читает очереди «documents», «scan-result», «ping-result»:
    1. В очереди «documents» находятся документы от паука. Если документ надо отправить на сканирование – добавляет его в очередь «scan-request».
    2. В очереди «scan-result» находятся результаты сканирования
    3. В очереди «ping-result» находятся результаты проверки существования документа. Если документ все еще существует, он добавляется снова в «ping-request»

Как же обеспечиваются отказоустойчивость и распределенность?

1. Мы используем сервис очередей, который предоставляет Azure. Это сервис достаточно дешевый, но при этом очень надежный – данные в очереди несколько раз резервируются и хранятся одновременно в различных дата-центрах.

2. Каждый сервис запущен в нескольких экземплярах (как минимум в двух), на разных серверах. Если один сервер выходит из строя – нагрузка ложится на остальные. Такая же ситуация, если сервер начинают банить.

3. Мы можем довольно просто регулировать нагрузку – если в очередях скапливается много документов, мы просто устанавливаем копию еще одного сервиса (это все равно, что открыть дополнительные кассы в магазине)

4. У нас настроено централизованное логирование, и мы быстро узнаем, когда что-то идет не так.

Технологии, которые мы используем.

Все сервисы у нас сделаны в виде служб Windows.

В качестве основного хранилища мы используем ElasticSearch. Выбор на такое решение пал по нескольким причинам – отказоусточивость, масштабируемость, распеределенность и скорость. Именно в это хранилище пишутся все найденные объявления. Также там хранится сопутствующая информация – станции метро, статистика цен и прочее. К сожалению, ничего не бывает бесплатно, и у ElasticSearch есть свои ограничения – например, при добавлении объявления, в поиске оно появляется не сразу, а через некоторое время (10-300мс), дорогие операции обновления документа. Поэтому, для некоторых утилитарных задач мы используем MongoDB.

Для сайта мы используем ASP.NET MVC и React. Если ASP.NET MVC – это уже стандарт в мире .NET, то React только-только завоевывает сердца .NET разработчиков. Выбор на React пал во многом из-за возможности Server-Side рендеринга (грубо говоря на сервере как Razor, только React) и скорости работы.

Для централизированного логирования, мы используем ELK (ElasticSearch, Logstash, Kibana) стек. Это довольно стандартное решение для таких задач. Мы можем быстро отслеживать ошибки и важные информационные сообщения.

Автоматизация обновлений.

1469796227186222082

Самое сложное в такой распределенной системе – это развертывание новых версий. Согласитесь, довольно неудобно вручную обновлять хотя бы один сервис на трех-четырех серверах. А обновлять сервисы иногда приходится довольно часто. В мире Linux есть Ansible, Docker и много других систем, позволяющих осуществлять автоматическое развертывание на многих серверах. Для .NET вариантов совсем мало. Но мы пока остановились на бесплатной версии Octopus-Deploy. Эта штука решила всю головную боль с развертыванием – теперь чтобы обновить версию, достаточно нажать буквально пару кнопок.

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

Удачных поисков!