package main
// Билеты по Проектированию Высоконагруженных систем
/*
Высокая нагрузка это что? Простой метод посчитать RPS - request per second 10 RPS много или мало? 1000 RPS много или мало? Ответ: "Это зависит"
High load наступает, когда мы не справляемся с нагрузкой. (это сильно зависит от требований пользователя и задачи)
TODO: ?? А что тут надо еще
Как готовиться к High Load?
- Хорошо понимать задачу
- Дизайн (архитекутра) - система должна масштабироваться
- Мониторинг - система должна быть наблюдаема
- Знать свои технологии / инструменты (+ алгосы и структуры данных)
Как не готовиться?
- Преждевременные оптимизации (Возможно тратим время просто так, часто портят архитектуру, оптимизированный код иногда выглядит ужасно)
TODO: ??? Добавить еще
Требования к системе. Короткими и ясными фразами. На естественном языке.
A user story is an informal, general explanation of a software feature written from the perspective of the end user. Its purpose is to articulate how a software feature will provide value to the customer.
- Stories keep the focus on the user. (a collection of stories keeps the team focused on solving problems for real users.)
- Stories enable collaboration. (With the end goal defined, the team can work together to decide how best to serve the user)
- Stories drive creative solutions.
- Stories create momentum. (With each passing story the development team enjoys a small challenges and a small win)
“As a [persona], I [want to], [so that].”
API - Application Programming Interface Хотим сделать взаимодействие между различными частями. Нужен протокол/интерфейс. Нам нужна абстракция, например мы не хотим знать детали монитора, но хотим уметь с ним взаимодействовавать Кроме этого, разграничиваем части системы, создав интерфейс.
Wiki: "It defines the kinds of calls or requests that can be made, how to make them, the data formats that should be used, the conventions to follow, etc. It can also provide extension mechanisms so that users can extend existing functionality in various ways and to varying degrees"
Виды API:
- Библиотеки, фреймворки
- Application Binary Interface (в такой-то кусок памяти положи то то)
- Remote (RPC, REST, JSON-API, взаимодействие удаленных узлов)
- Таблицы, структуры данных
- Очереди, шины
Remote Procedure Call - вызов процедуры.
Remote procedure call (RPC) is when a computer program causes a procedure (subroutine) to execute in a different address space (commonly on another computer on a shared network), which is coded as if it were a normal (local) procedure call, without the programmer explicitly coding the details for the remote interaction.
RPC is a request–response protocol. An RPC is initiated by the client, which sends a request message to a known remote server to execute a specified procedure with supplied parameters. The remote server sends a response to the client, and the application continues its process.
Адресуем методы. Не говорим про объекты, структуры, сущности.
Какие бывают?
- SOAP (сообщения в формате XML, объекты которые мы передаем в рамках протокола должны соотв. схеме)
- JSON-RPC, XML-RPC (простые схемы)
- gRPC (google RPC)
- очень много других
- использует любой транспорт
- сообщения - JSON объекты с определенной схемой
- использует систему типов JSON
Пример запроса
{
"jsonrpc": "2.0", // версия протокола
"method": "substract",
"params": [42, 43],
"id": 1 // id запроса, будет копирован в ответ
}
Пример ответа
{
"jsonrpc": "2.0",
"result": 19, // вместо result может быть error с кодом и сообщением ошибки
"id": 1
}
Используется в очень примитивных ситуациях, плохая поддержка в Go
- Протокол
- Фреймворк для разных языков и платформ (есть набор инструментов)
- Бинарная сериализация
- Транспорт: HTTP/2
- Поддерживает двунаправленные потоки (можно не диалог, а монолог, просто стримить сообщения)
- Определяем протокол (*.proto file)
- Генерируем код клиента и сервера
- Реализуем сервер и клиент
Пример proto файла:
syntax = "proto3";
option go_package = "github.com/mp-hl-2021/grpc-example/ api";
package echo;
service Echo {
rpc Do(EchoRequest) returns (EchoReply) {}
}
message EchoRequest {
string line = 1;
int32 num = 2;
}
message EchoReply {
string echo_line = 1;
}
Генерируем код
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative api/echo.proto
Нам сгенерируют интерфейсы и методы заглушки, нужно их реализовать
Representational State Transfer
Архитектурный стиль, в котором клиент state machine, а сервер движок текстовых квестов (вы в такой-то комнате, у вас дверь на север, на юг, куда кликните? и т.д)
REST как набор ограничений:
- Separation of Client and Server (имплементации сервера и клиента могут не знать о друг друге, пока каждая сторона понимает формат общения, они могут изменяться независимо)
- Statelessness (Сервер не должен знать ничего о состоянии клиента и наоборот, таким образом клиент и сервер могут воспринимать любые получаемые сообщения, даже без истории взаимодействия до)
- Cacheable (Данные в запросах и ответах могут быть помечены как кешируемые, стороны могут использовать те же данные при дальнейших запросах, не обновляя их)
- Uniform interface
(
- Identification of resources; (for example with URLs)
- manipulation of resources through representations; (имея ресурс representation of a resource клиенту хватает информации чтобы модифицировать или удалить его)
- Self-descriptive messages (Каждое сообщение содержит достаточно информации, чтобы его обработать)
- Hypermerdia as the engine of application state)
- Layered system (Разделяем приложение на слои, ограничиваем каждую компоненту в взаимодействии: разрешаем только с компонентами ее слоя)
TODO: Недостатки REST? Он вообще ничего не сказал
HTTP - HyperText Transfer Protocol (уровень общения application)
HyperText and HyperMedia - к какждому нашему медиа (текст, картинки) добавляем перекрестные ссылки, каждый ресурс получает идентификатор и мы можем использовать их внутри наших дкументов, чтобы ссылаться на другие ресурсы, ссылки могут быть нелинейные.
HTTP Model - все представляется в виде ресурсов, к каждому ресурсу можно получить доступ по URL (Uniform Resource Location)
Пример https://example.com:80/examples/1#test
Примерная грамматика URL: scheme://[userinfo@]host[:port]/path[?query][#fragment]
HTTP: Запрос
- Метод (глагол)
- Положение ресурса
- Заголовки
- Тело
Методы:
- GET (получить предстваление ресурса)
- HEAD - как GET но не возвращает тело (например метаданные взять из заголовка, когда ресурс обновился)
- POST - передает серверу "нечто" в подчинение какому-то ресурсу (ресурсу по URL)
- PUT - сохранить "нечто" с доступом по указанному URI
- DELETE - удалить ресурс
- etc
HTTP: ответ
- Статус (некий код)
- Заголовок
- Тело
Статус коды:
Informational responses (100–199) Successful responses (200–299) Redirects (300–399) Client errors (400–499) Server errors (500–599)
HTTPS: HTTP over TLS (secured TCP), Алиса и Боб используют асимметричное шифрование (Открытый, приватный ключ у Алисы, но еще нужно подписывать сообщения у сторонних сервисов, которым все доверяют) Мы как владельцы домена приходим к Certification Authority, один раз валидируем свою личность, получаем подпись и кладем ее в конфиг сервера, теперь нам можно доверять (ну типа)
Аутентификация - процесс, при котором система удостоверяется, что нечто является подлинным
- ID соответствует пользователю
- Сайт настоящий, а не поддельный
Авторизация - подтверждения права получить доступ к ресурсу. (и если есть доступ, то какой)
9. Аутентификация в Web. Basic HTTP Authentication. Form-based authentication. Cookies. JSON Web Token
(через HTTP заголовок) Клиент:
Authorization: Basic <credentials>
credentials := BASE64(id:password)
Authorization: Basic AkkBkerCdlaFASff6Adssf66a6f6jg891921bBbasdgvbadsC
Сервер (если не авторизован)
401 Unauthorized
WWW-Authenticate: Basic realm="User Visible Realm" // отвечает на что авторизация
Такой подход незащищенный, заголовки не шифруются, легко представится пользователем
- Формочка, в нее записываем логин пароль
- После этого например это в javascript записывается в json, отправляется POST запросом на сервер
- Сервер валидирует данные этой формы, возвращает токен Надо как-то хранить токен, чтобы каждый раз не пришлось вводить логин-пароль Два варианта, про которые сказал Никита:
- Cookies
- Bearer Authentication
Механизм хранения состояния на стороне клиента
- Аутентификация
- Корзина товаров (так стараются не делать)
- Персональные предпочтнения (темная тема)
- Слежка за пользователями (third party cookies, я так понял это хотят забанить)
Чтобы выставить Cookies сервер возвращает заголовки
Set-Cookie: theme=light
Set-Cookie: sessionToken=6dasdgafasdsa; Expires=Wed, 09 Jun 2021 10:18:14 GMT
В следующий раз мы (client) уже в заголовке посылаем
Cookie: theme=light; sessionToken=6dasdgafasdsa
Виды HTTP Cookie:
- Session (удаляются после закрытия браузера)
- Persistent (удаляются с течением времени, хранятся внутри браузера)
- Secure (работают только по HTTPS)
- Same-site (Отправлять куки только в рамках домена, защищает от Cross Site Scripting) TODO: XSS
- Third-party (Куки, установленные с других доменов)
- HTTP-Only (Недоступно из клиентского JS)
- ...
В Go для работы с куки есть http.Cookie
Cookie опасны! (XSS)
- Требуйте HTTPS (secure cookies)
- Помните, что на клиенте тоже могут подменить куки (сервер не должен всегда доверять содержимому куки, если мы хотим обезопасить себя, нужно хранить состояние клиента, в реальности корзину мы храним на сервере, session_id храним на сервере, и т.д в итоге от REST много где нам придется отказаться =((( )
- Устанавливайте Domain
JWT, джот - кусок данных в формате JSON, использует подпись и/или шифрование Сервер вместе с джотом генерирует подпись, по которой может проверить, что JSON был сгенерирован им Обычно содержит информацию о правах доступа.
Обычно кодируют публичным и приватным ключом, приватный оставляют только у сервера.
В Go это все делает либой rsa и с помощью openssl.
JWT не средство шифрования! Токен подписан, но любой сторонний сервис может узнать содержимое
Пример: Создать аккаунт с помощью Apple/Facebook/Google/Microsoft
- Resource Owner (конечный пользователь, ресурс - мой акк в гугле)
- Resource Server (хранит ресурсы, гугл)
- Client (сторонее приложение, сокращатель ссылок)
- Authorization Server - выдает клиенту токены, которые разрешают от имени RO получить доступ к ресурсам на RS
гугл = Resource Server
Client запрашивает разрешение у RO на авторизацию через гугл
RO выдает разрешение Client
Client показывает разрешение Authorization Server
Authorization Server выдает Client Access Token
Client показывает гугл Access Token
гугл выдает protected resource Client-у
Обновление токена:
Обычно вместе с Access Token выдается Refresh Token, Access Token работает какое-то время, используя Refresh Token Client может обновить Access Token
- Не храните пароли в открытом виде
- Проверяйте сложность, валидируйте
- Не изобретайте свои алгоритмы !!!
- Защищайтесь от перебора
- Подумайте о возможных уязвимостях (модель угроз)
Как хранить пароли?
- В открытом виде (базу точно украдут и все пароли утекут)
- Криптографические хеш функции (из байтов делаем мусор, функция необратима) (В базу сохраняем хэши паролей) (возможен перебор по таблицам паролей - хешей, радужные таблицы)
- Добавляем соль к паролю (добавляем какую-то строку ко всем паролям и после считаем хеш) (сложно строить таблицы, но можно узнать соль)
- Рандомизируем соль
- Добавляем раунды хеширования
- Не пишем ничего из этого, используем
bcrypt
- Стремительно набирает популярность в серверной разработке
- Хорошо иметь еще один инструмент в запасе (кроме петона)
- Го простой язык, легко перейти с Java/C++/C
- Документация Go, число деталей, намного меньше, чем у тех же C++/Java
- Go стремится к простоте и единообразию (хочется всего один способ сделать вещь правильно)
- Компилируется в нативный код (лучше чем JavaScript)
- Автоматическое управление памятью (лучше чем C/C++)
- Удобная поддержка конкуретного программирования (на уровне синтаксиса, в отличие от C++/Java) (в питоне есть async/await, но во-первых, у него нет своего планировщика, во-вторых, заражает весь остальной код, короче неудобно)
- Много инфраструктурного кода написано на Go (docker, kubernetes, etc)
go is not good:
- too simple / lack of sugar
- no generics
- bad dependency management
- stuck in 70/80s
- error handling
- no unused imports
- too opinionated
- too verbose
- no ternary operator
- no macros or templates
Go's 21st Century Characteristics
- Concurrency (C++ at Google was awful with concurrency)
- Distributed Systems
- Garbage Collection
- Memory Locality
- Readability
Пакеты в Go - набор файликов, которые делят область видимости типов и переменных
package main - точка входа */