8.7 KiB
8.7 KiB
Руководство по созданию микросервиса
🚀 Быстрый старт
Шаг 1: Скопировать шаблон
cp -r microservices/template_service microservices/my_new_service
cd microservices/my_new_service
Шаг 2: Выбрать порт
Выберите порт из диапазона 13000-14000. Уже занятые:
- 13001 - User Service
Пусть ваш сервис будет на порту 13002.
Шаг 3: Создать proto файл
Создайте shared_proto/proto/my_service.proto:
syntax = "proto3";
package my_service;
message GetDataRequest {
string id = 1;
}
message Data {
string id = 1;
string content = 2;
}
service MyService {
rpc GetData(GetDataRequest) returns (Data);
}
Шаг 4: Обновить shared_proto/src/lib.rs
Добавьте:
pub mod my_service {
tonic::include_proto!("my_service");
}
Шаг 5: Обновить shared_proto/build.rs
Добавьте:
tonic_build::compile_protos("proto/my_service.proto")?;
Шаг 6: Обновить microservices/my_new_service/Cargo.toml
[package]
name = "my_new_service"
version.workspace = true
edition.workspace = true
authors.workspace = true
[dependencies]
tokio = { version = "1.35", features = ["full"] }
axum = "0.7"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tower = "0.4"
tower-http = { version = "0.5", features = ["trace"] }
tracing = "0.1"
tracing-subscriber = "0.3"
tonic = "0.11"
prost = "0.12"
shared_proto = { path = "../../shared_proto" }
Шаг 7: Реализовать сервис
Обновите microservices/my_new_service/src/main.rs:
use tonic::{Request, Response, Status, transport::Server};
use shared_proto::my_service::{
my_service_server::{MyService, MyServiceServer},
GetDataRequest, Data,
};
use tracing_subscriber;
pub struct MyServiceImpl;
#[tonic::async_trait]
impl MyService for MyServiceImpl {
async fn get_data(
&self,
request: Request<GetDataRequest>,
) -> Result<Response<Data>, Status> {
let id = request.into_inner().id;
tracing::info!("GetData called with id: {}", id);
Ok(Response::new(Data {
id: id.clone(),
content: format!("Data for {}", id),
}))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
let addr = "127.0.0.1:13002".parse()?;
let my_service = MyServiceImpl;
tracing::info!("MyService gRPC server listening on {}", addr);
Server::builder()
.add_service(MyServiceServer::new(my_service))
.serve(addr)
.await?;
Ok(())
}
Шаг 8: Добавить в workspace
Обновите корневой Cargo.toml:
[workspace]
members = [
"api_gateway",
"api",
"microservices/user_service",
"microservices/my_new_service",
"shared_proto"
]
Шаг 9: Скомпилировать
cargo check
# или
cargo build
📚 Примеры
Пример 1: Сервис продуктов
shared_proto/proto/product.proto:
syntax = "proto3";
package product;
message Product {
int32 id = 1;
string name = 2;
float price = 3;
}
message GetProductRequest {
int32 id = 1;
}
message CreateProductRequest {
string name = 1;
float price = 2;
}
service ProductService {
rpc GetProduct(GetProductRequest) returns (Product);
rpc CreateProduct(CreateProductRequest) returns (Product);
}
microservices/product_service/src/main.rs:
use tonic::{Request, Response, Status, transport::Server};
use shared_proto::product::{
product_service_server::{ProductService, ProductServiceServer},
GetProductRequest, Product, CreateProductRequest,
};
use tracing_subscriber;
pub struct ProductServiceImpl;
#[tonic::async_trait]
impl ProductService for ProductServiceImpl {
async fn get_product(
&self,
request: Request<GetProductRequest>,
) -> Result<Response<Product>, Status> {
let id = request.into_inner().id;
Ok(Response::new(Product {
id,
name: "Product".to_string(),
price: 99.99,
}))
}
async fn create_product(
&self,
request: Request<CreateProductRequest>,
) -> Result<Response<Product>, Status> {
let req = request.into_inner();
Ok(Response::new(Product {
id: 1,
name: req.name,
price: req.price,
}))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
let addr = "127.0.0.1:13002".parse()?;
let service = ProductServiceImpl;
tracing::info!("Product Service listening on {}", addr);
Server::builder()
.add_service(ProductServiceServer::new(service))
.serve(addr)
.await?;
Ok(())
}
Пример 2: Сервис заказов
Использует User Service и Product Service:
microservices/order_service/src/main.rs:
use tonic::transport::Channel;
use shared_proto::order::{
order_service_server::{OrderService, OrderServiceServer},
CreateOrderRequest, Order,
};
use shared_proto::user::user_service_client::UserServiceClient;
use shared_proto::product::product_service_client::ProductServiceClient;
pub struct OrderServiceImpl {
user_client: UserServiceClient<Channel>,
product_client: ProductServiceClient<Channel>,
}
#[tonic::async_trait]
impl OrderService for OrderServiceImpl {
async fn create_order(
&self,
request: tonic::Request<CreateOrderRequest>,
) -> Result<tonic::Response<Order>, tonic::Status> {
let req = request.into_inner();
// Вызвать User Service
// Вызвать Product Service
// Создать заказ
Ok(tonic::Response::new(Order {
id: 1,
user_id: req.user_id,
product_id: req.product_id,
}))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
let user_channel = Channel::from_static("http://127.0.0.1:13001")
.connect()
.await?;
let product_channel = Channel::from_static("http://127.0.0.1:13002")
.connect()
.await?;
let user_client = UserServiceClient::new(user_channel);
let product_client = ProductServiceClient::new(product_channel);
let order_service = OrderServiceImpl {
user_client,
product_client,
};
let addr = "127.0.0.1:13003".parse()?;
tracing::info!("Order Service listening on {}", addr);
tonic::transport::Server::builder()
.add_service(OrderServiceServer::new(order_service))
.serve(addr)
.await?;
Ok(())
}
🔄 Интеграция с API Gateway
После создания сервиса, обновите api_gateway/src/main.rs для добавления REST endpoints:
// Создать gRPC клиента для вашего сервиса
let my_service_channel = Channel::from_static("http://127.0.0.1:13002")
.connect()
.await?;
// Добавить REST endpoints
.route("/api/data/:id", get(get_data_handler))
✅ Чек-лист
- Скопирован шаблон сервиса
- Выбран порт (13000-14000)
- Создан proto файл
- Обновлен
shared_proto/src/lib.rs - Обновлен
shared_proto/build.rs - Обновлен
Cargo.tomlмикросервиса - Реализована логика сервиса
- Добавлен в workspace
Cargo.toml - Успешно компилируется (
cargo check) - Добавлены тесты (опционально)
🐛 Отладка
Проверить что сервис запускается
cargo run -p my_new_service
Должно вывести:
MyService gRPC server listening on 127.0.0.1:13002
Проверить gRPC endpoint
# Установить grpcurl если не установлен
# https://github.com/fullstorydev/grpcurl
grpcurl -plaintext localhost:13002 list
Логирование
RUST_LOG=debug cargo run -p my_new_service
📞 Помощь
Если возникли проблемы:
- Проверьте что все proto файлы скомпилировались
- Убедитесь что порт не занят другим процессом
- Проверьте логи сервиса
- Обратитесь к
ARCHITECTURE.mdдля общей информации