برنامه نویسی

ساخت میکروسرویس های واکنشی: راهنمای گام به گام

از یکپارچه تا میکروسرویس ها: یک رویکرد واکنشی

گذار از معماری یکپارچه به میکروسرویس ها گام مهمی برای هر سازمانی است. میکروسرویس های واکنشی راهی برای ساخت برنامه های کاربردی بسیار پاسخگو، انعطاف پذیر و مقیاس پذیر ارائه می دهند. این راهنما شما را در فرآیند تبدیل یک برنامه یکپارچه به مجموعه ای از میکروسرویس های واکنشی با استفاده از آخرین نسخه جاوا راهنمایی می کند.

چرا میکروسرویس های واکنشی؟

میکروسرویس‌های واکنش‌گرا از اصول برنامه‌نویسی واکنش‌گرا برای مدیریت همزمانی بالا، ایجاد انعطاف‌پذیری و اطمینان از مقیاس‌پذیری استفاده می‌کنند. مزایای کلیدی عبارتند از:

  1. پاسخگویی: میکروسرویس های واکنشی با رسیدگی به درخواست ها به صورت ناهمزمان، پاسخ های سریعی را حتی تحت بار سنگین ارائه می دهند.
  2. تاب آوری: سیستم های واکنشی شکست ها را ایزوله می کنند و به خوبی بازیابی می کنند.
  3. مقیاس پذیری: عملیات غیرمسدود کننده امکان استفاده بهتر از منابع را فراهم می کند و به سیستم ها اجازه می دهد تا به طور کارآمد مقیاس شوند.

مرحله 1: درک یکپارچه

قبل از شکستن یکپارچه، درک ساختار آن ضروری است. یک برنامه یکپارچه معمولی دارای یک پایه کد واحد با اجزای محکم جفت شده است.

public class MonolithicApp {
    public static void main(String[] args) {
        UserService userService = new UserService();
        OrderService orderService = new OrderService(userService);

        Order order = orderService.createOrder("user123", "product456");
        System.out.println(order);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مرحله 2: نامزدهای Microservice را شناسایی کنید

برنامه یکپارچه را برای شناسایی اجزایی که می‌توانند به میکروسرویس‌های مجزا جدا شوند، تجزیه و تحلیل کنید. نامزدهای رایج عبارتند از مدیریت کاربر، پردازش سفارش و مدیریت موجودی.

مرحله 3: میکروسرویس ها را طراحی کنید

طراحی دامنه محور (DDD)

از اصول طراحی دامنه محور (DDD) برای شناسایی و مدل سازی دامنه های اصلی و زیر دامنه های برنامه خود استفاده کنید. هر میکروسرویس باید با یک دامنه یا زیر دامنه خاص هماهنگ باشد و منطق تجاری و داده های خود را در بر بگیرد.

مثال:

  1. سرویس کاربر: حساب های کاربری و پروفایل ها را مدیریت می کند.
  2. سفارش خدمات: ایجاد، پردازش و مدیریت سفارش را مدیریت می کند.
  3. خدمات محصول: کاتالوگ و موجودی محصول را مدیریت می کند.

مرحله 4: اصول برنامه نویسی واکنشی را پیاده سازی کنید

مثال خدمات کاربر

با استفاده از Spring WebFlux، می توانیم یک سرویس کاربر واکنشی بسازیم. WebFlux بر روی Project Reactor ساخته شده است که یک مدل برنامه نویسی واکنشی قدرتمند و انعطاف پذیر را ارائه می دهد.

مدل کاربر و پیاده سازی خدمات

مدل User یک POJO ساده (Plain Old Java Object) است که نهاد کاربر را نشان می دهد. کلاس UserService چرخه حیات اشیاء کاربر را در یک نقشه هش همزمان مدیریت می کند.

// User.java
public class User {
    private String id;
    private String name;
    // getters and setters
}

// UserService.java
@Service
public class UserService {
    private final Map<String, User> users = new ConcurrentHashMap<>();

    public Mono<User> getUserById(String id) {
        return Mono.justOrEmpty(users.get(id));
    }

    public Mono<User> createUser(User user) {
        users.put(user.getId(), user);
        return Mono.just(user);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کنترل کننده کاربر

کلاس UserController درخواست های HTTP را مدیریت می کند و با UserService تعامل دارد. از قابلیت های واکنشی Spring WebFlux برای بازگشت استفاده می کند Mono اشیاء، که یک مقدار ناهمزمان واحد را نشان می دهند.

// UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public Mono<ResponseEntity<User>> getUser(@PathVariable String id) {
        return userService.getUserById(id)
                .map(ResponseEntity::ok)
                .defaultIfEmpty(ResponseEntity.notFound().build());
    }

    @PostMapping
    public Mono<User> createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نقطه ورود برنامه

کلاس برنامه اصلی با حاشیه نویسی شده است @SpringBootApplication، که اسکن مؤلفه و پیکربندی خودکار را آغاز می کند.

// Application.java
@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نمونه خدمات سفارش

سرویس سفارش با استفاده از WebClient، یک سرویس گیرنده وب واکنشی که در Spring WebFlux گنجانده شده است، به طور ناهمزمان با سرویس کاربر تعامل خواهد داشت.

مدل سفارش و اجرای خدمات

مدل Order یک موجودیت سفارش را نشان می دهد. کلاس OrderService از WebClient برای ایجاد درخواست های غیرمسدود کننده HTTP به سرویس کاربر برای بازیابی اطلاعات کاربر استفاده می کند.

// Order.java
public class Order {
    private String orderId;
    private String userId;
    private String productId;
    // getters and setters
}

// OrderService.java
@Service
public class OrderService {
    private final WebClient webClient;

    public OrderService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("http://localhost:8080").build();
    }

    public Mono<Order> createOrder(String userId, String productId) {
        return webClient.get()
                .uri("/users/{id}", userId)
                .retrieve()
                .bodyToMono(User.class)
                .map(user -> {
                    Order order = new Order();
                    order.setUserId(user.getId());
                    order.setProductId(productId);
                    order.setOrderId(UUID.randomUUID().toString());
                    return order;
                });
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کنترل کننده سفارش

کلاس OrderController درخواست های HTTP را مدیریت می کند و برای پردازش سفارش ها با OrderService تعامل دارد.

// OrderController.java
@RestController
@RequestMapping("/orders")
public class OrderController {
    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public Mono<Order> createOrder(@RequestParam String userId, @RequestParam String productId) {
        return orderService.createOrder(userId, productId);
    }
}

// Application.java
@SpringBootApplication
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مرحله 5: ارتباطات بین خدماتی را پیاده سازی کنید

میکروسرویس های واکنشی اغلب نیاز به ارتباط با یکدیگر دارند. ما از WebClient در Spring WebFlux برای غیر مسدود کردن درخواست های HTTP استفاده می کنیم.

@Bean
public WebClient.Builder webClientBuilder() {
    return WebClient.builder();
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مرحله 6: فشار برگشتی و انعطاف پذیری را کنترل کنید

برای کنترل سناریوهایی که تولیدکننده سریعتر از مصرف کننده است، فشار برگشتی را اعمال کنید. از Project Reactor’s استفاده کنید Flux و Mono برای مدیریت جریان داده و انعطاف پذیری.

مدار شکن

از Resilience4j برای پیاده‌سازی یک قطع کننده مدار استفاده کنید و اطمینان حاصل کنید که خدمات شما می‌توانند به خوبی از پس خرابی‌ها برآیند.

// OrderService.java
@Service
public class OrderService {
    private final WebClient webClient;
    private final CircuitBreaker circuitBreaker;

    public OrderService(WebClient.Builder webClientBuilder, CircuitBreakerRegistry circuitBreakerRegistry) {
        this.webClient = webClientBuilder.baseUrl("http://localhost:8080").build();
        this.circuitBreaker = circuitBreakerRegistry.circuitBreaker("userService");
    }

    public Mono<Order> createOrder(String userId, String productId) {
        return Mono.fromCallable(() -> circuitBreaker.executeSupplier(() ->
                webClient.get()
                        .uri("/users/{id}", userId)
                        .retrieve()
                        .bodyToMono(User.class)
                        .block()))
                .map(user -> {
                    Order order = new Order();
                    order.setUserId(user.getId());
                    order.setProductId(productId);
                    order.setOrderId(UUID.randomUUID().toString());
                    return order;
                });
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مرحله 7: استقرار و نظارت

میکروسرویس‌های خود را با استفاده از پلت‌فرم‌های ارکستراسیون کانتینری مانند Kubernetes مستقر کنید. نظارت را برای ردیابی سلامت و عملکرد خدمات خود اجرا کنید.

مانیتورینگ با میکرومتر و پرومتئوس

// Add dependencies for micrometer and prometheus
dependencies {
    implementation 'io.micrometer:micrometer-core'
    implementation 'io.micrometer:micrometer-registry-prometheus'
}

// Application.java
@SpringBootApplication
public class MonitoringApplication {
    public static void main(String[] args) {
        SpringApplication.run(MonitoringApplication.class, args);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

موضوعات پیشرفته

معماری رویداد محور

ریزسرویس‌های واکنشی اغلب از معماری رویداد محور سود می‌برند، جایی که سرویس‌ها از طریق رویدادها به جای تماس‌های مستقیم HTTP ارتباط برقرار می‌کنند. این خدمات را از هم جدا می کند و به انعطاف پذیری و مقیاس پذیری بیشتر اجازه می دهد.

مثال: استفاده از کافکا برای ارتباطات رویداد محور

// KafkaProducerConfig.java
@Configuration
public class KafkaProducerConfig {

    @Bean
    public ProducerFactory<String, Order> producerFactory() {
        Map<String, Object> configProps = new HashMap<>();
        configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
        return new DefaultKafkaProducerFactory<>(configProps);
    }

    @Bean
    public KafkaTemplate<String, Order> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }
}

// KafkaConsumerConfig.java
@Configuration
public class KafkaConsumerConfig {

    @Bean
    public ConsumerFactory<String, Order> consumerFactory() {
        Map<String, Object> configProps = new HashMap<>();
        configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        configProps.put(ConsumerConfig.GROUP_ID_CONFIG, "group_id");
        configProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        configProps.put(ConsumerConfig.VALUE_DES

ERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
        configProps.put(JsonDeserializer.TRUSTED_PACKAGES, "*");
        return new DefaultKafkaConsumerFactory<>(configProps);
    }

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, Order> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, Order> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        return factory;
    }
}

// OrderProducer.java
@Service
public class OrderProducer {

    private final KafkaTemplate<String, Order> kafkaTemplate;

    public OrderProducer(KafkaTemplate<String, Order> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void sendOrder(Order order) {
        kafkaTemplate.send("orders", order);
    }
}

// OrderConsumer.java
@Service
public class OrderConsumer {

    @KafkaListener(topics = "orders", groupId = "group_id")
    public void consume(Order order) {
        System.out.println("Consumed order: " + order);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

الگوهای طراحی و بهترین روش ها

1. اصل مسئولیت واحد (SRP)

هر میکروسرویس باید یک مسئولیت واحد داشته باشد که شامل یک قابلیت تجاری خاص است. این امر قابلیت نگهداری و مقیاس پذیری را ارتقا می دهد.

2. الگوی مدار شکن

از الگوی قطع کننده مدار برای جلوگیری از خرابی های آبشاری استفاده کنید و به سیستم اجازه دهید تا به خوبی بازیابی شود. این امر به ویژه در یک محیط توزیع شده که در آن خدمات به یکدیگر وابسته هستند اهمیت دارد.

// OrderService.java
@Service
public class OrderService {
    private final WebClient webClient;
    private final CircuitBreaker circuitBreaker;

    public OrderService(WebClient.Builder webClientBuilder, CircuitBreakerRegistry circuitBreakerRegistry) {
        this.webClient = webClientBuilder.baseUrl("http://localhost:8080").build();
        this.circuitBreaker = circuitBreakerRegistry.circuitBreaker("userService");
    }

    public Mono<Order> createOrder(String userId, String productId) {
        return Mono.fromCallable(() -> circuitBreaker.executeSupplier(() ->
                webClient.get()
                        .uri("/users/{id}", userId)
                        .retrieve()
                        .bodyToMono(User.class)
                        .block()))
                .map(user -> {
                    Order order = new Order();
                    order.setUserId(user.getId());
                    order.setProductId(productId);
                    order.setOrderId(UUID.randomUUID().toString());
                    return order;
                });
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

3. رویداد منبع یابی

منبع یابی رویداد یک الگوی طراحی است که در آن تغییرات حالت به عنوان دنباله ای از رویدادها ثبت می شود. این امکان یک تاریخچه کامل از تغییرات حالت را فراهم می کند و بازسازی حالت را در هر مقطع زمانی آسان می کند.

// EventStore.java
public class EventStore {
    private final List<Event> events = new ArrayList<>();

    public void save(Event event) {
        events.add(event);
    }

    public List<Event> getEvents() {
        return new ArrayList<>(events);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

4. CQRS (تفکیک مسئولیت پرس و جوی فرمان)

CQRS الگویی است که مسئولیت رسیدگی به دستورات (نوشتن) و پرس و جوها (خواندن) را از هم جدا می کند. این جداسازی امکان سیستم های مقیاس پذیرتر و قابل نگهداری را فراهم می کند.

// C# example using CQRS
public class Command {
    public string Data { get; set; }
}

public class Query {
    public string Criteria { get; set; }
}

public interface ICommandHandler<T> {
    void Handle(T command);
}

public interface IQueryHandler<T, R> {
    R Handle(T query);
}

public class CommandHandler : ICommandHandler<Command> {
    public void Handle(Command command) {
        // Handle the command
    }
}

public class QueryHandler : IQueryHandler<Query, string> {
    public string Handle(Query query) {
        // Handle the query and return result
        return "Result";
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

5. الگوی حماسه

الگوی Saga راهی برای مدیریت تراکنش های توزیع شده در چندین سرویس است. این تراکنش را به مجموعه ای از مراحل کوچکتر تقسیم می کند که هر کدام توسط یک سرویس مدیریت می شوند و تراکنش های جبرانی برای رسیدگی به خرابی ها وجود دارد.

مثال:

  1. سفارش خدمات: حماسه را با ایجاد یک سفارش شروع می کند.
  2. خدمات موجودی: موجودی محصول را رزرو می کند.
  3. خدمات پرداخت: پرداخت را پردازش می کند.
  4. سفارش خدمات: سفارش را نهایی می کند.

اگر هر مرحله ای با شکست مواجه شود، تراکنش های جبرانی برای بازگرداندن تغییرات فعال می شوند.

نتیجه

ساخت ریزسرویس‌های واکنشی شامل درک اصول واکنش‌پذیر، جداسازی اجزا و اطمینان از انعطاف‌پذیری و مقیاس‌پذیری است. با انتقال از معماری یکپارچه به معماری میکروسرویس واکنشی، می‌توانید برنامه‌هایی ایجاد کنید که برای رسیدگی به نیازهای محیط‌های مدرن و با همزمانی بالا مناسب‌تر باشند. این راهنما پایه ای برای ساخت چنین سیستم هایی با استفاده از آخرین نسخه جاوا و چارچوب های برنامه نویسی واکنشی فراهم می کند. پذیرش برنامه نویسی واکنشی می تواند عملکرد، قابلیت نگهداری و پاسخگویی برنامه های شما را به میزان قابل توجهی افزایش دهد.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا