From a2c07bd2dca9a9b184a01073fa7cc1077846e3c6 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 6 Apr 2026 16:37:26 +0000 Subject: [PATCH] add new posts --- .gitmodules | 3 + .hugo_build.lock | 0 Dockerfile | 13 ++ archetypes/default.md | 6 + config.toml | 33 +++ content/posts/_index.md | 4 + content/posts/clean-arch.md | 27 +++ content/posts/gRPS.md | 281 +++++++++++++++++++++++++ content/projects/GLIPH.md | 1 + content/projects/HSE.md | 1 + docker-compose.yml | 7 + layouts/partials/google_analytics.html | 0 themes/PaperMod | 1 + 13 files changed, 377 insertions(+) create mode 100644 .gitmodules create mode 100644 .hugo_build.lock create mode 100644 Dockerfile create mode 100644 archetypes/default.md create mode 100644 config.toml create mode 100644 content/posts/_index.md create mode 100644 content/posts/clean-arch.md create mode 100644 content/posts/gRPS.md create mode 100644 content/projects/GLIPH.md create mode 100644 content/projects/HSE.md create mode 100644 docker-compose.yml create mode 100644 layouts/partials/google_analytics.html create mode 160000 themes/PaperMod diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..89af1b0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "themes/PaperMod"] + path = themes/PaperMod + url = https://github.com/adityatelange/hugo-PaperMod.git diff --git a/.hugo_build.lock b/.hugo_build.lock new file mode 100644 index 0000000..e69de29 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a2f46fe --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +# Используем официальный и актуальный образ Hugo +FROM hugomods/hugo:latest AS builder + +WORKDIR /src +COPY . . + +# Сборка статики +RUN hugo --minify + +# ЭТАП 2: Раздача через Nginx +FROM nginx:alpine +COPY --from=builder /src/public /usr/share/nginx/html +EXPOSE 80 diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..00e77bd --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..21306f2 --- /dev/null +++ b/config.toml @@ -0,0 +1,33 @@ +baseURL = 'https://returntozer0.ru' +languageCode = 'ru' +title = 'returntozer0.ru' +theme = 'PaperMod' + +[params] + env = 'production' + description = 'Software Developer | Founder of GLIPH' + author = 'Микаэл Оганесян' + ShowCodeCopyButtons = true + ShowShareButtons = true + ShowReadingTime = true + ShowToc = true + TocOpen = true + [params.profileMode] + enabled = true + title = 'Микаэл Оганесян' + subtitle = 'Software Developer • GLIPH Founder' + imageUrl = 'https://github.com/mikaeloganesian.png' + imageWidth = 160 + imageHeight = 160 + buttons = [ + { name = 'Проекты', url = '/projects' }, + { name = 'Статьи', url = '/posts' }, + { name = 'Gitea', url = 'https://git.returntozer0.ru' } + ] + + [[params.socialIcons]] + name = 'github' + url = 'https:/github.com/mikaeloganesian' + [[params.socialIcons]] + name = 'telegram' + url = 'https://t.me/returntozer0' diff --git a/content/posts/_index.md b/content/posts/_index.md new file mode 100644 index 0000000..02da2fd --- /dev/null +++ b/content/posts/_index.md @@ -0,0 +1,4 @@ +--- +title: "Статьи" +description: "Заметки об IT-индустрии и то, что лично мне кажется интересным" +--- diff --git a/content/posts/clean-arch.md b/content/posts/clean-arch.md new file mode 100644 index 0000000..3034560 --- /dev/null +++ b/content/posts/clean-arch.md @@ -0,0 +1,27 @@ +--- +title: "Иерархия каталогов в Linux" +tags: ["linux", "файловые системы"] +categories: ["tech"] +--- + +В Linux все дерево начинается с корня - `/`. Каждая директория имеет свое строгое назначение: + +### Системные и исполняемые файлы +- `/bin` и `/sbin` - содержат основные программы, необходимые для работы системы и ее восстановления. В `/sbin` лежат команды, предназначенные для системного администратора. +- `/usr` - может показаться, что является сокращением от user, однако на самом деле является аббривеатурой **Unix System Resources** - вторичная иерархия. Здесь хранятся пользовательские программы, библиотеки и документация. Современные дистрибутивы часто делают `/bin` ссылкой на `/usr/bin` +- `/lib`, '/lib64' - системные библиотеки, которые нужны программам из `/bin` и `/sbin` для запуска. + +### Настройки и переменные данные +- `/etc` - здесь хранятся **конфигурационные файлы** всей системы. +- `/var` - сокращение от **Variable**. Директория для файлов, которые часто меняются. К таким, например, относятся логи (которые, кстати, находятся по пути `/var/log`), базы данных, временные файлы печати и тд. +- `/tmp` - временные файлы. Важно помнить, что во многих системах содержимое этой папки очищается при перезагрузке. Это связано с файловой системой, которая предписывает хранение файлов из /tmp в оперативной памяти. + +### Пользовательские данные +- `/home` - здесь находятся личные папки пользователей. При вводе `cd ~` система переносит пользователя как раз в директорию `/home/`. +- `/root` - домашний каталог суперпользователя (администратора с UID 0). Он вынесен отдельно от остальных пользователей, чтобы администратор мог войти в систему, даже если раздел `/home` не удалось примонтировать. + +### Виртуальные и псевдо-файловые системы +Основная идея таких данных - что это не реальные данные на диске, а интерфейсы к ядру: +- `/proc` - виртуальная ФС, содержащая информацию о процессах и состоянии ядра. По-хорошему, можно просто прочитать файл в этой папке и узнать, например, модель процессора, который стоит на системе. +- `/sys` - информация об устройствах и драйверах. +- `/dev` - как мне изначально казалось, сокращение от developer, однако на самом деле является сокращением от **Devices** - файлы устройств. В Linux **все есть файл**, а значит, работа с жестким диском, терминалом, мышкой или любым другим устройством идет так же, как с обычным файлом. diff --git a/content/posts/gRPS.md b/content/posts/gRPS.md new file mode 100644 index 0000000..ccf36da --- /dev/null +++ b/content/posts/gRPS.md @@ -0,0 +1,281 @@ +--- +title: "Почему gRPC это лучший выбор для back-to-back взаимодействия" +tags: ["backend", "go"] +categories: ["tech"] + +--- +**gRPC** - это высокопроизводительный фреймворк удаленных вызовов процедур от Google, построенный на HTTP/2 и Protocol Buffers. Он быстрее REST, строго типизирован и отлично масштабируется в микросервисных архитектурах. + +--- + +## Что такое gRPC? +Google Remote Procedure Call - это современный open-source RPC-фреймворк, позволяющий сервисам вызывать методы друг друга так, как если бы они были локальными функциями. Вместо того чтобы думать о HTTP-запросах и JSON-сериализации, разработчик просто вызывает метод на удаленном сервисе. + +gRPC был разработан и открыт компанией **Google** в **2015** году. Он вырос из внутренней системы Stubby, которую Google использовал более десяти лет для связи между своими микросервисами, обрабатывающими миллиарды запросов в секунду. + +Сегодня проект находится под управлением **Cloud Native Computing Foundation (CNCF)** - той же организации, что курирует Kibernetes и Prometheus. Это гарантирует его нейтральное развитие и широкую поддержку индустрии. + +--- + +## Ключевые особенности +### Protobuf вместо JSON +gRPC использует **Protobuf** - бинарный формат сериализации данных. В отличие от текстового JSON: +- Данные занимают сильно меньше места +- Сериализация и десериализация происходят также быстрее +- Схема данных строго типизирована и версионируется через `.proto`-файлы +- Автоматическая кодогенерация клиентов и серверов на 10+ языках + +### HTTP/2 под капотом +Это дает следующие возможности: +- Мультиплексирование +- Двунаправленный стриминг +- Сжатие заголовков +- Server Push + +### Четыре режима взаимодействия +``` +Unary RPC → клиент шлёт запрос, сервер возвращает ответ (как REST) +Server Streaming → сервер стримит поток ответов на один запрос +Client Streaming → клиент стримит данные, сервер возвращает один ответ +Bidirectional → оба шлют потоки данных друг другу одновременно +``` + +### Строгий контракт через .proto +`.proto`-файл — это единственный источник правды для всей коммуникации. Если один сервис меняет API, компилятор Protobuf немедленно сломает несовместимых клиентов ещё на этапе сборки. + +### Встроенные инструменты +- **Deadline / Timeout** — встроенный контроль времени ожидания +- **Cancellation** — отмена запросов по цепочке вызовов +- **Load Balancing** — клиентская балансировка нагрузки из коробки +- **Health Checking** — стандартный протокол проверки готовности сервиса +- **Interceptors** — аналог middleware для аутентификации, логирования, трассировки + +--- + +## Пример: сервис пользователей на gRPC + +Разберём полный цикл: от `.proto`-контракта до рабочего клиента и сервера на Go. + +### Шаг 1. Определяем контракт (`user.proto`) + +```protobuf +syntax = "proto3"; + +package user; +option go_package = "github.com/example/user-service/proto"; + +// Запрос на получение пользователя +message GetUserRequest { + int64 id = 1; +} + +// Ответ с данными пользователя +message GetUserResponse { + int64 id = 1; + string name = 2; + string email = 3; + string created_at = 4; +} + +// Запрос на создание пользователя +message CreateUserRequest { + string name = 1; + string email = 2; +} + +// Сервис с двумя методами +service UserService { + rpc GetUser (GetUserRequest) returns (GetUserResponse); + rpc CreateUser (CreateUserRequest) returns (GetUserResponse); +} +``` + +### Шаг 2. Генерируем код + +```bash +# Устанавливаем плагины +go install google.golang.org/protobuf/cmd/protoc-gen-go@latest +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + +# Генерируем Go-код из .proto +protoc --go_out=. --go-grpc_out=. proto/user.proto +``` + +После этого компилятор создаст два файла: +- `user.pb.go` — структуры данных (GetUserRequest, GetUserResponse и т.д.) +- `user_grpc.pb.go` — интерфейсы сервера и заглушки клиента + +### Шаг 3. Реализуем сервер (`server/main.go`) + +```go +package main + +import ( + "context" + "fmt" + "log" + "net" + "time" + + pb "github.com/example/user-service/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// userServer реализует интерфейс pb.UserServiceServer +type userServer struct { + pb.UnimplementedUserServiceServer + // В реальности здесь была бы БД + users map[int64]*pb.GetUserResponse +} + +// GetUser — обработчик метода GetUser +func (s *userServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) { + user, ok := s.users[req.Id] + if !ok { + // gRPC-статус коды вместо HTTP-кодов + return nil, status.Errorf(codes.NotFound, "пользователь с id=%d не найден", req.Id) + } + return user, nil +} + +// CreateUser — обработчик метода CreateUser +func (s *userServer) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.GetUserResponse, error) { + if req.Email == "" { + return nil, status.Error(codes.InvalidArgument, "email обязателен") + } + + newID := int64(len(s.users) + 1) + user := &pb.GetUserResponse{ + Id: newID, + Name: req.Name, + Email: req.Email, + CreatedAt: time.Now().Format(time.RFC3339), + } + s.users[newID] = user + + return user, nil +} + +func main() { + // Слушаем порт + lis, err := net.Listen("tcp", ":50051") + if err != nil { + log.Fatalf("не удалось запустить listener: %v", err) + } + + // Создаём gRPC-сервер + grpcServer := grpc.NewServer() + + // Регистрируем наш сервис + pb.RegisterUserServiceServer(grpcServer, &userServer{ + users: make(map[int64]*pb.GetUserResponse), + }) + + fmt.Println("gRPC-сервер запущен на :50051") + if err := grpcServer.Serve(lis); err != nil { + log.Fatalf("ошибка сервера: %v", err) + } +} +``` + +### Шаг 4. Пишем клиент (`client/main.go`) + +```go +package main + +import ( + "context" + "fmt" + "log" + "time" + + pb "github.com/example/user-service/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func main() { + // Подключаемся к серверу + conn, err := grpc.Dial( + "localhost:50051", + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + log.Fatalf("не удалось подключиться: %v", err) + } + defer conn.Close() + + // Создаём клиента — это та самая "магия" gRPC: + // вызов метода выглядит как локальная функция + client := pb.NewUserServiceClient(conn) + + // Контекст с таймаутом — хорошая практика для каждого запроса + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Создаём пользователя + created, err := client.CreateUser(ctx, &pb.CreateUserRequest{ + Name: "Алиса", + Email: "alice@example.com", + }) + if err != nil { + log.Fatalf("ошибка CreateUser: %v", err) + } + fmt.Printf("Создан пользователь: ID=%d, Name=%s\n", created.Id, created.Name) + + // Получаем пользователя по ID + user, err := client.GetUser(ctx, &pb.GetUserRequest{Id: created.Id}) + if err != nil { + log.Fatalf("ошибка GetUser: %v", err) + } + fmt.Printf("Получен пользователь: %s <%s>\n", user.Name, user.Email) +} +``` + +### Шаг 5. Запускаем + +```bash +# Терминал 1: запускаем сервер +go run server/main.go +# gRPC-сервер запущен на :50051 + +# Терминал 2: запускаем клиент +go run client/main.go +# Создан пользователь: ID=1, Name=Алиса +# Получен пользователь: Алиса +``` + +--- + +## gRPC vs REST: когда что выбирать? + +| Критерий | REST | gRPC | +|---|---|---| +| **Скорость** | Хорошая | Отличная (бинарный протокол) | +| **Типизация** | Слабая (JSON) | Строгая (Protobuf) | +| **Стриминг** | Ограниченный (SSE) | Полноценный (4 режима) | +| **Браузерная поддержка** | Нативная | Нужен gRPC-Web | +| **Отладка** | Легко (curl, Postman) | Сложнее (нужен grpcurl) | +| **Контракт API** | OpenAPI/Swagger | `.proto` (строже) | +| **Кодогенерация** | Опционально | Встроена | + +**Выбирайте gRPC**, когда: +- Сервисы общаются только между собой (backend-to-backend) +- Важна производительность и объём трафика +- Нужен стриминг данных в реальном времени +- Команда большая и строгий контракт критичен + +**Выбирайте REST**, когда: +- API потребляется браузером напрямую +- Важна простота и человекочитаемость +- Команда небольшая и overhead Protobuf не оправдан + +--- + +## Итог + +gRPC — это не просто «быстрый REST». Это принципиально другой подход к межсервисному взаимодействию, где строгий контракт, бинарная эффективность и встроенный стриминг делают его идеальным фундаментом для микросервисных архитектур. Google, Netflix, Cloudflare и десятки других компаний используют его в продакшне под нагрузками, которые REST с JSON попросту не выдержал бы. + +Если вы строите систему из нескольких сервисов — gRPC стоит рассмотреть как первый выбор для их взаимодействия. diff --git a/content/projects/GLIPH.md b/content/projects/GLIPH.md new file mode 100644 index 0000000..31a535b --- /dev/null +++ b/content/projects/GLIPH.md @@ -0,0 +1 @@ +HELLOW THERE! diff --git a/content/projects/HSE.md b/content/projects/HSE.md new file mode 100644 index 0000000..58dc86f --- /dev/null +++ b/content/projects/HSE.md @@ -0,0 +1 @@ +# Кроме всего прочего я работаю frontend-разработчиком в Высшей Школе Экономики и занимаюсь разработкой системы Решебник diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5cb4069 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +services: + portfolio: + build: . + container_name: hugo-portfolio + restart: unless-stopped + ports: + - "8081:80" diff --git a/layouts/partials/google_analytics.html b/layouts/partials/google_analytics.html new file mode 100644 index 0000000..e69de29 diff --git a/themes/PaperMod b/themes/PaperMod new file mode 160000 index 0000000..10d3dcc --- /dev/null +++ b/themes/PaperMod @@ -0,0 +1 @@ +Subproject commit 10d3dcc0e05cee0aaca58a1305a9d824b2cf9a2a