E-Ticaret Platformu Oluşturmak. Bölüm 5 : Apache Kafka ve Hazelcast Cache Entegrasyonu


#ecommerce #applicaition #backend #ddd #microservice #kafka #hazelcast #richdomainmodel #spring #java #hibernate
E-Ticaret Platformu Oluşturmak. Bölüm 1 : İhtiyaçları Çıkarmak : https://www.turkninja.com/2023/08/e-ticaret-platformu-olusturmak-bolum-1.html

E-Ticaret Platformu Oluşturmak. Bölüm 2 : Domain Stroytelling : Katılımcılar, İş Akışları, Kullanıcı Hikayeleri, İlgili Terimler ve Konseptler (Domain), Geliştirme İçin Önceliklendirme, İlgili Dokümantasyonlar : https://www.turkninja.com/2023/08/e-ticaret-platformu-olusturmak-bolum-2.html

E-Ticaret Platformu Oluşturmak. Bölüm 3 : DDD (Domain-Driven Design): İlgili alt sistemleri ve sınırlı bağlamları tanımları, microservicler, paketler, classlar, class kodları : https://www.turkninja.com/2023/08/e-ticaret-platformu-olusturmak-bolum-3.html

E-Ticaret Platformu Oluşturmak. Bölüm 4 : Rich Domain Modele Göre Microservicelerdeki Sınıfların Kodlarını oluşturmak : https://www.turkninja.com/2023/08/e-ticaret-platformu-olusturmak-bolum-4.html

E-Ticaret Platformu Oluşturmak. Bölüm 5 : Apache Kafka ve Hazelcast Cache Entegrasyonu : https://www.turkninja.com/2023/08/e-ticaret-platformu-olusturmak-bolum-5.html

E-Ticaret Platformu Oluşturmak. Bölüm 6 : Uygulamayı Dockerize etme ve Docker Compose ile localde ayağa kaldırma : https://www.turkninja.com/2023/08/e-ticaret-platformu-olusturmak-bolum-5_17.html

E-Ticaret Platformu Oluşturmak. Bölüm 7 : Jenkins ile uygulamayı CI/CD Pipeline'ına sokarak Dockerize etme, Test Etme ve Kubernetes'e deploy etme : https://www.turkninja.com/2023/08/e-ticaret-platformu-olusturmak-bolum-7.html


Bu uygulamaya Apache Kafka entegrasyonu eklemek istiyorum. Adaptör ve port ile bu entegrasyonu ekle. Hangi feature'a eklememiz gerektiğine sen karar ver.


Apache Kafka, büyük ölçekli uygulamalarda yaygın olarak kullanılan bir olay akışı platformudur. Bu entegrasyon, birçok farklı alanda kullanılabilir, ancak özellikle sipariş işleme veya envanter yönetimi gibi yüksek hacimli ve asenkron işlemlerde kullanmak faydalı olabilir.


Örneğin, Sepet ve Sipariş Yönetimi bağlamı içinde, siparişlerin oluşturulması ve işlenmesi için bir Kafka entegrasyonu eklemeyi düşünelim.


Kafka Adapter Class (Adapter Pattern)

java

Copy code

public class KafkaOrderAdapter {


    private final Producer<Long, Order> producer;

    private final String topicName;


    public KafkaOrderAdapter(String topicName, String bootstrapServers) {

        Properties properties = new Properties();

        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);

        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, LongSerializer.class);

        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);


        this.producer = new KafkaProducer<>(properties);

        this.topicName = topicName;

    }


    public void sendOrder(Order order) {

        ProducerRecord<Long, Order> record = new ProducerRecord<>(topicName, order.getId(), order);

        producer.send(record);

    }

}

OrderService Class (Updated with Port)

java

Copy code

@Service

public class OrderService {


    private final OrderRepository orderRepository;

    private final KafkaOrderAdapter kafkaOrderAdapter;


    public OrderService(OrderRepository orderRepository, KafkaOrderAdapter kafkaOrderAdapter) {

        this.orderRepository = orderRepository;

        this.kafkaOrderAdapter = kafkaOrderAdapter;

    }


    public void createOrder(Order order) {

        // Business logic for creating an order

        orderRepository.save(order);


        // Send order to Kafka

        kafkaOrderAdapter.sendOrder(order);

    }


    // Other methods...

}

Bu düzenleme, siparişlerin oluşturulduğunda Kafka'ya gönderilmesini sağlar. Diğer mikroservisler daha sonra bu olayları dinleyebilir ve gerekli işlemleri gerçekleştirebilir, böylece asenkron bir iş akışı sağlanabilir.


Elbette, Kafka ile entegrasyonu yapabilmek için gerekli yapılandırmayı sağlamak adına ayrı bir yapılandırma sınıfı oluşturulabilir. Spring Boot kullanıyorsanız, aşağıdaki gibi bir yapılandırma sınıfı oluşturabilirsiniz:


java

Copy code

@Configuration

public class KafkaConfig {


    @Value("${kafka.bootstrap.servers}")

    private String bootstrapServers;


    @Value("${kafka.order.topic}")

    private String orderTopic;


    @Bean

    public ProducerFactory<Long, Order> producerFactory() {

        Map<String, Object> configProps = new HashMap<>();

        configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);

        configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, LongSerializer.class);

        configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);

        return new DefaultKafkaProducerFactory<>(configProps);

    }


    @Bean

    public KafkaTemplate<Long, Order> kafkaTemplate() {

        return new KafkaTemplate<>(producerFactory());

    }


    @Bean

    public KafkaOrderAdapter kafkaOrderAdapter() {

        return new KafkaOrderAdapter(orderTopic, bootstrapServers);

    }

}

Bu yapılandırma sınıfı, Kafka üreticisinin (producer) nasıl oluşturulacağını ve hangi özelliklere sahip olacağını belirtir. Ayrıca, KafkaOrderAdapter örneğinin de oluşturulmasını sağlar.


application.properties veya application.yml dosyasında, Kafka sunucusunun konumunu ve ilgili başka detayları da belirtmeniz gerekecektir:


properties

Copy code

kafka.bootstrap.servers=localhost:9092

kafka.order.topic=orders

Bu şekilde, Kafka entegrasyonu tamamlanmış olur ve Spring uygulamanız içerisinde kullanılabilir.


Bu uygulamaya Hazelcast cache entegrasyonu eklemek istiyorum. Adaptör ve port ile bu entegrasyonu ekle. 


Hazelcast entegrasyonu, genellikle performans ihtiyaçları doğrultusunda veri önbellekleme işlemleri için kullanılır. Bu tür bir uygulamada, en sık okunan verilerin önbelleklenmesi gerekebilir. Örneğin, Ürün Yönetimi Microservisi içindeki ürün bilgileri, sıkça erişilen ve değişmeyen veriler olabilir. Bu nedenle, bu entegrasyonu Ürün Yönetimi Microservisi içine eklemek mantıklı olabilir.


Aşağıda, Hazelcast'ın Ürün Yönetimi Microservisi içine nasıl entegre edilebileceğini gösteren bir örnek yapılandırma ve adaptör sınıfı bulunmaktadır:


Hazelcast Yapılandırması:

java

Copy code

@Configuration

public class HazelcastConfig {


    @Bean

    public Config hazelCastConfig() {

        Config config = new Config();

        config.setInstanceName("hazelcast-instance")

              .addMapConfig(

                  new MapConfig()

                      .setName("products")

                      .setTimeToLiveSeconds(20)

              );

        return config;

    }

}

Ürün Yönetimi Port ve Adaptörü:

java

Copy code

public interface ProductCachePort {

    Product getProductById(Long id);

    void putProduct(Product product);

}


@Component

public class HazelcastProductCacheAdapter implements ProductCachePort {


    private final IMap<Long, Product> products;


    public HazelcastProductCacheAdapter(HazelcastInstance hazelcastInstance) {

        this.products = hazelcastInstance.getMap("products");

    }


    @Override

    public Product getProductById(Long id) {

        return products.get(id);

    }


    @Override

    public void putProduct(Product product) {

        products.put(product.getId(), product);

    }

}

Bu adaptör, ürün bilgilerini önbellekten almayı ve önbelleğe koymayı sağlar. Ürün servisleri bu adaptörü kullanarak gerekli ürün bilgilerini hızlı bir şekilde alabilir.


Bu entegrasyon, ürün bilgilerinin okunma performansını önemli ölçüde artıracaktır, çünkü veriler artık doğrudan hafızadan alınacaktır, veritabanından okuma işlemi gerekmeyecektir.


Tabii ki! Ürün servisi içinde, yukarıda oluşturduğumuz ProductCachePort adaptörünü kullanarak ürün bilgilerini önbelleklemek ve önbellekten almak isteyebiliriz.


Örneğin, ProductService sınıfını aşağıdaki gibi güncelleyebiliriz:


java

Copy code

@Service

public class ProductService {


    private final ProductRepository productRepository;

    private final ProductCachePort productCachePort;


    @Autowired

    public ProductService(ProductRepository productRepository, ProductCachePort productCachePort) {

        this.productRepository = productRepository;

        this.productCachePort = productCachePort;

    }


    public Product getProductById(Long id) {

        Product product = productCachePort.getProductById(id);

        if (product == null) {

            product = productRepository.findById(id).orElseThrow(() -> new ProductNotFoundException(id));

            productCachePort.putProduct(product);

        }

        return product;

    }


    public Product createProduct(Product product) {

        product = productRepository.save(product);

        productCachePort.putProduct(product);

        return product;

    }


    // Diğer metodlar

}

Bu kod, bir ürünü ID ile alma işlemi sırasında öncelikle ürünün önbellekte olup olmadığını kontrol eder. Eğer ürün önbellekte yoksa, veritabanından alınır ve önbelleğe eklenir. Bir ürün eklendiğinde veya güncellendiğinde de önbelleğe eklenir.


Bu yaklaşım, sıkça okunan veriler için veritabanı üzerindeki yükü azaltmaya yardımcı olur ve veri erişimini hızlandırır. Her çağrı için veritabanına gitmek yerine, önbellekten alınan verilerle işlemler hızlanır.


Yine de, önbellek tutarlılığı ve verilerin güncellenmesi gibi konuların dikkate alınması gerekir. Uygulamanın ihtiyacına göre önbellek politikaları ve geçerlilik süreleri düzenlenebilir.






Please Select Embedded Mode To Show The Comment System.*

Daha yeni Daha eski

نموذج الاتصال