常见的开源分布式中间件

消息队列中间件

  • Apache Kafka
    • 使用过程
      • 引入依赖:在Maven项目中,添加相关依赖<dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>2.8.0</version></dependency>
      • 生产者代码
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;

public class KafkaProducerExample {
    
    
    public static void main(String[] args) {
    
    
        // 设置生产者配置
        Properties props = new Properties();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        // 创建生产者实例
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);
        // 发送消息
        ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key1", "value1");
        producer.send(record);
        // 关闭生产者
        producer.close();
    }
}
    - **消费者代码**:
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    
    
    public static void main(String[] args) {
    
    
        // 设置消费者配置
        Properties props = new Properties();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group");
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
        // 创建消费者实例
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
        // 订阅主题
        consumer.subscribe(Collections.singletonList("test-topic"));
        // 拉取消息并处理
        while (true) {
    
    
            ConsumerRecords<String, String> records = consumer.poll(100);
            for (ConsumerRecord<String, String> record : records) {
    
    
                System.out.println("Received message: " + record.value());
            }
        }
    }
}
- **注意要点**:合理设置分区数和副本数,以满足性能和可靠性需求;注意消息的序列化和反序列化方式,确保数据的正确传输和处理;监控Kafka集群的性能指标,如吞吐量、延迟等。
  • RabbitMQ
    • 使用过程
      • 创建生产者
import pika

# 建立连接
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# 声明交换机
channel.exchange_declare(exchange='logs', exchange_type='fanout')
# 发送消息
message = "Hello, RabbitMQ!"
channel.basic_publish(exchange='logs', routing_key='', body=message)
# 关闭连接
connection.close()
    - **创建消费者**:
import pika

# 建立连接
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# 声明交换机
channel.exchange_declare(exchange='logs', exchange_type='fanout')
# 声明随机队列
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
# 绑定交换机和队列
channel.queue_bind(exchange='logs', queue=queue_name)
# 定义回调函数处理消息
def callback(ch, method, properties, body):
    print("Received message: %r" % body)
# 消费消息
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
# 开始消费
channel.start_consuming()
- **注意要点**:合理设计消息路由策略,根据业务需求选择合适的交换机类型和路由键;确保消息的持久化配置,避免消息丢失;注意内存和磁盘的使用情况,防止RabbitMQ服务器因资源不足而出现问题。

服务治理中间件

  • Dubbo
    • 使用过程
      • 定义公共接口package com.example.api;public interface UserService {String getUserById(String userId);}
      • 实现服务提供者
package com.example.provider;
import com.example.api.UserService;
import org.apache.dubbo.config.annotation.DubboService;

@DubboService(version = "1.0.0")
public class UserServiceImpl implements UserService {
    
    
    @Override
    public String getUserById(String userId) {
    
    
        return "User(id=" + userId + ",name=乔总)";
    }
}
    - **配置dubbo服务提供者**:在`application.yml`中配置dubbo和注册中心。
dubbo:
  application:
    name: user-service-provider
  registry:
    address: zookeeper://127.0.0.1:2181
  protocol:
    name: dubbo
    port: 20880
    - **实现服务消费者**:
package com.example.consumer;
import com.example.api.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class UserServiceConsumer implements CommandLineRunner {
    
    
    @DubboReference(version = "1.0.0")
    private UserService userService;

    @Override
    public void run(String... args) {
    
    
        String user = userService.getUserById("123");
        System.out.println("Received user: " + user);
    }
}
    - **配置dubbo服务消费者**:在客户端的`application.yml`配置。
dubbo:
  application:
    name: user-service-consumer
  registry:
    address: zookeeper://127.0.0.1:2181
- **注意要点**:注意服务版本管理,避免因为版本不兼容导致服务调用失败;确保注册中心的高可用性,部署为高可用集群;合理调整服务调用的超时与重试机制。
  • Nacos
    • 使用过程
      • 服务注册:在服务提供者项目中,引入Nacos客户端依赖,在配置文件中配置Nacos服务器地址等信息,在启动类或配置类中使用相关注解或API进行服务注册。
      • 服务发现:在服务消费者项目中,引入Nacos客户端依赖,配置Nacos服务器地址,使用Nacos提供的API获取服务实例列表,进行远程调用。
      • 配置中心:在应用中引入Nacos配置客户端依赖,配置Nacos服务器地址,使用API或注解获取配置信息,实现动态更新。
    • 注意要点:注意Nacos服务器的部署模式,根据实际需求选择单机或集群部署;合理设置命名空间、分组等,避免配置冲突;确保Nacos与其他组件的兼容性。

分布式事务中间件

  • Seata
    • 使用过程
      • AT模式:在微服务项目中引入Seata依赖,配置Seata服务器地址、事务分组等信息,在需要分布式事务的方法上添加@GlobalTransactional注解。
      • TCC模式:定义TCC接口,包含tryconfirmcancel方法,实现TCC接口,在业务逻辑中调用TCC接口的方法。
    • 注意要点:关注网络延迟和事务超时问题,避免事务长时间悬挂;处理好锁竞争,考虑使用乐观锁等机制;合理设置日志记录级别和存储方式,便于排查问题。

分布式数据库中间件

  • ShardingSphere
    • 使用过程
      • 引入依赖:在项目的pom.xml文件中引入ShardingSphere的相关依赖。
      • 配置数据源:配置多个数据源,定义分片规则、读写分离规则等。
      • 使用JDBC操作:使用JDBC的标准接口进行数据库操作,ShardingSphere会根据配置自动进行分片和读写分离。
    • 注意要点:确保分片键的选择合理,避免数据倾斜;注意数据迁移和扩容的问题;监控数据库连接池的状态,防止连接泄漏。