Engineering
Josh Long
April 29, 2020
speaker: Josh Long (@starbuxman)
Hi, Spring fans! Welcome to another installment of Spring Tips! In this installment, we’ll revisit two topics that we’ve addressed in two previous videos (distributed tracing and metrics collection) in terms of the superb Tanzu Wavefront observability platform.
The first video of the two videos, as mentioned above, dating way back in early 2017, looked at distributed tracing with spring cloud sleuth and openzipkin. Spring Cloud Sleuth is an abstraction for capturing the flow of messages from one node to another. It’s useful to help you see how messages move through a system. Spring cloud sleuth integrates with all the usual ingress and egress points in a Spring Boot application. Make an HTTP request using either the Restteplat or the reactive WebClient or Spring Cloud Feign? It works. Receive an HTTP request to a traditional (Servlet-based) or reactive HTTP endpoint built with Spring? It works. Send or receive a message using Spring Cloud Stream or Spring Integration? Yep. You guessed it. It just works. You don’t have to do anything, either.
Just add the Spring Cloud Sleuth starter to the classpath, and Spring Cloud Sleuth does the rest. It can, in turn, forward the information that it captures to an out-of-band trace server like OpenZipkin. Some even provide Zipkin-compatible proxies, like Google Cloud StackDriver trace. I like that last bit as it almost feels like we’ve gone full circle. Remember that Zipkin was inspired by, among other things, google ’s dapper whitepaper. It’s nice that we can, in turn, use Zipkin to talk to google cloud’s tracing infrastructure. Distributed tracing is ideal when you want to drill down into the specifics of a single request into, or out of, the system.
The second video from early 2018 looks at collecting metrics with Micrometer.
Micrometer is an abstraction that captures metrics - statistics - about your application that can then be made available from the spring boot actuator /actuator/metrics endpoint or forwarded to a time series database like Wavefront. Micrometer can also talk to other time-series databases like AppOptics, Azure Monitor, Netflix Atlas, CloudWatch, Datadog, Dynatrace, Elastic, Ganglia, Graphite, Humio, Influx/Telegraf, JMX, KairosDB, New Relic, Prometheus, SignalFx, Google Stackdriver, StatsD. Metrics are useful when you want to capture statistics - aggregate numbers about the frequency a given HTTP endpoint is hit, or an HTTP endpoint returns a particular status code or responds to a specific HTTP verb.
That was a quick recap. For a more in-depth look at both of these, I would refer you to the two referenced Spring Tips videos. That’s why they’re there! The beautiful thing about Wavefront is that you won’t interact with these project’s APIs in this installment because, as we’re about to see, the Wavefront Spring Boot integration jsut works. And this is no small surprise: the Spring Boot team worked hard on making the Wavefront integration work seamlessly. Wavefront has other integrations for tons of different platforms, runtimes, and projects, too.
NOTE: I’ve pasted together the seemingly endless list of other integrations supported into one ginormous screenshot that you can find at the bottom of this blog. It’ll be the image that’s like ten times longer in length than the blog itself.
Let’s build a new project using the Spring Initializr. You must use a build of Spring Boot greater than Spring Boot 2.3.M4. Select R2DBC, PostgreSQL, Reactive Web, Spring Cloud Sleuth and Lombok. Click Generate, unzip the resulting file. When I wrote this, it worked well enough to use Spring Cloud Hoxton SR3. No need for the snapshots. Also, we need to add the Wavefront starter itself. Add the following dependency to the pom.xml.
<dependency>
<groupId>com.wavefront</groupId>
<artifactId>wavefront-spring-boot-starter</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
The Wavefront Spring Boot starter is a SNAPSHOT dependency - it wouldn’t be a Spring Tips video if we didn’t dare to dance on the edge! At the time of this writing, the dependency is in the Sonatype SNAPSHOTS repository. I needed to have the following Spring and Sonatype repositories in my build. Who knows, though? Perhaps everything will be GA by the time you read this. Things move quickly in these bootiful parts!
<repositories>
<repository>
<id>sonatype-snapshots</id>
<name>Sonatype Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
That all done, import the project up in your favorite IDE.
The application is a typical reactive Spring Boot application, with which you have no doubt become familiar after watching so many other SPring Tips installments on functional reactive HTTP endpints, Spring Data R2DBC, testing reactive services, and more. Here’s the code.
package com.example.wavefront;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.annotation.Id;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
@SpringBootApplication
public class WavefrontApplication {
public static void main(String[] args) {
SpringApplication.run(WavefrontApplication.class, args);
}
@Bean
RouterFunction<ServerResponse> routes(ReservationRepository rr) {
return route()
.GET("/reservations", r -> ok().body(rr.findAll(), Reservation.class))
.GET("/hello", r -> ok().bodyValue("Hi, Spring fans!"))
.build();
}
@Bean
ApplicationRunner runner(ReservationRepository reservationRepository) {
return args -> {
var data = Flux
.just("A", "B", "C", "D")
.map(name -> new Reservation(null, name))
.flatMap(reservationRepository::save);
reservationRepository
.deleteAll()
.thenMany(data)
.thenMany(reservationRepository.findAll())
.subscribe(System.out::println);
};
}
}
interface ReservationRepository extends ReactiveCrudRepository<Reservation, String> {
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Reservation {
@Id
private String id;
private String name;
}
We’ll need to speicfy some configuration information for the PostgreSQL database in our src/main/resources/application.properties.
spring.r2dbc.url=r2dbc:postgresql://localhost/orders
spring.r2dbc.username=orders
spring.r2dbc.password=orders
We’ll also need to specify how our application identifies itself to Wavefront in src/main/resources/application.properties. Wavefront can observe multiple applications. An application, in turn, can have numerous services within it. An application name is a logical grouping of services. For our application, the name will be spring-tips, and the service name will be reservations.
wavefront.application.name=spring-tips
wavefront.application.service=reservations
Aaaaannd… that’s it! Start the application in your IDE or on the command line using mvn spring-boot:run. You’ll see that the application starts up and displays some information on the console, sort of like this.
…
To share this account, make sure the following is added to your configuration:
management.metrics.export.wavefront.api-token=58e749b5-ee60-4c0b-988e-458c6cb77b32
management.metrics.export.wavefront.uri=https://wavefront.surf
Connect to your Wavefront dashboard using this one-time use link:
https://wavefront.surf/us/cY69hp561D
…
Yep. That’s it. When the Wavefront Spring Boot starter starts up, it negotiates a token for your application. So your dashboard is already ready and waiting for you by the time the application starts up. The spring boot starter is even kind enough to capture the Wavefront token for you in ~/.wavefront_token. Subsequent runs will read that data for you. Or, you could use the Spring Boot properties printed out on the console, and it’ll defer to that, too.
you probably don’t want to have the token checked into your git repository. Instead, prefer environment variables or the Spring Cloud Config Server. Want to learn more about configuration? See this SPring tips video on configuration.
Note the last URL there for reference later on. But first, go to your browser and exercise some of the endpoints, http://localhost:8080/reservations and http://localhost:8080/hello. Invoke them both in the browser a half dozen times.
Now, go to that wavefront URL, and you should see a dashboard with the data for your application. If you don’t, then just wait a minute. IT takes a few minutes to see the data collected from your application.
You’ll immediately see that Wavefront has captured metrics about your application at both the application level - it knows, for example, about your HTTP requests, as well as at the JVM level, where it knows about things like your JVM’s memory use.
Click on one of those HTTP requests or go to Application > Traces, and you’ll be able to drill down into the traces for your application, like this. There is a ton of information there, too.
Everything I’ve shown you thus far is just what gets prepared for you out of the box. The real power is in the customization and the integrations. You can create custom dashboards to show all sorts of information that matters to you. Graph useful business indicators. Use plots, time series, and more. And, once you’ve figured out what the correct data to act on is, and figured out how to best contextualize data, then it’s trivial to install integrations to alert you when its time to act.
Speaking of integrations, I promised I’d show you some of the other integrations available. So, here it is, your moment of zen: the insane list of other integrations for the rare sort who is not Spring Boot (huh?):
Still here? …Why? Get! You’ve got places to be, production deploys to savor, growth to measure. Take what you’ve learned here today and integrate Wavefront into your application. If you’re using Tanzu Enterprise-ready Kubernetes Grid (Kubernetes), Tanzu Application Service (Cloud Foundry), or Azure Spring Cloud, then this should be an especially tantalizing opportunity. Finally, an observability platform that can scale like your Spring Boot-based microservices do. So, go. Go try out Wavefront. Get to production, faster, and safer.
comments powered by Disqus
translate:
翻译:
如上所述,这两个视频的第一个视频可以追溯到2017年初,它着眼于spring cloud sleuth和openzipkin的分布式跟踪。Spring Cloud Sleuth是一个抽象,用于捕获从一个节点到另一个节点的消息流。帮助您了解消息如何在系统中移动是很有用的。Spring cloud sleuth与Spring引导应用程序中所有常见的入口和出口点集成。使用Restteplat或reactive WebClient或Spring Cloud Feign发出HTTP请求?它起作用了。接收到用Spring构建的传统(基于Servlet)或反应式HTTP端点的HTTP请求?它起作用了。使用Spring云流或Spring集成发送或接收消息?是的。你猜对了。它只是起作用。你也不必做任何事。
只需将Spring Cloud Sleuth starter添加到类路径,剩下的由Spring Cloud Sleuth完成。反过来,它可以将捕获的信息转发给像OpenZipkin这样的带外跟踪服务器。有些甚至提供了与Zipkin兼容的代理,比如Google Cloud StackDriver trace。我喜欢这最后一点,因为它几乎感觉我们已经走了一个完整的循环。请记住,Zipkin的灵感来源于谷歌的时髦白皮书。很高兴我们可以反过来使用Zipkin与google云的跟踪基础设施进行对话。当您想要深入到系统中或系统外的单个请求的细节时,分布式跟踪是理想的选择。
2018年初的第二个视频着眼于用千分尺收集指标。
测微计是一个抽象,它捕获关于您的应用程序的度量-统计信息,然后可以从spring boot actuator/actuator/metrics端点获得,或者转发到Wavefront之类的时间序列数据库。测微计还可以与其他时间序列数据库进行对话,如AppOptics、Azure Monitor、Netflix Atlas、CloudWatch、Datadog、Dynatrace、Elastic、Ganglia、Graphite、Humio、Inflox/Telegraf、JMX、KairosDB、New Relic、Prometheus、SignalFx、Google Stackdriver、StatsD。当您想要捕获统计信息时,度量是很有用的—有关给定HTTP端点被击中的频率的聚合数字,或者HTTP端点返回特定的状态代码或响应特定的HTTP动词。
这是一个快速的概括。为了更深入地了解这两个方面,我将向您介绍两个参考的Spring提示视频。这就是他们来的原因!Wavefront的优点在于,在本期中您不会与这些项目的api交互,因为正如我们即将看到的,Wavefront Spring Boot集成jsut可以工作。这也不足为奇:Spring Boot团队努力使波前集成无缝工作。Wavefront还集成了大量不同平台、运行时和项目。
注意:我已经将看似无止境的其他集成列表粘贴到一个ginormous截图中,您可以在这个博客的底部找到它。这张图片的长度是博客本身的十倍。
让我们使用Spring初始化器构建一个新项目。您必须使用比SpringBoot2.3.M4更大的SpringBoot版本。选择R2DBC、PostgreSQL、Reactive Web、Spring Cloud Sleuth和Lombok。单击Generate,解压缩结果文件。当我写这篇文章的时候,使用SpringCloudHoxtonSR3已经足够好了。不需要快照。另外,我们还需要添加波前启动器本身。将以下依赖项添加到pom.xml中。
Wavefront Spring Boot starter是一个快照依赖项-如果我们不敢在边缘跳舞,它就不是Spring Tips视频!在编写本文时,依赖项位于Sonatype快照存储库中。我需要在我的构建中包含以下Spring和Sonatype存储库。但谁知道呢?也许你读到这篇文章的时候一切都会好起来的。在这些卑鄙的地方事情进展很快!
我们需要在src/main/resources/application.properties中为PostgreSQL数据库指定一些配置信息。
spring.r2dbc.url=r2dbc:postgresql://localhost/orders
spring.r2dbc.username=订单
spring.r2dbc.password=订单
我们还需要在src/main/resources/application.properties中指定应用程序如何将自己标识为Wavefront。波前可以观察多种应用。反过来,一个应用程序内部可以有许多服务。应用程序名是服务的逻辑分组。对于我们的应用程序,名称是spring tips,服务名称是reservations。
wavefront.application.name=弹簧头
wavefront.application.service=预订
啊!就是这样!使用mvn spring boot:run在IDE或命令行启动应用程序。您将看到应用程序启动并在控制台上显示一些信息,大致如下。