在vertx中跨顶点共享单例客户端的正确方法

Posted

技术标签:

【中文标题】在vertx中跨顶点共享单例客户端的正确方法【英文标题】:Correct way of sharing singleton clients across verticles in vetx 【发布时间】:2021-12-21 22:38:01 【问题描述】:

我有一个 vertx 应用程序,我在其中部署了多个 verticle A 实例 (HttpVerticle.java) 和多个 verticle B 实例 (AerospikeVerticle.java)。 Aerospike verticles 需要共享一个 AerospikeClient。 HttpVerticle 监听端口 8888 并使用事件总线调用 AerospikeVerticle。我的问题是:

    使用 sharedData 是共享单例客户端实例的正确方法吗?还有其他推荐/更清洁的方法吗?我计划在应用程序中创建和共享更多这样的单例对象(cosmos db 客户端、meterRegistry 等)。我计划使用 sharedData.localMap 以类似的方式共享它们。 是否可以使用 vertx 的事件循环作为 aerospike 客户端的支持事件循环?这样 aerospike 客户端初始化不需要创建自己的新事件循环?目前看起来 aerospike get 调用的 onRecord 部分在 aerospike 的事件循环上运行。
public class SharedAerospikeClient implements Shareable 
  public final EventLoops aerospikeEventLoops;
  public final AerospikeClient client;

  public SharedAerospikeClient() 
    EventPolicy eventPolicy = new EventPolicy();
    aerospikeEventLoops = new NioEventLoops(eventPolicy,  2 * Runtime.getRuntime().availableProcessors());
    ClientPolicy clientPolicy = new ClientPolicy();
    clientPolicy.eventLoops = aerospikeEventLoops;
    client = new AerospikeClient(clientPolicy, "localhost", 3000);
  

Main.java

public class Main 
  public static void main(String[] args) 
    Vertx vertx = Vertx.vertx();
    LocalMap localMap = vertx.sharedData().getLocalMap("SHARED_OBJECTS");
    localMap.put("AEROSPIKE_CLIENT", new SharedAerospikeClient());
    vertx.deployVerticle("com.demo.HttpVerticle", new DeploymentOptions().setInstances(2 * 4));
    vertx.deployVerticle("com.demo.AerospikeVerticle", new DeploymentOptions().setInstances(2 * 4));
  

HttpVerticle.java

public class HttpVerticle extends AbstractVerticle 

  @Override
  public void start(Promise<Void> startPromise) throws Exception 
    vertx.createHttpServer().requestHandler(req -> 
      vertx.eventBus().request("read.aerospike", req.getParam("id"), ar -> 
        req.response()
          .putHeader("content-type", "text/plain")
          .end(ar.result().body().toString());
        System.out.println(Thread.currentThread().getName());
      );
    ).listen(8888, http -> 
      if (http.succeeded()) 
        startPromise.complete();
        System.out.println("HTTP server started on port 8888");
       else 
        startPromise.fail(http.cause());
      
    );
  

AerospikeVerticle.java

public class AerospikeVerticle extends AbstractVerticle 
  private SharedAerospikeClient sharedAerospikeClient;

  @Override
  public void start(Promise<Void> startPromise) throws Exception 
    EventBus eventBus = vertx.eventBus();
    sharedAerospikeClient = (SharedAerospikeClient) vertx.sharedData().getLocalMap("SHARED_OBJECTS").get("AEROSPIKE_CLIENT");
    MessageConsumer<String> consumer = eventBus.consumer("read.aerospike");
    consumer.handler(this::getRecord);
    System.out.println("Started aerospike verticle");
    startPromise.complete();
  

  public void getRecord(Message<String> message) 
    sharedAerospikeClient.client.get(
      sharedAerospikeClient.aerospikeEventLoops.next(),
      new RecordListener() 
        @Override
        public void onSuccess(Key key, Record record) 
            if (record != null) 
              String result = record.getString("value");
              message.reply(result);
             else 
              message.reply("not-found");
            
        

        @Override
        public void onFailure(AerospikeException exception) 
            message.reply("error");
        
      ,
      sharedAerospikeClient.client.queryPolicyDefault,
      new Key("myNamespace", "mySet", message.body())
    );
  

【问题讨论】:

【参考方案1】:

我不知道 Aerospike 客户端。

关于verticles之间的共享对象,实际上共享数据映射就是为此目的而设计的。

但是,这样做更容易:

    在您的主类或自定义启动器中创建共享客户端 提供客户端作为verticle构造函数的参数

Vertx 接口有一个deployVerticle(Supplier&lt;Verticle&gt;, DeploymentOptions) 方法,在这种情况下很方便:

MySharedClient client = initSharedClient();
vertx.deploy(() -> new SomeVerticle(client), deploymentOptions);

【讨论】:

谢谢,这似乎更方便了。

以上是关于在vertx中跨顶点共享单例客户端的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

Vertx WebClient 在多个 Verticle 之间共享还是单一?

AngularJS 中跨域 REST 调用的正确架构模式是啥?

这是重用redis客户端的正确方法吗?

将文件从 REST Web 服务发送到客户端的正确方法是啥?

从 vertx 中的客户端证书中提取用户主体

服务器/客户端的共享错误号? [关闭]