在Spring Cloud中以Eureka作为默认的服务注册中心。第一次接触微服务架构的时候都不太明白服务注册和服务发现这么几个概念,下面就简单的针对服务注册和服务发现作一些文字型的解释,然后在用代码实现一遍。
一、什么是服务注册
在服务治理的框架中,通常会有一个注册中心,每一个服务都会像服务注册中心注册自己的服务(就是告诉注册中心自己的 ip,端口号,版本号,通信协议等一些附加的信息)。比如说我们现在2个进程都提供支付服务(pay-service),它们分别运行192.168.0.180:8080,192.168.180.8081;还有1个进程提供订单服务(order-service),它运行在192.168.0.180:8082 上。当这些进程都启动的时候,就会把自己的服务注册到注册中心中。注册中心就会维护这些服务。服务中心以心跳连接的方式监测清单中的服务是否可用,如果不可用了就会将该服务从服务列表中剔除。
服务名称 | 位置 |
pay-service | 192.168.0.180:8080 192.168.180.8081 |
order-service | 192.168.0.180:8082 |
二、什么是服务发现
当服务治理的框架运行起来后,服务调用者要调用某一个服务的时候,不需要知道服务实例所在的具体位置。而是通过服务名称调用服务,在调用服务的时候需要向注册中心咨询服务,获取服务的实例清档,以实现对具体服务的访问。必须现在有一个服务A要想调用pay-service服务,服务A就会向注册中心发起咨询服务请求,注册中心把已经注册过的服务清单返回给服务A。这时服务A根据需要调用服务的名称(pay-service)就可以获取到 192.168.0.180:8080和192.168.0.180:8081这两个实例。在通过负载均衡的方式调用其中的某一个实例。
三、代码实现
项目结构:
eureka-server:注册中心
eureka-clietn:服务提供者
先搭建注册中心:
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.properties配置文件:
server.port=1111
eureka.client.fetch-registry=false
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.serverUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
eureka.client.fetch-registry=false: 注册中心不需要去检索服务,它只是维护服务实例
eureka.client.register-with-eureka=false ::在搭建服务注册中心的时候,避免服务注册中心把自己也注册进去
启动类:
@SpringBootApplication
@EnableEurekaServer //表明这是一个服务注册中心
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
以上服务的注册中心的服务就搭建好了启动项目:
会有一个security 的password,这是因为Spring boot 2.x以后以为了服务注册中心的安全,添加的配置。所以还要简单的配置一下security
WebSecurityConfig配置类:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
super.configure(http);
}
}
访问注册中心:localhost:1111
默认用户名为:user
默认密码就是上面截图中的passoword
可以看到,到此为止我们的服务注册中心已经搭建好了。
服务提供者搭建
Pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.1.5.RELEASE</version>
</dependency>
</dependencies>
application.properties配置文件:
server.port=8081
spring.application.name=pay-service
eureka.client.serviceUrl.defaultZone=http://user:注册中心启动的时候的密码@localhost:1111/eureka
启动类:
@SpringBootApplication
@EnableDiscoveryClient //表明这是一个服务提供者
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
启动完成后看到 pay-service 以及注册进注册中心了
来一个测试接口:
@RestController
public class HelloController {
private final Logger logger = Logger.getLogger(getClass()+"");
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String hello(){
ServiceInstance instance = discoveryClient.getLocalServiceInstance();
logger.info("/hello,host:"+instance.getHost()+", service_id"+instance.getServiceId()+"at port:"+instance.getPort());
return "hello World";
}
}
在搭建过程中遇到的一个问题总结:
com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:111) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.DiscoveryClient.register(DiscoveryClient.java:815) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.InstanceInfoReplicator.run(InstanceInfoReplicator.java:104) [eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.InstanceInfoReplicator$1.run(InstanceInfoReplicator.java:88) [eureka-client-1.4.10.jar:1.4.10]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_201]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_201]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_201]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_201]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_201]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_201]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]
2019-05-16 09:59:45.439 WARN 12100 --- [nfoReplicator-0] c.n.discovery.InstanceInfoReplicator : There was a problem with the instance info replicator
com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:111) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.DiscoveryClient.register(DiscoveryClient.java:815) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.InstanceInfoReplicator.run(InstanceInfoReplicator.java:104) ~[eureka-client-1.4.10.jar:1.4.10]
at com.netflix.discovery.InstanceInfoReplicator$1.run(InstanceInfoReplicator.java:88) [eureka-client-1.4.10.jar:1.4.10]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_201]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_201]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_201]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_201]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_201]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_201]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]
解决办法:
1.eureka-server 加上security的组件,如上文一样。
2.在eureka-client 的配置文件的url中加上连接注册中心的用户名和密码
希望以上的一些愚见可以帮助到大家。也希望大家可以多多指正我的错误。谢谢!