要使用nacos,我们首先得下载它的服务端,下载地址https://github.com/alibaba/nacos/releases
根据你的Spring Cloud Alibaba版本来下载需要使用的版本
我这里是tar.gz的,下载完成后,解压,进入bin目录
执行sh startup.sh -m standalone
通过docker安装nacos服务端
docker pull nacos/nacos-server:1.1.3
docker run -d --name nacos -p 8848:8848 --env MODE=standalone nacos/nacos-server:1.1.3
然后通过浏览器访问http://127.0.0.1:8848/nacos/
此时界面如图所示
输入账号nacos,密码nacos后,进入管理界面
搭建一个Spring Cloud Alibaba项目,在父项目中,Springboot版本2.1.7,SpringCloud版本Greenwich.SR2,SpringCloudAlibaba版本2.1.1.RELEASE
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-cloud-alibaba.version>2.1.1.RELEASE</spring-cloud-alibaba.version>
<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>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在具体的子项目中放入如下依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
添加配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: user
启动项目,端口8080,在管理界面中可以看到
我们的项目已经被注册进来了。现在我们来建一个类似的项目,端口号8081,编写一个测试Controller,来查找之前的user项目。
@RestController
public class TestController {
/**
* 无论使用哪种注册中心(Eureka,Zookeeper,Consul),该DiscoveryClient是通用的
* 它是一个接口
*/
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/test")
public List<ServiceInstance> findUser() {
return discoveryClient.getInstances("user");
}
}
运行后,访问如下
如果user启动多个实例,这里也可以获取多个user的信息
现在我们在user模块中增加一个Controller,用另外一个模块使用RestTemplate来调用这个Controller.
@RestController
public class TestController {
@GetMapping("/find")
public String findStr() {
return "春秋一统";
}
}
在调用模块中使用RestTemplate来调用,我们之前发现在discoveryClient.getInstances("user")返回List中有一个uri的属性是我们需要的,我们再拼接上/find就是我们需要的Rest API。
@Slf4j
@Service
public class ConnectServer {
@Autowired
private DiscoveryClient discoveryClient;
private RestTemplate restTemplate = new RestTemplate();
@PostConstruct
public void trace() {
List<ServiceInstance> instances = discoveryClient.getInstances("user");
String targetUrl = instances.stream().map(instance -> instance.getUri().toString() + "/find")
.findFirst()
.orElseThrow(() -> new RuntimeException("当前没有实例"));
String result = restTemplate.getForObject(targetUrl, String.class);
log.info(result);
}
}
运行结果(部分日志)
2019-12-06 23:09:12.764 INFO 847 --- main o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 563 ms
2019-12-06 23:09:18.229 INFO 847 --- main c.cgc.cloud.nacos.service.ConnectServer : 春秋一统
2019-12-06 23:09:18.235 WARN 847 --- main c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
现在我们要整合Ribbon来负载均衡
先在调用模块加入我们需要的Apache HTTPClient依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
给RestTemplate增加连接池,连接次数和超时时间。再打上Ribbon特有的标签@LoadBalanced
@Configuration
public class RestTemplateConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager();
//连接池最大连接数
pollingConnectionManager.setMaxTotal(400);
pollingConnectionManager.setDefaultMaxPerRoute(200);
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setConnectionManager(pollingConnectionManager);
//连接次数
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));
HttpClient httpClient = httpClientBuilder.build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
httpClient);
// 超时时间
clientHttpRequestFactory.setConnectTimeout(5000);
clientHttpRequestFactory.setReadTimeout(5000);
clientHttpRequestFactory.setConnectionRequestTimeout(5000);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(clientHttpRequestFactory);
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
return restTemplate;
}
}
为了以示区别,我们在user模块中修改第二个实例的返回字符串
@RestController
public class TestController {
@GetMapping("/find")
public String findStr() {
return "战国一统";
}
}
在调用模块中增加测试Controller
@RestController
public class BalanceController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/trace")
public String trace() {
return restTemplate.getForObject("http://user/find", String.class);
}
}
启动调用模块
我们不断的点击刷新,它就会不断的出现春秋一统和战国一统返回字符串。
Nacos的环境配置
我们可以在命名空间中设置我们不同环境(比如开发,测试,线上等等)的配置,它们是相互隔离的,互不影响。
在项目中配置如下,加入我们现在要把项目配置到开发环境中
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 9257bc96-8af7-4737-9ce1-a63da2ba2af7
application:
name: user
这里需要注意的就是,我们在填写namespace的时候一定要配置它的命名空间ID,而不能配它的名称,比如dev。
项目启动后,我们可以看到我们的服务现在是在dev的服务列表中.
我们还可以配置它到集群中心
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 9257bc96-8af7-4737-9ce1-a63da2ba2af7
cluster-name: GuangZhou
application:
name: user
启动后,点击详情,可以看到
Nacos配置中心
pom
在子项目中添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
增加bootstrap.yml,添加如下配置(我这里是将tomcat改成了undertow,关于此处说明可以参考Feign HTTP连接的几点建议 )
Spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# namespace: 9257bc96-8af7-4737-9ce1-a63da2ba2af7
# cluster-name: GuangZhou
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
application:
name: user
profiles:
active: dev
server:
port: 8082
undertow:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
# 不要设置过大,如果过大,启动项目会报错:打开文件数过多
io-threads: 16
# 阻塞任务线程池, 当执行类似servlet请求阻塞IO操作, undertow会从这个线程池中取得线程
# 它的值设置取决于系统线程执行任务的阻塞系数,默认值是IO线程数*8
worker-threads: 256
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分,不要设置太大,以免影响其他应用,合适即可
buffer-size: 1024
# 是否分配的直接内存(NIO直接分配的堆外内存)
direct-buffers: true
在nacos服务台中进行如下操作
点+号,进入如下界面
然后填入数据
Data ID这里需要将Springboot的项目名称与开发环境名称用"-"连接用.yaml后缀名结尾,配置格式选择yaml,配置内容可以放入你对数据库连接,zipkin,mq,mybatis等等各种配置。
点发布返回后,就可以看到该配置列表
启动Springboot项目,从日志可以看到它会先把配置文件给拉取下来
2019-12-09 14:19:29.242 INFO user,,, 2129 --- main c.a.c.n.c.NacosPropertySourceBuilder : Loading nacos data, dataId: 'user-dev.yaml', group: 'DEFAULT_GROUP', data: logging:
level:
root: info
com.cloud: debug
file: logs/${spring.application.name}.log
spring:
zipkin:
base-url: http://192.168.1.219:9411
enabled: true
sender:
type: web
sleuth:
sampler:
probability: 1.0
生产环境的集群改造
nacos本身是使用derby来做数据持久化的,具体查看derby数据方式如下。
关闭nacos
sh shutdown.sh
使用IDEA来连接nacos,打开database工具,点+号
选择Derby(Embedded)
如果没有驱动的话,需要先下载驱动。
找到nacos安装目录/data/derby-data,使用用户名nacos,密码nacos,点Test Connection按钮,出现Successful,表示连接成功。
此后可以看到包含这样一些表的数据库
点开CONFIG_INFO表可以看到我们之前配置中心的配置信息
考虑到Derby的单节点性,生产环境需使用MySQL作为后端存储,因此需要搭建MySQL。生产中,MySQL建议至少主备模式,高可用MySQL更佳。关于高可用的mysql集群可以参考CentOS 7 Galera Cluster安装全攻略 ,主从的可以参考Docker安装mysql8主从结构 版本选择5.7就好。
生产环境部署架构图
这里5.7和8.0就在于他们的驱动不同。8.0的驱动下载地址为https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.16/mysql-connector-java-8.0.16.jar