Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Vert.x With Zookeeper Service Discovery

DZone's Guide to

Vert.x With Zookeeper Service Discovery

Time for a lesson in service discovery! See how you can integrate Vert.x with Zookeeper by making use of service discovery.

· Microservices Zone ·
Free Resource

Learn why microservices are breaking traditional APM tools that were built for monoliths.

In this quick article, we’ll discuss the integration of Vert.x with Zookeeper.

Setup

1. Java 8

2. Zookeeper

3. IDE Eclipse/STS

4. Gradle

compile group: 'io.vertx', name: 'vertx-core', version: '3.5.0'
    compile group: 'io.vertx', name: 'vertx-web-client', version: '3.5.0'
    compile group: 'io.vertx', name: 'vertx-web', version: '3.5.0'
    compile 'io.vertx:vertx-service-discovery:3.5.0'
    compile 'io.vertx:vertx-service-discovery:3.5.0'
    compile 'io.vertx:vertx-service-discovery-backend-zookeeper-scala_2.12:3.5.0'
    compile group: 'io.vertx', name: 'vertx-rx-java', version: '3.5.0'


Vert.x Application

In this example, I am sending point-to-point messages based on Vert.x EventBus. The event bus supports publish/subscribe, point-to-point, and request-response messaging. The core concept of the event bus is allowing the different components of an application to interact using messages. For more details about EventBus, take a look at http://vertx.io/docs/vertx-core/java/#event_bus.

Publisher Verticle

PublisherVerticle: This component receives HTTP request messages and publishes them as messages to a designated address. In this example, we have to separate the designated addresses, i.e. STUDENT_ALL and STUDENT_BY_ID

@Override
public void start()throws Exception {
super.start();
        vertx.eventBus()
                .<String>consumer(STUDENT_BY_ID)
                .handler(getStudentById(studentService));

        vertx.eventBus()
        .<String>consumer(STUDENT_ALL)
        .handler(getStudentAllHandler(studentService));
}


ConsumerVerticle: This component listens for incoming messages and injects them as Spring Bean services.

The ConsumerVerticle component will keep listening to the event bus on an address (STUDENT_ALL and STUDENT_BY_ID). Once it receives a message, then it delegates it to the getStudentById, or getStudentAllHandler. In the getStudentById method, we are reading studentId from the header, and this header value is set in the PublisherVerticle’s getStudentById method.

private Handler <Message<String>> getStudentById(StudentService studentService) {
    return msg -> vertx. <String> executeBlocking(hf -> {
        String studentId = msg.headers().get(STUDENT_REQ_PARAM_NAME);
        try {
            hf.complete(studentService.getStudentBy(studentId));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            hf.fail(e);
        }
    }, rh -> {
        if (rh.succeeded()) {
            msg.reply(rh.result());
        } else {
            msg.reply(rh.cause().toString());
        }
    });
}

private Handler <Message<String>> getStudentAllHandler(StudentService studentService) {
    return msg -> vertx. <String> executeBlocking(hf -> {
        try {
            hf.complete(studentService.getAllStudent());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            hf.fail(e);
        }
    }, rh -> {
        if (rh.succeeded()) {
            msg.reply(rh.result());
        } else {
            msg.reply(rh.cause().toString());
        }
    });
}


Service Discovery

With microservices, location transparency can be addressed by a pattern called Service Discovery. For more details, check out these articles:

Zookeeper Discovery Publisher (Server Side)

In this simple implementation:

  • Create a service discovery setup to use discovery infrastructure (it requires a publisher and consumer)
  • Create a record for a Zookeeper's service provider
  • Publish this record to Zookeeper's service discovery

For more info, check out this article: https://dzone.com/articles/zookeeper-for-microservice-registration-and-discov

 private void publishStudentByIdToZookeeperRepo() {
     //creating record , to store details in zookeeper
      Record record=HttpEndpoint.createRecord("studentid-api-service", "localhost",
      9999,"/students");
   //creating service discovery for zookeeper
      ServiceDiscovery discovery= ServiceDiscovery.create(vertx, new ServiceDiscoveryOptions()
              .setBackendConfiguration(
                  buildZookeeperConnection()
              ));
      discovery.publish(record, r->{
      if(r.succeeded()) {
      LOG.info("successfully published to zookeeper>>>>> "+r.result().toJson());
      } else {
      r.cause().printStackTrace();
      }
      });
  }
//zookeeper configuration coming from yaml .
  private JsonObject buildZookeeperConnection() {
return new JsonObject()
      .put("connection", yamlConfiguration.getZookeeper().getConnect())
      .put("ephemeral", true)
      .put("guaranteed", true)
      .put("basePath", yamlConfiguration.getZookeeper().getBasePath());
  }


Zookeeper Discovery Lookup (Client Side)

In this simple implementation:

  • Create a service discovery to use service discovery infrastructure.
  • Create a filter for a lookup service in Zookeeper's service discovery.
  • Get the proxy client (HttpClient) and invoke the service.

Note: You must clean up the ServiceReference.

Example: ServiceDiscovery.releaseServiceObject(zookeeperDiscovery, client);

final Vertx vertx = Vertx.vertx();
//zookeeper serivce discovery creation 
 ServiceDiscovery zookeeperDiscovery= ServiceDiscovery.create(vertx, new ServiceDiscoveryOptions()
                .setBackendConfiguration(
                    new JsonObject()
                        .put("connection", "127.0.0.1:2181")
                        .put("ephemeral", true)
                        .put("guaranteed", true)
                        .put("basePath", "/services/my-api-backend")
                ));
 //creating json base filter. To lookup in zookeeper serive by name
 HttpEndpoint.getClient(zookeeperDiscovery, new JsonObject().put("name", "students-all"), ar -> {
  if (ar.succeeded()) {
                //proxy client
    HttpClient client = ar.result();
    if (ar.succeeded()) {
    System.out.println("Success");
    }

    client.getNow("/students/all", response -> {

      System.out.println("Status Code===="+response.statusCode());
      response.bodyHandler(bh->{
      System.out.println("Rec "+new String(bh.getBytes()));
                    //release service reference
      ServiceDiscovery.releaseServiceObject(zookeeperDiscovery, client);
      });


    });
  }
});


Service Class

The service class is a simple implementation that has two methods to retrieve student by id and retrieves all students as mock data.

@Service
public class StudentService {

    private List<Student> students=new ArrayList<>();
    private final ObjectMapper mapper = Json.mapper;
    @PostConstruct
    public void initMockStudents( ) {
        students.add(new Student(1,"student-1"));
        students.add(new Student(2,"student-2"));
        students.add(new Student(3,"student-3"));
        students.add(new Student(4,"student-4"));
        students.add(new Student(5,"student-5"));
    }
    public String getStudentBy(String id) throws JsonProcessingException {
        Optional<Student> result=students.stream().filter(s->s.getId().toString().equals(id)).findFirst();
        if (result.isPresent())
        return mapper.writeValueAsString(result.get());
        else
        return mapper.writeValueAsString(new Student());
    }
    public String getAllStudent() throws JsonProcessingException {
        return mapper.writeValueAsString(students);
    }
}


Deploying Verticles

We will be deploying the application, just the way we would do for a regular Spring Boot application. We have to create a Vert.x instance in the post construct method and set the publisher and consumer verticles in it.

@SpringBootApplication
@Configuration
@ComponentScan(basePackages = {"com.uppi.vertx.poc"})
public class VertxZookeeperSpringBootApplication {

    @Autowired
    private ConsumerVerticle consumerVerticle;
    @Autowired
    private PublisherVerticle publishVerticle;
    public static void main(String ...args) {
        SpringApplication.run(VertxZookeeperSpringBootApplication.class, args);
    }
    @PostConstruct
    public void deployVerticles() {
        Vertx vertx = Vertx.vertx();
        vertx.deployVerticle(publishVerticle);
        vertx.deployVerticle(consumerVerticle);

    }
}


You can find the code for this article on GitHub: https://github.com/upenderc/spring-vertx-poc.git

Record growth in microservices is disrupting the operational landscape. Read the Global Microservices Trends report to learn more.

Topics:
microservices ,vert.x ,zookeeper ,service discovery ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}