切換語言為:簡體

SpringBoot專案解決多機房之間資料同步的問題

  • 爱糖宝
  • 2024-11-27
  • 2009
  • 0
  • 0

在實現同城多活的方案中,機房之間的資料同步是一個至關重要的部分。通常,這類系統需要保證跨機房的資料一致性和高可用性。爲了實現這個目標,可以採用資料庫同步、訊息佇列、分散式快取等技術。

實際場景案例

假設我們有一個電商平臺,在同城的兩個資料中心(機房A和機房B)中部署了相同的服務例項。在這些例項中,使用者訂單和庫存資訊需要在兩個機房之間進行實時同步,以保證無論使用者訪問哪個機房,都能獲得最新的訂單和庫存狀態。

方案設計

  1. 資料同步方案: 我們可以使用資料庫主從複製來保證資料的一致性。主資料庫部署在機房A中,從資料庫部署在機房B中。同時,透過訊息佇列(如Kafka)將訂單和庫存的變動事件同步到另一個機房。這樣,當訂單資訊或庫存變動時,會透過訊息佇列實時同步到另一機房的服務例項。

  2. 服務架構:

    • 服務透過 Spring Boot 來提供REST API。

    • 使用 Spring Data JPA 進行資料庫操作。

    • 使用 Kafka 作為訊息佇列,監聽訂單變動的事件,並將資料同步到另一個機房。

  3. 資料一致性保證:

    • 利用資料庫的事務管理來保證資料一致性。

    • 使用Kafka的訊息佇列來非同步處理訂單和庫存的同步操作,確保資料不會丟失。

詳細程式碼實現

1. 環境設定

我們首先需要在Spring Boot中配置資料庫連線和Kafka訊息佇列。假設我們使用MySQL和Kafka來實現資料同步。

1.1 資料庫配置(application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf8
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: order-sync-group
    producer:
      acks: all

1.2 Kafka配置類
@Configuration
public class KafkaConfig {

    @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());
    }

    @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, "order-sync-group");
        configProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
        return new DefaultKafkaConsumerFactory<>(configProps);
    }

    @Bean
    public ConcurrentMessageListenerContainer<String, Order> messageListenerContainer() {
        MessageListenerContainer container = new ConcurrentMessageListenerContainer<>(
                consumerFactory(), new ContainerProperties("order-topic"));
        container.setupMessageListener(new MessageListener<String, Order>() {
            @Override
            public void onMessage(ConsumerRecord<String, Order> record) {
                Order order = record.value();
                // 將訂單同步到本地資料庫
                orderService.saveOrder(order);
            }
        });
        return container;
    }
}

1.3 Order實體類
@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String userId;
    private String productId;
    private Integer quantity;
    private Double totalPrice;

    // Getters and Setters
}

1.4 OrderService類(處理業務邏輯)
@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private KafkaTemplate<String, Order> kafkaTemplate;

    @Transactional
    public Order createOrder(Order order) {
        // 儲存訂單到資料庫
        Order savedOrder = orderRepository.save(order);
        
        // 將訂單資訊傳送到Kafka佇列
        kafkaTemplate.send("order-topic", savedOrder);
        
        return savedOrder;
    }

    public void saveOrder(Order order) {
        // 將接收到的訂單同步到本地資料庫
        orderRepository.save(order);
    }
}

1.5 OrderController類(提供API介面)
@RestController
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping
    public ResponseEntity<Order> createOrder(@RequestBody Order order) {
        Order createdOrder = orderService.createOrder(order);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdOrder);
    }
}

2. 訂單建立和資料同步

當一個使用者在機房A建立訂單時,OrderService 會將訂單資訊儲存到本地資料庫,並透過Kafka將訂單資訊推送到訊息佇列(order-topic)。機房B的服務例項會從訊息佇列中獲取訂單資訊,並將訂單同步到本地資料庫。這樣,無論使用者訪問哪個機房,訂單資訊都會保持同步。

3. 資料庫主從同步(可選)

如果你希望資料庫層面也實現主從同步,可以考慮使用MySQL的主從複製或者分散式資料庫系統(如TiDB、PolarDB等)。在此示例中,主資料庫和從資料庫可以分佈在不同的機房,透過資料庫的複製機制保持資料一致性。

4. 高可用設計

爲了提高系統的高可用性,可以使用以下策略:

  • 負載均衡: 在機房A和機房B之間部署負載均衡器(如Nginx、Spring Cloud Gateway等),確保使用者請求可以均勻地分配到兩個機房的服務例項。

  • 服務降級與容錯: 使用Spring Cloud Circuit Breaker等技術,在一臺機房的服務不可用時,自動切換到另一臺機房,確保服務的持續可用。

  • 定期監控: 對Kafka和資料庫進行定期監控,確保資料同步過程中的問題能夠及時發現並處理。

總結

透過結合SpringBoot框架、MySQL主從複製、Kafka訊息佇列等技術,可以實現機房之間的實時資料同步。在訂單和庫存資訊變更時,透過Kafka非同步傳遞變更資料,並透過資料庫儲存同步資料,確保同城多活架構中的資料一致性和高可用性。


0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.