主要有eureka做服务发现、config做分布式配置、zuul做api-gateway、feign做客户端负载均衡、hystrix做断路器、turbine做聚合的monitor、graphite做指标监控。
eureka
-
pom配置
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eureka-serverartifactId>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<scope>testscope>
dependency>
dependencies>
-
application.yml
server:
port: 8761
eureka:
instance:
hostname: discovery
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://discovery:${server.port}/eureka/
spring.cloud.config.discovery.enabled: true
-
bootstrap.yml
spring:
application:
name: discovery
-
application
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main( String[] args ) {
SpringApplication.run(EurekaApplication.class, args);
}
}
-
访问
http://192.168.99.100:8761/
config
-
pom配置
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-serverartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
dependencies>
-
application.yml
spring:
cloud:
config:
server:
native:
search-locations: classpath:/config
server:
port: 8888
-
bootstrap.yml
spring:
application:
name: config
profiles:
active: native
eureka:
instance:
preferIpAddress: true
client:
service-url:
defaultZone: http://discovery:8761/eureka/
-
application
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigApplication {
public static void main( String[] args ) {
SpringApplication.run(ConfigApplication.class,args);
}
}
-
访问
http://192.168.99.100:8888/review/default/master
feign实例
-
pom
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
<dependency>
<groupId>com.patterncatgroupId>
<artifactId>commonartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-ribbonartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-feignartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrix-dashboardartifactId>
dependency>
dependencies>
-
application.yml
server:
port: 9001
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
ribbon:
eureka:
enabled: true
-
bootstrap.yml
spring:
application:
name: product
cloud:
config:
uri: http://config:8888
encrypt:
failOnError: false
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://discovery:8761/eureka/
-
FeignClient
@FeignClient("recommend")
public interface RemoteRecommendService {
@RequestMapping(method = RequestMethod.GET,value = "/recommend")
public List getRecommendations(
@RequestParam(value = "productId", required = true) int productId) ;
}
-
feign使用
@RestController
public class ProductController {
private static final Logger LOG = LoggerFactory.getLogger(ProductController.class);
@Autowired
private SetProcTimeBean setProcTimeBean;
@Autowired
RemoteRecommendService remoteRecommendService;
@RequestMapping("/product/recommends")
@HystrixCommand(fallbackMethod = "callRecommendFallback", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100")
})
public List remoteRecommends(@RequestParam(value = "productId", required = true) int productId) {
return remoteRecommendService.getRecommendations(productId);
}
public List callRecommendFallback(int productId) {
return Collections.emptyList();
}
@RequestMapping("/product/{productId}")
public Product getProduct(@PathVariable int productId) {
int pt = setProcTimeBean.calculateProcessingTime();
LOG.info("/product called, processing time: {}", pt);
sleep(pt);
LOG.debug("/product return the found product");
return new Product(productId, "name", 123);
}
}
-
application
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrix
@EnableHystrixDashboard
public class ProductApplication {
private static final Logger LOG = LoggerFactory.getLogger(ProductApplication.class);
public static void main(String[] args){
SpringApplication.run(ProductApplication.class,args);
LOG.info("Register ShutdownHook");
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
LOG.info("Shutting down product service, unregister from Eureka!");
DiscoveryManager.getInstance().shutdownComponent();
}
});
}
}
api-gateway
-
pom
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zuulartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
-
application.yml
server:
port: 10000
#sidecar:
#port: 8000
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
zuul:
ignored-services: "*"
routes:
product:
path: /product/**
url: http://product:9001/product
recommend:
path: /recommend/**
url: http://recommend:9002/recommend
review:
path: /review/**
url: http://review:9003/review
-
bootstrap.yml
spring:
application:
name: gateway
cloud:
config:
uri: http://config:8888
encrypt:
failOnError: false
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://discovery:8761/eureka/
-
application
@SpringBootApplication
@EnableCircuitBreaker
@EnableDiscoveryClient
@EnableZuulProxy
public class ApiGatewayApplication {
public static void main( String[] args ) {
new SpringApplicationBuilder(ApiGatewayApplication.class).web(true).run(args);
}
}
-
访问
http://192.168.99.100:10000/recommend?productId=1
转向
http://192.168.99.100:9002/recommend?productId=1
hystrix
http://192.168.99.100:9001/product/recommends?productId=1
http://192.168.99.100:9001/hystrix
http://192.168.99.100:9003/hystrix/monitor?stream=http%3A%2F%2F192.168.99.100%3A9001%2Fhystrix.stream
turbine
-
pom
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-turbineartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrix-dashboardartifactId>
dependency>
dependencies>
-
application.yml
server:
port: 8889
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://discovery:8761/eureka/
turbine:
appConfig: product,review
clusterNameExpression: new String("default")
-
bootstrap.yml
spring:
application:
name: turbine
cloud:
config:
uri: http://config:8888
encrypt:
failOnError: false
-
application
@SpringCloudApplication
@EnableTurbine
@EnableHystrixDashboard
public class TurbineApplication {
public static void main(String[] args){
SpringApplication.run(TurbineApplication.class,args);
}
}
-
访问
http://192.168.99.100:9001/hystrix
http://192.168.99.100:9001/product/recommends?productId=1
http://192.168.99.100:9003/review/product/100
graphite配置
-
pom
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>io.dropwizard.metricsgroupId>
<artifactId>metrics-coreartifactId>
<version>${dropwizard-metrics.version}version>
dependency>
<dependency>
<groupId>io.dropwizard.metricsgroupId>
<artifactId>metrics-graphiteartifactId>
<version>${dropwizard-metrics.version}version>
dependency>
<dependency>
<groupId>io.dropwizard.metricsgroupId>
<artifactId>metrics-annotationartifactId>
<version>${dropwizard-metrics.version}version>
dependency>
<dependency>
<groupId>io.dropwizard.metricsgroupId>
<artifactId>metrics-jvmartifactId>
<version>${dropwizard-metrics.version}version>
dependency>
<dependency>
<groupId>com.ryantenney.metricsgroupId>
<artifactId>metrics-springartifactId>
<version>3.1.0version>
<exclusions>
<exclusion>
<artifactId>spring-beansartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
<exclusion>
<artifactId>spring-aopartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
exclusions>
dependency>
dependencies>
-
configuration
@Configuration
@AutoConfigureAfter(MetricRepositoryAutoConfiguration.class)
@ConditionalOnProperty(prefix = "graphite", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(GraphiteProperties.class)
@EnableScheduling
@EnableMetrics
public class GraphiteAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(GraphiteAutoConfiguration.class);
@Bean
public MetricsConfigurerAdapter metricsConfigurerAdapter(final GraphiteProperties graphiteProperties) {
return new GraphiteReportingManager(graphiteProperties);
}
/**
* https://qbgbook.gitbooks.io/spring-boot-reference-guide-zh/content/IV.%20Spring%20Boot%20features/36.3.3.%20Property%20conditions.html
* @param graphiteProperties
* @param metricRegistry
* @return
*/
@Bean
@ConditionalOnProperty(value = "graphite.host",matchIfMissing = true)
public ConsoleReporter consoleReporter(GraphiteProperties graphiteProperties,MetricRegistry metricRegistry) {
ConsoleReporter.Builder builder = ConsoleReporter.forRegistry(metricRegistry);
ConsoleReporter reporter = builder.build();
reporter.start(graphiteProperties.getReportInterval(), TimeUnit.MILLISECONDS);
return reporter;
}
}
-
report
public class GraphiteReportingManager extends MetricsConfigurerAdapter implements DisposableBean {
private final Logger logger = LoggerFactory.getLogger(getClass());
private GraphiteProperties props;
public GraphiteReportingManager(GraphiteProperties props) {
this.props = props;
}
@Override
public void configureReporters(MetricRegistry metricRegistry) {
//gc的metrics,目前看来每秒发送一次貌似太频繁,可以另起一个reporter进行
metricRegistry.register("jvm.gc", new GarbageCollectorMetricSet());
metricRegistry.register("jvm.mem", new MemoryUsageGaugeSet());
metricRegistry.register("jvm.thread-states", new ThreadStatesGaugeSet());
logger.info("graphite host:{},port:{}", props.getHost(), props.getPort());
GraphiteReporter reporter = GraphiteReporter.forRegistry(metricRegistry)
.prefixedWith(props.getPrefix())
// .convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.filter(MetricFilter.ALL)
.build(createSender(props));
registerReporter(reporter);
reporter.start(1L, TimeUnit.SECONDS);
}
@Override
public void destroy() throws Exception {
super.destroy();
}
private GraphiteSender createSender(GraphiteProperties props) {
switch (props.getSenderType()) {
case udp:
return new GraphiteUDP(props.getHost(), props.getPort());
case tcp:
return new Graphite(props.getHost(), props.getPort());
case pickled:
return new PickledGraphite(props.getHost(), props.getPort());
default:
return new GraphiteUDP(props.getHost(), props.getPort());
}
}
}
-
访问
http://192.168.99.100:8070/
参考
-
Blog Series - Building Microservices
-
git.blog-microservices
-
exposing-jvm-metrics-in-spring-boot
-
git.spring-boot-jvm-monitoring-demo
-
exporting-to-graphite-with-the-prometheus-java-client
https://segmentfault.com/a/1190000005142460