基于Zookeeper运行独立的Lagom服务

本文讨论如何开发Lagom微服务,Lagom是一个集成了微服务、RESTful、CQRS、EventSoucring、Reactive编程等最潮概念的开发框架。介绍见:这里

微服务是必须结合服务定位器,在开发环境,Lagom的插件提供了out of box之外的服务定位器,在独立部署运行时,需要使用Zookeeper作为服务定位器。

下面展示如何使用Zookeeper作为服务定位注册器,然后打包运行一个Lagom微服务。

服务接口:


import com.lightbend.lagom.javadsl.api.Descriptor;
import com.lightbend.lagom.javadsl.api.Service;
import com.lightbend.lagom.javadsl.api.ServiceCall;

import static com.lightbend.lagom.javadsl.api.Service.named;
import static com.lightbend.lagom.javadsl.api.transport.Method.POST;

public interface HelloWorldService extends Service {

ServiceCall<String, String> sayHello();

@Override
default Descriptor descriptor() {

return named("helloWorld").withCalls(Service.restCall(POST, "/msg&amp", this::sayHello)).withAutoAcl(Boolean.TRUE);
}
}

服务实现:


import com.lightbend.lagom.javadsl.api.ServiceCall;

import static java.util.concurrent.CompletableFuture.completedFuture;

public class HelloWorldServiceImpl implements HelloWorldService {

@Override
public ServiceCall<String, String> sayHello() {
return request -> completedFuture("Hello" + request );
}
}

以上是我们的微服务业务,下面看看整合Zookeeper:
首先,加入zookeeper的实现到lagom服务中,在本地建立lagom-zookeeper-service-locator项目,在github上已经有这个项目模板,直接下载:
git clone https://github.com/jboner/lagom-service-locator-zookeeper.git

发布在本地:
> sbt publishLocal

一旦被发布后,我们得增加这个项目作为服务的依赖,打开build.sbt,加入下面一行:


libraryDependencies in ThisBuild += "com.lightbend.lagom" % "lagom-service-locator-zookeeper_2.11" % "1.0.0-SNAPSHOT"

现在,必须激活服务定位器,在服务配置application.conf中定义模块类,如何访问服务定位器zookeeper实例:


lagom {
discovery {
zookeeper {
server-hostname = "127.0.0.1" # hostname or IP-address for the ZooKeeper server
server-port = 2181 # port for the ZooKeeper server
uri-scheme =
"http" # for example: http or https
routing-policy =
"round-robin" # valid routing policies: first, random, round-robin
}
}
}

现在服务能和服务定位器一起工作了,但是还不能被定位,修改服务模块类保证这个服务能够被定位:

public class HelloWorldServiceModule extends AbstractModule implements ServiceGuiceSupport {

private Environment environment;

@Inject
public HelloWorldServiceModule(Environment environment, Configuration configuration) {
this.environment = environment;
}

@Override
protected void configure() {

bindServices(serviceBinding(HelloWorldService.class, HelloWorldServiceImpl.class));

if (environment.mode() == Mode.Prod()) {

try {
ZooKeeperServiceRegistry registry = new ZooKeeperServiceRegistry(
ZooKeeperServiceLocator.zkUri(),
ZooKeeperServiceLocator.zkServicesPath());
registry.start();

// create the service instance for the service discovery
// needs to be held on to to be able to unregister the service on shutdown
ServiceInstance<String> serviceInstance = ServiceInstance.<String>builder()
.name(
"helloWorld")
.id(
"helloWorldId")
.address(
"localhost")
.port(8080)
.uriSpec(new UriSpec(
"{scheme}://{serviceAddress}:{servicePort}"))
.build();

// register the service
registry.register(serviceInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

id参数是指向微服务的标识,name是微服务名称。
现在你的服务能够在独立方式下运行,下面看看如何打包并运行服务:

从sbt控制台打包:
> project helloWorld-imp

运行下面命令:
> dist

以独立方式启动服务:
/helloworld/helloWorld-impl/target/universal/

生成压缩包:helloworldimpl-[current_version].zip
其中包含所有元素。

解压:
unzip helloworldimpl-1.0-SNAPSHOT.zip

运行bin目录下脚本:
./helloworldimpl-1.0-SNAPSHOT/bin/helloworldimpl

现在你的Lagom服务已经启动。

通过zookeeper客户端zkCli.sh访问,通过下面命令获得所有服务信息:
get /lagom/services/helloWorld/helloWorldId

会得到:


{"name":"helloWorld","id":"helloWorldId","address":"localhost",
"port":8080,"sslPort":null,"payload":null,
"registrationTimeUTC":1474744298139,"serviceType":"DYNAMIC",
"uriSpec":{"parts":[{"value":"scheme","variable":true},
{
"value":"://","variable":false},
{
"value":"serviceAddress","variable":true},
{
"value":":","variable":false},{"value":"servicePort","variable":true}]}}


Run a Lagom service standalone with Zookeeper – Co