==1. Eureka-Server==
1.1 新建eureka-server項(xiàng)目蹋订,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
1.2 修改application.yml
1.2.1 單例
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
1.2.2 多例
---
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2/eureka/
---
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1/eureka/
1.3 添加注解
@EnableEurekaServer
==2. Eureka-Client==
2.1 對應(yīng)的服務(wù)中七嫌,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.2 修改application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
2.3 添加注解
@EnableEurekaClient
==3. Ribbon==
3.1 對應(yīng)的服務(wù)中描沟,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
3.2 修改application.yml
beebee-archives-thrift-consumer: # 服務(wù)提供者的名稱
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 負(fù)載均衡策略
3.3 啟動(dòng)類
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
3.4 添加工具類 EurekaUtil
@Configuration
public class EurekaUtil {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
/**
* 遠(yuǎn)程調(diào)用
* @param server 調(diào)用的服務(wù)器
* @param method 調(diào)用的方法
* @param p 方法的參數(shù)
*/
public <P> String remoteInvoke(String server, String method, P p) {
ServiceInstance serviceInstance = loadBalancerClient.choose(server);
return restTemplate.postForObject("http://" + serviceInstance.getServiceId() + method, p, String.class);
}
}
3.5 Controller調(diào)用
@PostMapping("/getList")
public String getList(ArchivesListParam param) {
return eurekaUtil.remoteInvoke(Server.BEEBEE_ARCHIVES_THRIFT_PROVIDER_CLIENT, Method.ARCHIVES_GET_LIST, param);
}
==4. Feign==
4.1 對應(yīng)的服務(wù)中切心,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
4.2 啟動(dòng)類添加注解
@EnableFeignClients
4.3 在service.impl下欺抗,添加 interface
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/api/v1/product/find")
String findById(@RequestParam("id") int id);
}
4.4 在OrderServiceImpl下使用
@Autowired
private ProductClient productClient;
String resp = productClient.findById(productId);
==5. Hystrix==
5.1 對應(yīng)的服務(wù)中墓毒,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
5.2 啟動(dòng)類添加注解
@EnableCircuitBreaker
5.3 OrderController使用
@Autowired
private StringRedisTemplate redisTemplate;
@RequestMapping("save")
@HystrixCommand(fallbackMethod = "saveOrderFail")
public Object save(int userId, int productId, HttpServletRequest request) {
Map<String, Object> data = new HashMap<>();
data.put("code", 0);
data.put("data", orderService.save(userId, productId));
return data;
}
private Object saveOrderFail(int userId, int productId, HttpServletRequest request) {
String saveOrderKey = "save-order";
String saveValue = redisTemplate.opsForValue().get(saveOrderKey);
String ip = request.getRemoteAddr();
new Thread(() -> {
if (StringUtils.isBlank(saveValue)) {
// TODO 調(diào)用短信接口 ip服務(wù)器宕機(jī),請盡快處理
redisTemplate.opsForValue().set(saveOrderKey, "save-order-fail", 30, TimeUnit.SECONDS);
} else {
// TODO 30s內(nèi)不再重發(fā)
}
}).start();
Map<String, Object> msg = new HashMap<>();
msg.put("code", -1);
msg.put("msg", "搶購人數(shù)太多包帚,您被寄出來了");
return msg;
}
==6. Feign 結(jié)合 Hystrix==
6.1 開啟Feign支持Hystrix
feign:
hystrix:
enabled: true
6.2 在fallback包下創(chuàng)建ProductClientFallback
@Component
public class ProductClientFallback implements ProductClient {
@Override
public String findById(int id) {
System.out.println("異常處理:記錄日志、發(fā)送短信或郵件");
return null;
}
}
6.3 在注解@FeignClient添加fallback類
@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
public interface ProductClient {
@GetMapping("/api/v1/product/find")
String findById(@RequestParam("id") int id);
}
==7. 斷路器Dashboard監(jiān)控儀表盤==
7.1 對應(yīng)的服務(wù)中曹质,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
7.2 啟動(dòng)類添加注解
@EnableHystrixDashboard
7.3 修改application.yml
management:
endpoints:
web:
exposure:
include: "*"
7.4 訪問入口
http://localhost:8781/hystrix
http://localhost:8781/actuator/hystrix.stream
7.5 斷路器圖示
斷路器close狀態(tài)
graph LR
consumer-->斷路器
斷路器-->provider
斷路器半開狀態(tài)
graph LR
consumer-.->斷路器
斷路器-->provider
斷路器open狀態(tài)
graph LR
consumer-.X.->斷路器
斷路器-->provider
==8. Zuul==
8.1 新建beebee-zuul項(xiàng)目婴噩,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
8.2 啟動(dòng)類添加注解
@EnableZuulProxy
8.3 訪問
之前:http://localhost:8781/api/v1/order/save?userId=1&productId=1
現(xiàn)在:http://localhost:9000/order-service/api/v1/order/save?userId=1&productId=1
訪問規(guī)則:http://ip:port/service-id/*
注意:order-service 注意大小寫,需要和application.yml配置的一樣
8.4 自定義路由
server:
port: 9000
spring:
application:
name: beebee-api
zuul:
routes:
order-service: /beebee-api/order/** # 自定義服務(wù)名稱
product-service: /beebee-api/product/** # 此名稱不要與上面沖突羽德,否則會(huì)覆蓋上面的
ignored-services: product-service # 忽略一個(gè)几莽,忽略商品服務(wù),不能通過 http://localhost:9000/product-service/... 訪問
ignored-patterns: /*-service/** # 忽略多個(gè)宅静,只能通過 http://localhost:9000/beebee-api/... 訪問
訪問方式:http://localhost:9000/beebee-api/api/v1/order/save?userId=1&productId=1
8.5 Http請求頭過濾問題
@ConfigurationProperties("zuul")
public class ZuulProperties {
// 默認(rèn)以下三個(gè)敏感信息不傳遞到下游服務(wù)器
private Set<String> sensitiveHeaders = new LinkedHashSet<>(Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
}
# 將此屬性置為空
zuul:
sensitive-headers:
8.6 zuul流程
過濾器order值越小章蚣,越優(yōu)先執(zhí)行
[圖片上傳失敗...(image-be497b-1551267407598)]
8.7 自定義zuul過濾器
在filter包下添加LoginFilter
@Component
public class LoginFilter extends ZuulFilter {
/**
* 過濾器類型,前置過濾器
* @return
*/
@Override
public String filterType() {
return PRE_TYPE;
}
/**
* 過濾器執(zhí)行順序姨夹,越小越先執(zhí)行
* @return
*/
@Override
public int filterOrder() {
return 4;
}
/**
* 過濾器是否生效
* @return
*/
@Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
// 或者ACL方式
if ("/beebee-api/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
return true;
}
return false;
}
/**
* 業(yè)務(wù)邏輯
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getHeader("token");
token = StringUtils.isEmpty(token) ? request.getParameter("token") : token;
// 登錄校驗(yàn)纤垂,實(shí)際使用改為JWT
if (StringUtils.isBlank(token)) {
context.setSendZuulResponse(false);
context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
}
8.8 訂單服務(wù)限流
在filter包下創(chuàng)建OrderRateLimitFilter類
@Component
public class OrderRateLimitFilter extends ZuulFilter {
// Guava:每秒產(chǎn)生1000個(gè)令牌,即每秒最多1000個(gè)請求
private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return -4;
}
@Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
// 只對訂單接口限流
if ("/beebee-api/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
return true;
}
return false;
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
if (!RATE_LIMITER.tryAcquire()) {
context.setSendZuulResponse(false);
context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
}
return null;
}
}
==9. Sleuth==
9.1 對應(yīng)的項(xiàng)目中磷账,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
9.2 XxxServiceImpl中使用
private final Logger logger = LoggerFactory.getLogger(getClass());
logger.info("order -- service");
2019-01-16 17:45:51.507 INFO [order-service,4fdff23615ab2226,d8818e5c8e6e5ba5,false] 8446 --- [derController-2] c.z.o.service.impl.OrderServiceImpl : order -- service
第一個(gè)值:order-service峭沦,spring.application.name的值
第二個(gè)值:4fdff23615ab2226,叫TraceID逃糟,用來標(biāo)識一條請求鏈路吼鱼,一條請求鏈路中包含一個(gè)TraceID,多個(gè)SpanID
第三個(gè)值:d8818e5c8e6e5ba5绰咽,叫SpanID菇肃,基本的工作單元,獲取元數(shù)據(jù)取募,如發(fā)送一個(gè)http
第四個(gè)值:false琐谤,是否要將該信息輸出到zipkin服務(wù)中來收集和展示。
==10. Zipkin==
10.1 web使用 Zipkin
docker run -d -p 9411:9411 openzipkin/zipkin
訪問:http://localhost:9411/zipkin/
10.2 對應(yīng)的服務(wù)中玩敏,添加pom依賴
這個(gè)依賴包含了 spring-cloud-starter-sleuth斗忌、spring-cloud-sleuth-zipkin
相應(yīng)的服務(wù)都要添加以下依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
10.3 修改application.yml
spring:
application:
name: order-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1 # 采樣百分比:開發(fā)環(huán)境=1即100%,生成環(huán)境用默認(rèn)的=0.1即10%
==11. Config==
11.1 新建config-server項(xiàng)目旺聚,添加pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
11.2 啟動(dòng)類添加注解
@EnableConfigServer
11.3 修改application.yml
spring:
application:
name: config-server
server:
port: 9100
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
11.4 碼云建立config-cloud項(xiàng)目
https://gitee.com/zhangyimai/config-cloud.git
11.5 修改application.yml
spring:
cloud:
config:
server:
git:
uri: https://gitee.com/zhangyimai/config-cloud
username:
password:
timeout: 5
11.6 在碼云config-cloud項(xiàng)目上飞蹂,新建product-service.yml文件
11.7 訪問方式
http://localhost:9100/product-service.yml
/{name}-{profiles}.properties
/{name}-{profiles}.yml
/{name}-{profiles}.json
/{label}/{name}-{profiles}.yml
name:服務(wù)器名稱
profile:環(huán)境名稱,開發(fā)翻屈、測試陈哑、生產(chǎn)
lable:倉庫分支、默認(rèn)master分支
11.8 config-client使用,product-service添加pom依賴
<!--配置中心客戶端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
11.9 修改application.yml為bootstrap.yml
# 服務(wù)名稱
spring:
application:
name: product-service
# 指定從哪個(gè)配置中心讀取
cloud:
config:
discovery:
service-id: CONFIG-SERVER # 服務(wù)ID
enabled: true
label: dev # dev分支惊窖,建議用label區(qū)分配置文件的環(huán)境
profile: dev # 配置文件后綴刽宪,不建議用profile區(qū)分配置文件的環(huán)境
# 注冊中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
此配置文件讀取的路徑:http://localhost:9100/dev/product-service-dev.yml
==12. Bus==
12.1 Docker安裝啟動(dòng)RabbitMQ
docker pull rabbitmq:management
docker run -d --name="myrabbitmq" -p 5671:5671 -p 15672:15672 rabbitmq:management
訪問:http://localhost:15672
用戶名密碼:guest
12.2 config-client添加pom依賴
<!--配置中心結(jié)合消息隊(duì)列-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
12.3 添加RabbitMQ等配置
在碼云config-cloud項(xiàng)目中,對應(yīng)的配置文件添加如下配置
# RabbitMQ連接信息
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#暴露全部的監(jiān)控信息
management:
endpoints:
web:
exposure:
include: "*"
12.4 需要刷新配置的類上添加注解
如需動(dòng)態(tài)刷新界酒,需要配置以下注解
@RefreshScope
12.5 動(dòng)態(tài)刷新配置
post方式請求:http://localhost:8773/actuator/bus-refresh
8773是當(dāng)前項(xiàng)目的端口圣拄,如果是多個(gè)節(jié)點(diǎn),其他節(jié)點(diǎn)也會(huì)刷新
注意:動(dòng)態(tài)刷新配置毁欣,在開發(fā)和測試環(huán)境使用庇谆,盡量少在生產(chǎn)環(huán)境使用
==13. 微服務(wù)改造為配置中心總結(jié)==
13.1 碼云上創(chuàng)建cloud-config項(xiàng)目,并添加對應(yīng)配置文件
微服務(wù)添加以下配置
# RabbitMQ連接信息
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#暴露全部的監(jiān)控信息
management:
endpoints:
web:
exposure:
include: "*"
13.2 微服務(wù)添加pom依賴
<!--配置中心客戶端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<!--配置中心結(jié)合消息隊(duì)列-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
13.3 application.yml --> bootstrap.yml
# 服務(wù)名稱
spring:
application:
name: product-service
# 指定從哪個(gè)配置中心讀取
cloud:
config:
discovery:
service-id: CONFIG-SERVER # 服務(wù)ID
enabled: true
label: dev # dev分支
profile: dev # 配置文件后綴
# 注冊中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
13.4 各個(gè)項(xiàng)目啟動(dòng)順序
1. 注冊中心
2. 配置中心
3. 各個(gè)服務(wù):商品服務(wù)凭疮、訂單服務(wù)...
4. 啟動(dòng)網(wǎng)關(guān)