赞
踩
本篇博客有点长,个人觉得还是比较细致,希望对入手spring cloud的朋友能有所帮助
本来一直都想实践一下zookeeper的,但是看了一篇关于CAP的讨论之后,我还是选择Eureka作为服务发现与服务治理的软件。一个微服务项目需要的基础组件有Eureka/Config/Ribbon/Hystrix/Zuul和消息队列。不过ribbon和hystrix提供的服务可以由Feign代替。权衡之下,还是先使用ribbon加hystrix,弄明白其中的原理,在之后的项目中再去实践Feign。
用idea ,利用spring 官方提供的 spring initialzar 创建一个包含 EurekaServer 组件的spring boot项目。
然后在主程序中加入
@
E
n
a
b
l
e
E
u
r
e
k
a
S
e
r
v
e
r
@EnableEurekaServer
@EnableEurekaServer的注解,表示 启用 Eureka注册中心模块,本spring boot提供注册中心的服务。然后在配置中写入一下配置:
# 服务的端口号
server.port=8500
# 服务名称:在服务发现中,服务名称是一个关键信息,如果同一个服务名称有多个实例,那么,消费者在调用的时候就可以使用ribbon提供的负载均衡来调用
spring.application.name=server-register
# 是否向服务中心注册自己
eureka.client.register-with-eureka=false
# 是否需要检索服务
eureka.client.fetch-registry=false
eureka.instance.hostname=localhost
# web端访问地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
然后启动项目,访问 serviceUrl得到如下界面,现在里面的服务是空的,因为我们目前还没有向里面注册任何服务
根据我自己的项目需求,我创建了7个服务,商城服务、用户服务、数据库服务、商品推荐服务、交易服务、缓存服务、评价服务等 ,可能还会有消息队列的服务,数据库服务可能需要氛围 mysql的和 cockroachDB这两种,cockroachDB是分布式的,用于存储用户的浏览记录等,主要做后面的推荐做数据支撑。把创建好的服务全部定义到服务中心上面。所以再用 spring initialzar的方式创建七个服务,创建好之后,在每一个服务的主程序上面,加上注解 @ E n a b l e D i s c o v e r C l i e n t @EnableDiscoverClient @EnableDiscoverClient 。表示启用 Eureka客户端模块。目前spring cloud无法直接支持 cockroachdb,所以建一个spring boot的默认项目,然后构建项目就可以了。在每个客户端的配置文件中,设置如下:
spring.application.name=wupingtuijian-service
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/
server.port=8608
配置完成之后,首先打开 服务中心的服务,然后逐步打开其他服务。可以在服务中心的日志文件中查看到如下信息
这就是其他服务向服务中心注册的情况,打开web端管理界面
现在,我们来将 Eureka单机 -> Eureka 集群,实现高可用性。
利用 spring.profiles.active 属性 来构建集群,idea可以同时启动多个相同的服务,只需要在edit服务中取消单例即可,如图
具体的做法是,新建两个配置文件,命名为 application-xxx.properties的格式,
分别填入
server.port=8501
spring.application.name=server-register
#eureka.client.register-with-eureka=false
#eureka.client.fetch-registry=false
eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:8502/eureka/,http://localhost:8500/eureka/
反正和原配置一样,差不多改改端口之类的就行。
然后在 application.properties中设置 spring.propety.active 属性就可以了,如果不设置,默认加载 application.properties ,如果设置了,将打开设置的配置文件。于是,我创建了三个 Eureka服务,如下:
然后现在修改其他所有服务的配置项,使之能够注册到注册中心集群
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/
打开全部项目之后的效果如下:
服务注册中心搭好了。经过上面的配置,可以感受到改变一个地方,就需要改变大量的配置文件,为了避免这种不方便的方式,引入 spring-cloud 的 Config 服务。
用 spring initialzar创建一个具有 configserver组件和 EurekaServer组件的spring boot项目,在主程序中加入 @ E n a b l e D i s c o v e r y C l i e n t @EnableDiscoveryClient @EnableDiscoveryClient 和 @ E n a b l e C o n f i g S e r v e r @EnableConfigServer @EnableConfigServer 这两个注释分别表示启用服务注册客户端组件和启用配置服务组件。为了本地开发需要,我不使用默认的git配置的方式,而采取本地文件系统的方式。具体的例子如下:
@EnableDiscoveryClient
@EnableConfigServer
@SpringBootApplication
public class ConfigmanagerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigmanagerApplication.class, args);
}
}
application.properties
server.port=8400
spring.application.name=configmanager
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/
# 用 spring.profiles.active=native指明是用native的方式来构建的config的
spring.profiles.active=native
# 本地config的地址
spring.cloud.config.server.native.search-locations=D:/workspace/xinzu/nativeproperties
然后在其他服务中添加配置文件 bootstrap.properties
spring.application.name=user-service
server.port=8607
spring.cloud.config.uri=http://localhost:8400/
spring.cloud.config.label=master
spring.cloud.config.profile=dev
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/
对配置文件有特殊的命名要求,以我的模块为例子,应该在 D:/workspace/xinzu/nativeproperties 下面创建一个名为:
user-service-dev.properties 的配置文件,dev是标志,用 spring.cloud.config,profile 进行标记的。
在文件里面输入以下测试配置
nickName=minqixing
然后在 user项目中创建controller,来查询这个 nickName。项目代码如下
先来看看结构
config里面定义的swagger2的启动配置,关于swagger可以关注我的其他文章。
//UserApplication.class @ServletComponentScan @Configuration @EnableAutoConfiguration @EnableDiscoveryClient @ComponentScan({"com.xinzu.user"}) public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); } } //TestController.class @Api(value = "测试分布式环境是否可用", tags = {"测试springcloud环境"}) @Controller @RefreshScope public class TestController { @Value("${nickName}") private String nickName; @ApiOperation(value = "测试 springcloud config", notes = "测试 springcloud config") @RequestMapping(value = Path.TESTCONFIG, method = RequestMethod.GET) @ResponseBody public TestConfigDto getNickName(){ TestConfigDto dto = new TestConfigDto(); dto.setCode(200); dto.setInfo(nickName); return dto; } } // TestConfigDto.class public class TestConfigDto { private String info; private int code; public int getCode() { return code; } public String getInfo() { return info; } public void setCode(int code) { this.code = code; } public void setInfo(String info) { this.info = info; } }
题外话
spring boot有个很好的特性,省去了很多配置,我个人感觉可以让全民编程成为可能,哈哈。学会只要学会各种注释的使用方法就可以了。置于实现原理,才是真正的编程人员需要了解的。所以,我个人目前的打算也是先学会用,然后一步步的弄明白实现原理。
然后打开服务应该就成功了,注意,此处我省略了swagger的部分。
来看看现在Eureka中注册的服务:
我只打开了user-service这个服务,其他的服务现在测试就不需要打开了
下面是我的测试过程
springcloud config主要是能够帮助同一种服务能够统一配置,配置mysql用户名之类的东西。
实现了配置服务单点,肯定也要实现高可用。下面来说说如何实现高可用的配置服务中心
我们在 Eureka中通过服务名来访问到配置服务,而不是指定 ip:port 的方式,就可以实现配置服务中心高可用化了。
修改 User服务的配置文件
spring.application.name=user-service
server.port=8607
# 配置服务相关
#spring.cloud.config.uri=http://localhost:8400/
#spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=configmanager
# 服务发现相关
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/
这里我注释掉了通过url访问配置中心的方式,而是采取利用 Eureka 做服务发现,利用 configmanager 这个配置服务的服务名来做访问的。其他都不用改。修改待查找的配置文件里面的nickname的值
然后测试,结果如下
看起来现在咱们还是单点的,其实不然,只要使用 spring.profile.active 多创建几个configmananger的实例就可以了,目前我不这样做是因为,接下来将要介绍的是 负载均衡的内容,在没有讨论负载均衡的时候节点弄多了,效果不太好。
不过,目前我们的配置是只能加载一次,如果在运行的过程中想要改变配置,需要做以下配置
在项目中引入 actuator ,对 spring boot进行监控
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后在配置文件中加入:
# actuator
management.server.port=9001
#修改访问路径 2.0之前默认是/ 2.0默认是 /actuator 可以通过这个属性值修改
management.endpoints.web.base-path=/monitor
#开放所有页面节点 默认只开启了health、info两个节点
management.endpoints.web.exposure.include=*
#显示健康具体信息 默认不会显示详细信息
management.endpoint.health.show-details=always
这个模块的作用主要就是监听我们的spring boot项目,维护项目的运行情况,根据这样的配置,我们就可以使用 http://localhost:9001/monitor/health 来查看系统的健康状况。使用 http://localhost:9001/monitor/refresh来动态修改配置文件的更新。
测试一下
先测试一下 nickName当前的值
然后修改
使用 http://localhost:9001/monitor/refresh 的 post请求方法来动态加载更新
返回nickName说明nickName已经重新加载了,然后再在客户端查询nickName的值,发现已经改了
为了给大家做一个励志的榜样,我动态的把这句话补充完整
现在基本的架构已经有了,但是我们的Eureka的功能还没有用起来,除了configmanager使用了服务发现功能,其他服务都没有使用服务发现的功能,服务发现、负载均衡和服务治理是springcloud的关键之处。接下来先来说说服务发现。
在项目中加入ribbon,这是服务发现的时候,使用负载均衡的算法
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
然后,在主程序中这样写:
@ServletComponentScan @Configuration @EnableAutoConfiguration @EnableDiscoveryClient @ComponentScan({"com.xinzu.user"}) public class UserApplication { @Bean @LoadBalanced RestTemplate restTemplate(){ return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); } }
@LoadBalanced 这个注解就是使用了负载均衡
然后,我们改造 pingjiaservice这个服务,改造的代码如下,实际上就是实现了一个rest接口,让userservice来调用。
@RefreshScope @Controller public class TestController { @Value("${nickName}") private String nickName; @Value("${passWord}") private String passWord; @RequestMapping(value = Path.TEST_FUWUFAXIAN, method = RequestMethod.GET) @ResponseBody public Integer getnickName(){ int ans1 = Integer.parseInt(nickName); int ans2 = Integer.parseInt(passWord); return ans1 + ans2; } }
在userservice中创建一个方法来调用上面的controller
@ApiOperation(value = "测试服务发现", notes = "测试服务发现") @RequestMapping(value = Path.TESTCONSUMER, method = RequestMethod.GET) @ResponseBody public TestConfigDto getPingJia(){ TestConfigDto dto = new TestConfigDto(); dto.setCode(400); dto.setInfo("没有获取到"); try { String tmp = restTemplate.getForEntity("http://PINGJIA-SERVICE/testfuwufaxian", String.class).getBody(); tmp = tmp.replace("<Integer>",""); tmp = tmp.replace("</Integer>",""); Integer ans1 = Integer.parseInt(tmp); String nickName1 = nickName + ans1; dto.setCode(200); dto.setInfo(nickName1); }catch (Exception e){ System.out.println("出现了异常"); } return dto; }
启动被调用的服务,打开三个实例
然后在user这个服务的swagger ui界面上进行测试,发现结果如下。
至于那两个加起来的数字是多少,这是一个悬念,哈哈。
由于篇幅有限,关于服务容错保护,api网管服务这里就不进行配置了。等我项目做完了再来补坑。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。