Git Product home page Git Product logo

vk-internship's Introduction

VK Web Chat

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

Как запускать

Этот проект тестировался и запускался на 11 и 16 Java.

Для запуска клиента ./gradlew runFrontend

Для запуска сервера ./gradlew runBackend

Зависимости

В ТЗ было сказано использовать как можно меньше зависимостей. Я это расценил как то что проверяющему хочется оценить более фундаментальные знания нежели чем знания библиотек. По этой причине я притащил в проект только две библиотеки.

  • Gson - все общение клиент-сервер у меня происходит именно через JSON. Json хорошо себя показывает в случае когда нужно соблюдать обратную совместимость. Например, добавить какое-то новое поле в респонс. Что позитивно сказывается на обратной совместимости. Есть конечно бинарные протоколы, но кажется, что они не так хорошо прижились в этом мире, что плохо скажется на адаптации проекта в случае если придется открывать апи.
  • Jetty - http server. Использование HTTP протокола кажется отличным решением из-за того что мы сразу же бесплатно можем использовать все штуки для него придуманные. HTTP прокси, https и прочее.

Больше зависимостей нет. Только в тестах.

Архитектура

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

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

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

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

Строгая типизация API

Что сделано

В моей реализации каждый endpoint описывается через вот такую конструкцию:

    public static final Endpoint<UserPasswordRequest, SessionResponse> SIGN_UP_REQUEST_ENDPOINT
            = new Endpoint<>("signup", UserPasswordRequest.class, SessionResponse.class);

На сервере создается сервлет с путем signup, который принимает UserPasswordRequest и возвращает SessionResponse

После чего запросы выглядят вот так красиво

        HttpClient client = connect();
        var response = client.sendRequest(
                Endpoint.SIGN_UP_REQUEST_ENDPOINT,
                new UserPasswordRequest(username, password)
        );
        SessionResponse session = assertSuccess(response.response());
        validateResponse(session);

В итоге у нас получается, что компилятор сам за нас проверят, что мы правильно общаемся с сервером.

Зачем

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

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

Защита от DDoS

Что сделано

Сделан бан ip при большом количестве запросов с него за определенный промежуток времени. Реализовано это при помощи скользящего окна и аналога капчи. Я посчитал не очень нужным реализовывать настоящую капчу с картинками потому я просто шлю текстом математическую задачку.

Зачем

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

В общем, кажется, что вот такая простая защита от дудоса является очевидно необходимой

Long Poll

Что сделано

Реализован сервер на стеке TCP/IP. Реализация написана на Java NIO, то есть не использует блокирующее IO.

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

Зачем

Прежде всего для реализации чата в реальном времени нам нужно как то доставлять клиенту информацию о новых сообщениях ASAP. Так как мы не можем напрямую отправить клиенту, например, UDP пакет при получении нового сообщения из-за NAT, нам нужно, что бы клиент сам открывал к нам подключение. Так как мы не можем делать каждый раз HTTP запрос потому что это сначала TCP handshake, а потом еще и HTTP хэдер. И не то что бы очень хотим каждый раз открывать TCP подключение потому что handshake это уже достаточно больно. Решением является держать одно подключение постоянно.

Так как по большей части подключение будет простаивать использование потока на каждое подключение кажется очень избыточным в плане ЦПУ и ОЗУ, а потому non-blocking IO.

Статическая типизация LongPoll не менее важна чем типизация Rest API

DB Connections Pool

Что сделано

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

Зачем

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

Ограничение на кол-во запрашиваемых сообщений

Что сделано

Запрос сообщений не выдает слайс сообщений с лимитом в 100 штук и с задаваемым смещением по времени.

Зачем

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

Что можно добавить

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

Уменьшить кол-во запросов от пользователя

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

Сменить базу данных с SQLite

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

Поднять несколько инстансов сервиса с лоад балансером

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

Поднять фаерволл

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

Кажется задача, которую тоже относительно неплохо решили.

Сделать веб сокет в Long Poll

Для настоящего веб чата это все таки необходимое условие. Мне не захотелось реализовывать его ручками, а тащить либы читерство потому это в хотелках.

Сделать гораздо больше интеграционных тестов

Ну вот не хватило на них времени да

vk-internship's People

Contributors

justagod1 avatar

Stargazers

Evgeny Bykovskikh avatar Ivan Rozhnovskiy avatar

Watchers

James Cloos avatar  avatar

vk-internship's Issues

issue

Привет, несколько проблем:

  1. Очень неюзабельный ui, зачем нужно пространство наверху для логина, когда я уже залогинен?

image

у меня есть диалог с самим собой, куда я на самом деле ничего не писал, но там почему-то есть сообщение, которое я отправлял с oleg2 на oleg
  1. После отправления сообщения с oleg2 на oleg, в oleg я ничего не видел пока не реконектнулся.

Это необходимо поправить до собеседования.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.