SlideShare una empresa de Scribd logo
1 de 33
Descargar para leer sin conexión
1
YOUR FUTURE,
OUR CHALLENGE.
MICROSERVICIOS CON
QUARKUS
SmartPills
v 1.00 ES - 1 de diciembre de 2023
Juan Antonio Jiménez Torres
Software Architect
2
Juan Antonio Jiménez
@_jjimenez
https://about.me/juan-antonio-jimenez-torres
+35
proyectos
+25 años
de experiencia
Arquitecto de Software
https://linkedin.com/in/juanantoniojimeneztorres/
3
4
Frameworks JVM microservicios compilados a nativo
Sep 2018
helidon.io
Oct 2018
micronaut.io
Dic 2019
quarkus.io
5
¿Nos equivocamos al elegir Quarkus hace 4 años? Nooo
6
Quarkus está centrado en el rendimiento
7
Mi experiencia trabajando con Quarkus
● no hay que aprender nada nuevo
● es Java estándar
● la intuición funciona
● es menos verboso que otros frameworks
● modo de desarrollo mvn quarkus:dev
○ live reload
○ testing continuo
○ zero configuración
● lenguaje basado en estándares
○ MicroProfile
○ SmallRye
● orientado a cloud (eventos, K8s, etc…)
● muy rápido
● muy liviano
● muy fácil hacer TDD con @InjectSpy
En resumen, es muy fácil y sencillo
8
Basado en estándares
SmallRye Mutiny SmallRye GraphQL
9
AWS Lambda
AWS Lambda SnapStart Configuration
AWS Lambda with RESTEasy Reactive…
Azure Functions
Azure Functions with RESTEasy Reactive…
Container Images
Deploying on OpenShift
Deploying to Google Cloud Platform (GCP)
Deploying to Heroku
Deploying to Microsoft Azure Cloud
Funqy
Funqy AWS Lambda Binding
Funqy Google Cloud Functions
Funqy HTTP Binding (Standalone)
Funqy HTTP Binding with AWS Lambda
Funqy HTTP Binding with Azure Functions
Funqy HTTP Binding with Google Cloud Functions
Funqy Knative Events Binding
Orientado a contenedor. Cloud Native. CNCF
Google Cloud Functions (Serverless)
Google Cloud Functions (Serverless) with RESTEasy Reactive…
Dev Services for Kubernetes
Kubernetes Client
Kubernetes Config
Kubernetes extension
Reading properties from Spring Cloud Config Server
Getting Started with SmallRye Stork
Using Stork with Kubernetes
Stork Reference Guide
Quarkus: crear function as a
service con Funqy y Knative
10
Arranque en JVM vs arranque en nativo
● en JVM arranca en unos 10s
● en nativo arranca en unos 200ms ¡¡¡50 veces más rápido!!!
Compilación a
Nativo
Nativo: Guía de
Referencia
11
Experiencia muy gratificante de desarrollo:
12
Modo desarrollo. mvn quarkus:dev
Arranca la aplicación, y se pueden hacer cambios sobre la marcha, que se
ven reflejados inmediatamente en la aplicación sin reiniciar.
Continuos testing
Cuando cambiamos código y se graba el fichero se detectan los cambios y
se pasan los test.
Configuración: %dev y %test
quarkus.datasource.db-kind=mysql
quarkus.datasource.jdbc.url=jdbc:mysql://server:3306/users
quarkus.datasource.jdbc.driver=com.mysql.cj.jdbc.Driver
%dev.quarkus.datasource.jdbc.url = jdbc:mysql://localhost:3306/users
%test.quarkus.datasource.db-kind=h2
%test.quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:test
%test.quarkus.datasource.jdbc.driver=org.h2.Driver
Getting Started
Continuous Testing
Continuous Testing y
compilación a nativo
Introducción a Quarkus
Introducción a Quarkus - II
13
devServices (testContainers "automágicos")
Si incluimos una extensión y no la configuramos, Quarkus iniciará
automáticamente el servicio en modo desarrollo y pruebas.
Esto utiliza testContainers bajo el capot, y necesitas tener docker (o podman)
¡¡¡Configuración 0 para empezar a desarrollar!!!
Dev Services and UI for OpenID Connect (OIDC)
Dev Services for AMQP
Dev Services for Apicurio Registry
Dev Services for Elasticsearch
Dev Services for Infinispan
Dev Services for Kafka
Dev Services for Kubernetes
Dev Services for Pulsar
Dev Services for RabbitMQ
Dev Services for Databases
DB2 (container)
Derby (in-process)
H2 (in-process)
MariaDB (container)
Microsoft SQL Server (container)
MySQL (container)
Oracle Express Edition (container)
PostgreSQL (container)
Dev Services
14
Todas las anotaciones son del
estándar de Java:
javax.ws.rs.GET
jakarta.ws.rs.GET;
1 Indicamos el Path del endpoint
2 Método GET devolverá la lista
3 Podemos obtener una fruta por su
nombre
4 y el nombre lo obtenemos como un
PathParam
5 Lo mismo para el método POST
Servicios REST
@Path("/fruits")
public class FruitResource {
private Map<String,Fruit> fruits;
@GET
public Map<String, Fruit> list() {
return fruits;
}
@GET
@Path("/{fruitName}")
public Fruit getFruit(@PathParam String name) {
return fruits.get(name);
}
@POST
public Map<String, Fruit> add(Fruit fruit) {
fruits.add(fruit.name, fruit);
return fruits;
}
}
RESTEasy Classic
1
2
3
4
5
15
Todas las entidades extienden de
PanacheEntity o
PanacheEntityBase
1 Active Record prefiere propiedades
públicas
2 es como el find de Hibernate
3 ejemplo de list()
4 ejemplo de find con where
5 lo mismo para el delete
Persistencia con Panache y Active Record
@Entity
public class Fruit extends PanacheEntity {
public String name;
public Integer kcal;
public String season;
public static Fruit find(String name){
return find("name", name).firstResult();
}
public static List<Fruit> findSeason(String season){
return list("season", season);
}
public static void deleteByName(String name){
delete("name", name);
}
}
ORM Panache
1
2
3
4
5
16
Uni es objeto de SmallRye Mutiny
1 la firma del método dice si es
reactivo o no. Uni<Fruit> en lugar
de Fruit
2 Multi es parecido a un stream de
Uni. Puede ir devolviendo varios a
medida que se van recuperando.
3 Hay que distinguir también entre
void y Uni<Void>
Mismo ejemplo en reactivo
@Entity
public class Fruit extends PanacheEntity {
public String name;
public Integer kcal;
public String season;
public static Uni<Fruit> find(String name){
return find("name", name).firstResult();
}
public static Multi<List<Fruit>> findSeason(String season){
return list("season", season);
}
public static Uni<Void> deleteByName(String name){
delete("name", name);
}
}
RESTEasy Reactive
1
2
3
Getting started with Reactive
SmallRye Mutiny
17
@Path("/receipts")
@RegisterRestClient(configKey = "receipts-api")
public interface ReceiptsService {
@GET
Receipt getById(@QueryParam("id") Integer id);
@GET
@Path("/ingredient/{name}")
@Produces(MediaType.APPLICATION_JSON)
List<Receipt> getByIngredient(@PathParam String name);
}
La especificación de RestClient es
de las más sencillas que hay.
1 Anotamos @RegisterRestClient
para indicar que esta interfaz es la
de un servicio REST ajeno a nuestro
micro. Y con configKey le damos
un alias
Uso de RestClient
Reactive Rest Client
1
#application.properties
receipts-api/mp-rest/url=https://receipts-api.acme.com
receipts-api/mp-rest/scope=javax.enterprise.context.RequestScoped
receipts-api/mp-rest/connectTimeout=1000
receipts-api/mp-rest/readTimeout=1000
%dev.receipts-api/mp-rest/url=http://localhost:8081
1
1
Classic Rest Client
Microservicio con REST y
MongoDB
18
CloudEvent es un estándar
1 inyectamos el ObjectMapper de
jackson para hacer
transformaciones
2 se recibe el evento como un POST
3 Se proyecto el CloudEvent sobre el
evento concreto que es
4 se valida
5 se invoca al servicio con el payload
Recibir CloudEvents desde Knative Event Broker
@Path("/fruit")
public class FruitResource {
@Inject
ObjectMapper mapper;
@Inject
FruitService fruitService;
@POST
public void manageFruitEvent(final CloudEvent event) {
FruitEvent payload = PojoCloudEventDataMapper
.from(mapper, FruitEvent.class)
.map(event.getData())
.getValue();
validatePayload(payload);
fruitService.manage(payload, event.getId());
}
}
CloudEvents
1
2
3
4
5
19
public class EventService {
@Inject
ObjectMapper mapper;
@Inject
@RestClient
BrokerService brokerService;
public void sendEvent(final FruitEvent event) {
CloudEvent cloudEvent = CloudEventBuilder.v1()
.withSource(URI.create(“/fruit”))
.withType(“com.acme.fruit”)
.withId(UUID.randomUUID().toString())
.withDataContentType(MediaType.APPLICATION_JSON)
.withData(PojoCloudEventData
.wrap(event, mapper::writeValueAsBytes))
.build();
brokerService.send(cloudEvent);
}
}
Enviamos un CloudEvent al broker
1 inyectamos el ObjectMapper de
jackson serializar el evento que se
quiere enviar
2 inyectamos el RestClient con el
broker-ingress
3 Construimos el CloudEvent con el
POJO del evento
4 Lo enviamos como un POST a
través del brokerService
Enviar CloudEvents a Knative Event Broker
TriggerMesh
1
2
3
4
20
SmallRye GraphQL sirve recursos
vía GraphQL
1 Solo por anotar con @GraphQLApi
es un endpoint GraphQL
2 inyectamos el servicio
3 Una query de consulta
4 Mutación de creación
5 Mutación de borrado
GraphQL API
@GraphQLApi
public class FruitResource {
@Inject
FruitService service;
@Query("allFruits")
@Description("Get all fruits")
public List<Fruit> getAllFruits() {
return service.getAllFruitts();
}
@Mutation
public Fruit createFruit(Fruit fruit) {
service.addFruit(fruit);
return fruit;
}
@Mutation
public Fruit deleteFruit(int id) {
return service.deleteFruit(id);
}
}
SmallRye GraphQL
1
2
4
5
3
Cliente SmallRye GraphQL
Quarkus: exponer una
interfaz GraphQL
21
Microprofile: Health
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
</dependency>
● /q/health/live - La aplicación está levantada y corriendo
● /q/health/ready - La aplicación está lista para servir request
● /q/health/started - Evento que se produce al arrancar
● /q/health - Acumula todos los health check provinientes de la aplicación
@Liveness
@ApplicationScoped
public class SimpleHealthCheck implements HealthCheck {
@Override
public HealthCheckResponse call() {
if (externalService.liveness()){
return HealthCheckResponse.up("Simple health check");
} else { … }
}
Simplemente por incluir la librería
quarkus-smallrye-health el
microservicio expone unos endpoints
con el liveness y readyness
necesarios, por ejemplo, para un
entorno de K8s.
En el bloque de abajo se pone un
ejemplo, por si nuestro microservicio
depende síncronamente de otro, y se
quiere añadir como su liveness al
nuestro, ya que dependemos de él.
SmallRye Health
22
Microprofile: Metrics (sabor SmallRye Metrics)
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-metrics</artifactId>
</dependency>
● /q/metrics - Métricas de la aplicación y los endpoints
1 Por defecto, si incluimos la librería,
se empiezan a recoger información
de todos lo endpoints, pero
podemos anotar con counted y
timed cualquier método, y definir
métricas custom
2 @timed es muy útil para tomar
métricas de cada a identificar
posibles problemas de rendimeinto
NOTA: ahora se ha deprecado en
favor de micrometer
SmallRye Metrics
@ApplicationScoped
@Path("/fruit")
public class FruitResource {
@Inject
FruitService fruitService;
@POST
@Counted(name = "ProcessFruitCount", displayName = "fruit.counted")
@Timed(name = "ProcessFruitTime", displayName = "fruit.timed")
public void processFruit (final CloudEvent event) {
FruitEvent fruitEvent = map(event);
fruitService.process(fruitEvent)
}
1
2
23
Microprofile: Metrics (sabor Micrometer)
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-micrometer</artifactId>
</dependency>
o
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
SmallRye Metrics y Micrometer satisfacen el estándar de Microprofile Metrics
De las librerías anteriores, la primera expone en /q/metrics. La segunda, además, exporta las métricas
a un colector de prometheus. Hay muchos otros posibles colectores de métricas. Sólo hay que incluir la
librería adecuada
Telemery Micrometer
● micrometer-registry-newrelic-telemetry
● micrometer-registry-otlp
● micrometer-registry-signalfx
● micrometer-registry-stackdriver
● micrometer-registry-statsd
● micrometer-registry-azure-monitor
● micrometer-registry-datadog
● micrometer-registry-graphite
● micrometer-registry-influx
● micrometer-registry-jmx
Para los desarrolladores es muy útil
tener la info en /q/metrics pero de
cara a la observavilidad es preferible
poder estudiar los datos en un
dahboard de Grafana u otro sistema
que convierta los números en
gráficos.
24
Microprofile: OpenTelemetry
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
Telemetry Micrometer
#application.properties
quarkus.application.name=myservice
quarkus.otel.exporter.otlp.traces.endpoint=http://server:4317
quarkus.otel.exporter.otlp.traces.headers=authorization=Bearer my_secret
quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId},
parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t)
%s%e%n
# Alternative to the console log
quarkus.http.access-log.pattern="...traceId=%{X,traceId} spanId=%{X,spanId}"
%dev.quarkus.log.console.json=false
%test.quarkus.log.console.json=false
%dev.quarkus.opentelemetry.enabled=false
1
1
2
3
4
5
1 Ruta al servidor que recolectará los
spans de OpenTelemetry vía gRPC
2 Cabecera de autorización por si el
colector está securizado
3 Formato de los LOGs con los spans
de OpenTelemetry.
4 En el modo de desarrollo y test
prefiero ver los LOGs en formato
normal.
5 En el modo desarrollo deshabilito
opentelemetry
25
@Path("/fruits")
public class FruitResource {
@POST
@Retry(maxRetries=3, delay=1000, maxDuration=5000)
@Fallback(fallbackMethod="fallbackHandleEvent")
public void add(final FruitEvent event) {
Fruit stored = Fruit.findById(event.name);
if (stored == null){
map.toEntity(event).persist();
}
}
public void fallbackHandleEvent(final FruitEvent event) {
…
}
En un entorno de microservicios es
normal implementar cierta
resiliencia ante los fallos
1 La anotación Retry permite indicar
cuantas veces, como espaciamos los
intentos, etc…
2 Podemos indicar un método de
fallback para el caso de que se
alcance el número de reintentos y no
se haya alcanzado el éxito
3 Loggear y ¿DLQ?
4 Implementa: retries, timeouts,
fallbacks y circuit breaker
FaultTolerance
SmallRye Fault Tolerance
1
3
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-fault-tolerance</artifactId>
</dependency>
2
26
RunOnVirtualThread
@Path("/fruits")
@RunOnVirtualThread
public class FruitResource {
private Map<String,Fruit> fruits;
@GET
public Map<String, Fruit> list() {
return fruits;
}
@GET
@Path("/{fruitName}")
public Fruit getFruit(@PathParam String name) {
return fruits.get(name);
}
@POST
public Map<String, Fruit> add(Fruit fruit) {
fruits.add(fruit.name, fruit);
return fruits;
}
}
Writing CRUD applications
using virtual threads
1
When Quarkus meets virtual
threads
Testing Virtual Thread
Application
Processing Kafka records on
virtual thread
Compiling virtual thread
applications into native
executables
Use virtual threads in REST
applications
Virtual thread support
reference
27
Accessing application properties with Spring Boot
properties API
Use Spring Boot’s @ConfigurationProperties in
place of MicroProfile Config annotations
Extension for Spring Data API
While you are encouraged to use Hibernate ORM
with Panache for your data layer, Quarkus provides a
compatibility layer for Spring Data JPA in the form of
the spring-data-jpa extension.
Extension for Spring Data REST
Spring Data REST simplifies the creation of CRUD
applications based on our Spring Data compatibility
layer.
Quarkus Extension for Spring Cache API
While you are encouraged to use the Cache
extension for your application-level caching, Quarkus
provides a compatibility layer for Spring Cache in the
form of the spring-cache extension.
Quarkus Extension for Spring DI API
While you are encouraged to use CDI annotations for
injection, Quarkus provides a compatibility layer for
Spring dependency injection in the form of the
spring-di extension.
Quarkus: módulos para Spring
Quarkus Extension for Spring Scheduling API
While you are encouraged to use the Scheduler or Quartz
extensions to schedule tasks, Quarkus provides a
compatibility layer for Spring Scheduled in the form of the
spring-scheduled extension.
Quarkus Extension for Spring Security API
While you are encouraged to use the Quarkus Security layer
to secure your applications, Quarkus provides a
compatibility layer for Spring Security in the form of the
spring-security extension.
Quarkus Extension for Spring Web API
While you are encouraged to use Jakarta REST annotations
for defining REST endpoints, Quarkus provides a
compatibility layer for Spring Web in the form of the spring-
web extension.
Reading properties from Spring Cloud Config Server
Quarkus provides a compatibility layer for Spring Cloud
Config in the form of the spring-cloud-config-client
extension.
28
Libros gratuitos
29
Este chat es muy útil. Hay varios canales.
● #dev es para el propio desarrollo de Quarkus
● #users es para las preguntas que hacen los
usuarios. Revisa el historial, porque tu pregunta
seguramente ha sido respondida con
anterioridad y si no, planteala, y verás como
alguien pronto te ayuda.
Comunidad
STACK OVERFLOW
Las guías están muy bien documentadas y cubren el
95% de los casos. Pero en ocasiones, necesitas
preguntar sobre algún comportamiento extraño, y el tag
de quarkus es ampliamente usado en Stack Overflow.
Hay un montón de gente revisando este tag dispuesta a
ayudarte.
QUARKUS ZULIP CHAT QUARKUS DEVELOPMENT MAILING LIST
Esta lista de correo es para los propios desarrolladores
de Quarkus, no es para preguntar dudas acerca del
funcionamiento. Pero es muy interesante estar suscrito
para conocer de primera mano, las decisiones que se
toman sobre el lenguaje, o ver las novedades de una y
otra release.
30
Quarkiverso
31
YouTube Quarkus Channel
32
¿Qué hemos aprendido de Quarkus?
Es muy liviano y consume muy pocos recursos
Ya sabes Quarkus
Es muy sencillo
Muy agradable para el desarrollador
Una documentación muy buena
Con una gran comunidad detrás
Turno de preguntas
33
.com

Más contenido relacionado

Similar a Quarkus microservicios compilados a nativo

Groovy&Grails: Cambia la forma de desarrollar tus aplicaciones web
Groovy&Grails: Cambia la forma de desarrollar tus aplicaciones webGroovy&Grails: Cambia la forma de desarrollar tus aplicaciones web
Groovy&Grails: Cambia la forma de desarrollar tus aplicaciones webParadigma Digital
 
Cambia la forma de desarrollar tus aplicaciones web con groovy y grails
Cambia la forma de desarrollar tus aplicaciones web con groovy y grailsCambia la forma de desarrollar tus aplicaciones web con groovy y grails
Cambia la forma de desarrollar tus aplicaciones web con groovy y grailsFátima Casaú Pérez
 
JavaScript no es Vietnam
JavaScript no es VietnamJavaScript no es Vietnam
JavaScript no es VietnamAlex Casquete
 
Orquestando microservicios como lo hace Netflix
Orquestando microservicios como lo hace NetflixOrquestando microservicios como lo hace Netflix
Orquestando microservicios como lo hace NetflixParadigma Digital
 
LabAndroid: Taller "Mi Primera Aplicación Android"
LabAndroid: Taller "Mi Primera Aplicación Android"LabAndroid: Taller "Mi Primera Aplicación Android"
LabAndroid: Taller "Mi Primera Aplicación Android"Alberto Ruibal
 
HackDay Java 9 Spanish version
HackDay Java 9 Spanish versionHackDay Java 9 Spanish version
HackDay Java 9 Spanish versionHillmerC
 
Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...
Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...
Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...Micael Gallego
 
Concurrency with Promise Style – Rayco Araña
Concurrency with Promise Style – Rayco ArañaConcurrency with Promise Style – Rayco Araña
Concurrency with Promise Style – Rayco ArañaDroidcon Spain
 
Curso de Desarrollo Web 2
Curso de Desarrollo Web 2Curso de Desarrollo Web 2
Curso de Desarrollo Web 2juliocombativo
 
Introducción a AngularJS
Introducción a AngularJS Introducción a AngularJS
Introducción a AngularJS Marcos Reynoso
 
Breve introducción práctica al DevOps - (es) 2021_03_18
Breve introducción práctica al DevOps -  (es) 2021_03_18Breve introducción práctica al DevOps -  (es) 2021_03_18
Breve introducción práctica al DevOps - (es) 2021_03_18Young Suk Ahn Park
 

Similar a Quarkus microservicios compilados a nativo (20)

Xamarin Forms y MVVM
Xamarin Forms y MVVMXamarin Forms y MVVM
Xamarin Forms y MVVM
 
Groovy&Grails: Cambia la forma de desarrollar tus aplicaciones web
Groovy&Grails: Cambia la forma de desarrollar tus aplicaciones webGroovy&Grails: Cambia la forma de desarrollar tus aplicaciones web
Groovy&Grails: Cambia la forma de desarrollar tus aplicaciones web
 
Cambia la forma de desarrollar tus aplicaciones web con groovy y grails
Cambia la forma de desarrollar tus aplicaciones web con groovy y grailsCambia la forma de desarrollar tus aplicaciones web con groovy y grails
Cambia la forma de desarrollar tus aplicaciones web con groovy y grails
 
JavaScript no es Vietnam
JavaScript no es VietnamJavaScript no es Vietnam
JavaScript no es Vietnam
 
Grails
GrailsGrails
Grails
 
Concurrencia en Java
Concurrencia en Java Concurrencia en Java
Concurrencia en Java
 
Orquestando microservicios como lo hace Netflix
Orquestando microservicios como lo hace NetflixOrquestando microservicios como lo hace Netflix
Orquestando microservicios como lo hace Netflix
 
Taller de Grails
Taller de GrailsTaller de Grails
Taller de Grails
 
LabAndroid: Taller "Mi Primera Aplicación Android"
LabAndroid: Taller "Mi Primera Aplicación Android"LabAndroid: Taller "Mi Primera Aplicación Android"
LabAndroid: Taller "Mi Primera Aplicación Android"
 
De zero a 100 con Spring Boot
De zero a 100 con Spring BootDe zero a 100 con Spring Boot
De zero a 100 con Spring Boot
 
HackDay Java 9 Spanish version
HackDay Java 9 Spanish versionHackDay Java 9 Spanish version
HackDay Java 9 Spanish version
 
Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...
Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...
Herramientas y plugins para el desarrollo de aplicaciones cloud native para K...
 
Concurrency with Promise Style – Rayco Araña
Concurrency with Promise Style – Rayco ArañaConcurrency with Promise Style – Rayco Araña
Concurrency with Promise Style – Rayco Araña
 
Evolución Android - DroidconMad 2014
Evolución Android - DroidconMad 2014Evolución Android - DroidconMad 2014
Evolución Android - DroidconMad 2014
 
Workshop Técnicas Replicacion I
Workshop Técnicas Replicacion IWorkshop Técnicas Replicacion I
Workshop Técnicas Replicacion I
 
Curso de Desarrollo Web 2
Curso de Desarrollo Web 2Curso de Desarrollo Web 2
Curso de Desarrollo Web 2
 
GWT
GWTGWT
GWT
 
Introducción a AngularJS
Introducción a AngularJS Introducción a AngularJS
Introducción a AngularJS
 
Enclausulamiento java
Enclausulamiento javaEnclausulamiento java
Enclausulamiento java
 
Breve introducción práctica al DevOps - (es) 2021_03_18
Breve introducción práctica al DevOps -  (es) 2021_03_18Breve introducción práctica al DevOps -  (es) 2021_03_18
Breve introducción práctica al DevOps - (es) 2021_03_18
 

Quarkus microservicios compilados a nativo

  • 1. 1 YOUR FUTURE, OUR CHALLENGE. MICROSERVICIOS CON QUARKUS SmartPills v 1.00 ES - 1 de diciembre de 2023 Juan Antonio Jiménez Torres Software Architect
  • 2. 2 Juan Antonio Jiménez @_jjimenez https://about.me/juan-antonio-jimenez-torres +35 proyectos +25 años de experiencia Arquitecto de Software https://linkedin.com/in/juanantoniojimeneztorres/
  • 3. 3
  • 4. 4 Frameworks JVM microservicios compilados a nativo Sep 2018 helidon.io Oct 2018 micronaut.io Dic 2019 quarkus.io
  • 5. 5 ¿Nos equivocamos al elegir Quarkus hace 4 años? Nooo
  • 6. 6 Quarkus está centrado en el rendimiento
  • 7. 7 Mi experiencia trabajando con Quarkus ● no hay que aprender nada nuevo ● es Java estándar ● la intuición funciona ● es menos verboso que otros frameworks ● modo de desarrollo mvn quarkus:dev ○ live reload ○ testing continuo ○ zero configuración ● lenguaje basado en estándares ○ MicroProfile ○ SmallRye ● orientado a cloud (eventos, K8s, etc…) ● muy rápido ● muy liviano ● muy fácil hacer TDD con @InjectSpy En resumen, es muy fácil y sencillo
  • 8. 8 Basado en estándares SmallRye Mutiny SmallRye GraphQL
  • 9. 9 AWS Lambda AWS Lambda SnapStart Configuration AWS Lambda with RESTEasy Reactive… Azure Functions Azure Functions with RESTEasy Reactive… Container Images Deploying on OpenShift Deploying to Google Cloud Platform (GCP) Deploying to Heroku Deploying to Microsoft Azure Cloud Funqy Funqy AWS Lambda Binding Funqy Google Cloud Functions Funqy HTTP Binding (Standalone) Funqy HTTP Binding with AWS Lambda Funqy HTTP Binding with Azure Functions Funqy HTTP Binding with Google Cloud Functions Funqy Knative Events Binding Orientado a contenedor. Cloud Native. CNCF Google Cloud Functions (Serverless) Google Cloud Functions (Serverless) with RESTEasy Reactive… Dev Services for Kubernetes Kubernetes Client Kubernetes Config Kubernetes extension Reading properties from Spring Cloud Config Server Getting Started with SmallRye Stork Using Stork with Kubernetes Stork Reference Guide Quarkus: crear function as a service con Funqy y Knative
  • 10. 10 Arranque en JVM vs arranque en nativo ● en JVM arranca en unos 10s ● en nativo arranca en unos 200ms ¡¡¡50 veces más rápido!!! Compilación a Nativo Nativo: Guía de Referencia
  • 12. 12 Modo desarrollo. mvn quarkus:dev Arranca la aplicación, y se pueden hacer cambios sobre la marcha, que se ven reflejados inmediatamente en la aplicación sin reiniciar. Continuos testing Cuando cambiamos código y se graba el fichero se detectan los cambios y se pasan los test. Configuración: %dev y %test quarkus.datasource.db-kind=mysql quarkus.datasource.jdbc.url=jdbc:mysql://server:3306/users quarkus.datasource.jdbc.driver=com.mysql.cj.jdbc.Driver %dev.quarkus.datasource.jdbc.url = jdbc:mysql://localhost:3306/users %test.quarkus.datasource.db-kind=h2 %test.quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:test %test.quarkus.datasource.jdbc.driver=org.h2.Driver Getting Started Continuous Testing Continuous Testing y compilación a nativo Introducción a Quarkus Introducción a Quarkus - II
  • 13. 13 devServices (testContainers "automágicos") Si incluimos una extensión y no la configuramos, Quarkus iniciará automáticamente el servicio en modo desarrollo y pruebas. Esto utiliza testContainers bajo el capot, y necesitas tener docker (o podman) ¡¡¡Configuración 0 para empezar a desarrollar!!! Dev Services and UI for OpenID Connect (OIDC) Dev Services for AMQP Dev Services for Apicurio Registry Dev Services for Elasticsearch Dev Services for Infinispan Dev Services for Kafka Dev Services for Kubernetes Dev Services for Pulsar Dev Services for RabbitMQ Dev Services for Databases DB2 (container) Derby (in-process) H2 (in-process) MariaDB (container) Microsoft SQL Server (container) MySQL (container) Oracle Express Edition (container) PostgreSQL (container) Dev Services
  • 14. 14 Todas las anotaciones son del estándar de Java: javax.ws.rs.GET jakarta.ws.rs.GET; 1 Indicamos el Path del endpoint 2 Método GET devolverá la lista 3 Podemos obtener una fruta por su nombre 4 y el nombre lo obtenemos como un PathParam 5 Lo mismo para el método POST Servicios REST @Path("/fruits") public class FruitResource { private Map<String,Fruit> fruits; @GET public Map<String, Fruit> list() { return fruits; } @GET @Path("/{fruitName}") public Fruit getFruit(@PathParam String name) { return fruits.get(name); } @POST public Map<String, Fruit> add(Fruit fruit) { fruits.add(fruit.name, fruit); return fruits; } } RESTEasy Classic 1 2 3 4 5
  • 15. 15 Todas las entidades extienden de PanacheEntity o PanacheEntityBase 1 Active Record prefiere propiedades públicas 2 es como el find de Hibernate 3 ejemplo de list() 4 ejemplo de find con where 5 lo mismo para el delete Persistencia con Panache y Active Record @Entity public class Fruit extends PanacheEntity { public String name; public Integer kcal; public String season; public static Fruit find(String name){ return find("name", name).firstResult(); } public static List<Fruit> findSeason(String season){ return list("season", season); } public static void deleteByName(String name){ delete("name", name); } } ORM Panache 1 2 3 4 5
  • 16. 16 Uni es objeto de SmallRye Mutiny 1 la firma del método dice si es reactivo o no. Uni<Fruit> en lugar de Fruit 2 Multi es parecido a un stream de Uni. Puede ir devolviendo varios a medida que se van recuperando. 3 Hay que distinguir también entre void y Uni<Void> Mismo ejemplo en reactivo @Entity public class Fruit extends PanacheEntity { public String name; public Integer kcal; public String season; public static Uni<Fruit> find(String name){ return find("name", name).firstResult(); } public static Multi<List<Fruit>> findSeason(String season){ return list("season", season); } public static Uni<Void> deleteByName(String name){ delete("name", name); } } RESTEasy Reactive 1 2 3 Getting started with Reactive SmallRye Mutiny
  • 17. 17 @Path("/receipts") @RegisterRestClient(configKey = "receipts-api") public interface ReceiptsService { @GET Receipt getById(@QueryParam("id") Integer id); @GET @Path("/ingredient/{name}") @Produces(MediaType.APPLICATION_JSON) List<Receipt> getByIngredient(@PathParam String name); } La especificación de RestClient es de las más sencillas que hay. 1 Anotamos @RegisterRestClient para indicar que esta interfaz es la de un servicio REST ajeno a nuestro micro. Y con configKey le damos un alias Uso de RestClient Reactive Rest Client 1 #application.properties receipts-api/mp-rest/url=https://receipts-api.acme.com receipts-api/mp-rest/scope=javax.enterprise.context.RequestScoped receipts-api/mp-rest/connectTimeout=1000 receipts-api/mp-rest/readTimeout=1000 %dev.receipts-api/mp-rest/url=http://localhost:8081 1 1 Classic Rest Client Microservicio con REST y MongoDB
  • 18. 18 CloudEvent es un estándar 1 inyectamos el ObjectMapper de jackson para hacer transformaciones 2 se recibe el evento como un POST 3 Se proyecto el CloudEvent sobre el evento concreto que es 4 se valida 5 se invoca al servicio con el payload Recibir CloudEvents desde Knative Event Broker @Path("/fruit") public class FruitResource { @Inject ObjectMapper mapper; @Inject FruitService fruitService; @POST public void manageFruitEvent(final CloudEvent event) { FruitEvent payload = PojoCloudEventDataMapper .from(mapper, FruitEvent.class) .map(event.getData()) .getValue(); validatePayload(payload); fruitService.manage(payload, event.getId()); } } CloudEvents 1 2 3 4 5
  • 19. 19 public class EventService { @Inject ObjectMapper mapper; @Inject @RestClient BrokerService brokerService; public void sendEvent(final FruitEvent event) { CloudEvent cloudEvent = CloudEventBuilder.v1() .withSource(URI.create(“/fruit”)) .withType(“com.acme.fruit”) .withId(UUID.randomUUID().toString()) .withDataContentType(MediaType.APPLICATION_JSON) .withData(PojoCloudEventData .wrap(event, mapper::writeValueAsBytes)) .build(); brokerService.send(cloudEvent); } } Enviamos un CloudEvent al broker 1 inyectamos el ObjectMapper de jackson serializar el evento que se quiere enviar 2 inyectamos el RestClient con el broker-ingress 3 Construimos el CloudEvent con el POJO del evento 4 Lo enviamos como un POST a través del brokerService Enviar CloudEvents a Knative Event Broker TriggerMesh 1 2 3 4
  • 20. 20 SmallRye GraphQL sirve recursos vía GraphQL 1 Solo por anotar con @GraphQLApi es un endpoint GraphQL 2 inyectamos el servicio 3 Una query de consulta 4 Mutación de creación 5 Mutación de borrado GraphQL API @GraphQLApi public class FruitResource { @Inject FruitService service; @Query("allFruits") @Description("Get all fruits") public List<Fruit> getAllFruits() { return service.getAllFruitts(); } @Mutation public Fruit createFruit(Fruit fruit) { service.addFruit(fruit); return fruit; } @Mutation public Fruit deleteFruit(int id) { return service.deleteFruit(id); } } SmallRye GraphQL 1 2 4 5 3 Cliente SmallRye GraphQL Quarkus: exponer una interfaz GraphQL
  • 21. 21 Microprofile: Health <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-smallrye-health</artifactId> </dependency> ● /q/health/live - La aplicación está levantada y corriendo ● /q/health/ready - La aplicación está lista para servir request ● /q/health/started - Evento que se produce al arrancar ● /q/health - Acumula todos los health check provinientes de la aplicación @Liveness @ApplicationScoped public class SimpleHealthCheck implements HealthCheck { @Override public HealthCheckResponse call() { if (externalService.liveness()){ return HealthCheckResponse.up("Simple health check"); } else { … } } Simplemente por incluir la librería quarkus-smallrye-health el microservicio expone unos endpoints con el liveness y readyness necesarios, por ejemplo, para un entorno de K8s. En el bloque de abajo se pone un ejemplo, por si nuestro microservicio depende síncronamente de otro, y se quiere añadir como su liveness al nuestro, ya que dependemos de él. SmallRye Health
  • 22. 22 Microprofile: Metrics (sabor SmallRye Metrics) <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-smallrye-metrics</artifactId> </dependency> ● /q/metrics - Métricas de la aplicación y los endpoints 1 Por defecto, si incluimos la librería, se empiezan a recoger información de todos lo endpoints, pero podemos anotar con counted y timed cualquier método, y definir métricas custom 2 @timed es muy útil para tomar métricas de cada a identificar posibles problemas de rendimeinto NOTA: ahora se ha deprecado en favor de micrometer SmallRye Metrics @ApplicationScoped @Path("/fruit") public class FruitResource { @Inject FruitService fruitService; @POST @Counted(name = "ProcessFruitCount", displayName = "fruit.counted") @Timed(name = "ProcessFruitTime", displayName = "fruit.timed") public void processFruit (final CloudEvent event) { FruitEvent fruitEvent = map(event); fruitService.process(fruitEvent) } 1 2
  • 23. 23 Microprofile: Metrics (sabor Micrometer) <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-micrometer</artifactId> </dependency> o <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-micrometer-registry-prometheus</artifactId> </dependency> SmallRye Metrics y Micrometer satisfacen el estándar de Microprofile Metrics De las librerías anteriores, la primera expone en /q/metrics. La segunda, además, exporta las métricas a un colector de prometheus. Hay muchos otros posibles colectores de métricas. Sólo hay que incluir la librería adecuada Telemery Micrometer ● micrometer-registry-newrelic-telemetry ● micrometer-registry-otlp ● micrometer-registry-signalfx ● micrometer-registry-stackdriver ● micrometer-registry-statsd ● micrometer-registry-azure-monitor ● micrometer-registry-datadog ● micrometer-registry-graphite ● micrometer-registry-influx ● micrometer-registry-jmx Para los desarrolladores es muy útil tener la info en /q/metrics pero de cara a la observavilidad es preferible poder estudiar los datos en un dahboard de Grafana u otro sistema que convierta los números en gráficos.
  • 24. 24 Microprofile: OpenTelemetry <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-opentelemetry</artifactId> </dependency> Telemetry Micrometer #application.properties quarkus.application.name=myservice quarkus.otel.exporter.otlp.traces.endpoint=http://server:4317 quarkus.otel.exporter.otlp.traces.headers=authorization=Bearer my_secret quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n # Alternative to the console log quarkus.http.access-log.pattern="...traceId=%{X,traceId} spanId=%{X,spanId}" %dev.quarkus.log.console.json=false %test.quarkus.log.console.json=false %dev.quarkus.opentelemetry.enabled=false 1 1 2 3 4 5 1 Ruta al servidor que recolectará los spans de OpenTelemetry vía gRPC 2 Cabecera de autorización por si el colector está securizado 3 Formato de los LOGs con los spans de OpenTelemetry. 4 En el modo de desarrollo y test prefiero ver los LOGs en formato normal. 5 En el modo desarrollo deshabilito opentelemetry
  • 25. 25 @Path("/fruits") public class FruitResource { @POST @Retry(maxRetries=3, delay=1000, maxDuration=5000) @Fallback(fallbackMethod="fallbackHandleEvent") public void add(final FruitEvent event) { Fruit stored = Fruit.findById(event.name); if (stored == null){ map.toEntity(event).persist(); } } public void fallbackHandleEvent(final FruitEvent event) { … } En un entorno de microservicios es normal implementar cierta resiliencia ante los fallos 1 La anotación Retry permite indicar cuantas veces, como espaciamos los intentos, etc… 2 Podemos indicar un método de fallback para el caso de que se alcance el número de reintentos y no se haya alcanzado el éxito 3 Loggear y ¿DLQ? 4 Implementa: retries, timeouts, fallbacks y circuit breaker FaultTolerance SmallRye Fault Tolerance 1 3 <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-smallrye-fault-tolerance</artifactId> </dependency> 2
  • 26. 26 RunOnVirtualThread @Path("/fruits") @RunOnVirtualThread public class FruitResource { private Map<String,Fruit> fruits; @GET public Map<String, Fruit> list() { return fruits; } @GET @Path("/{fruitName}") public Fruit getFruit(@PathParam String name) { return fruits.get(name); } @POST public Map<String, Fruit> add(Fruit fruit) { fruits.add(fruit.name, fruit); return fruits; } } Writing CRUD applications using virtual threads 1 When Quarkus meets virtual threads Testing Virtual Thread Application Processing Kafka records on virtual thread Compiling virtual thread applications into native executables Use virtual threads in REST applications Virtual thread support reference
  • 27. 27 Accessing application properties with Spring Boot properties API Use Spring Boot’s @ConfigurationProperties in place of MicroProfile Config annotations Extension for Spring Data API While you are encouraged to use Hibernate ORM with Panache for your data layer, Quarkus provides a compatibility layer for Spring Data JPA in the form of the spring-data-jpa extension. Extension for Spring Data REST Spring Data REST simplifies the creation of CRUD applications based on our Spring Data compatibility layer. Quarkus Extension for Spring Cache API While you are encouraged to use the Cache extension for your application-level caching, Quarkus provides a compatibility layer for Spring Cache in the form of the spring-cache extension. Quarkus Extension for Spring DI API While you are encouraged to use CDI annotations for injection, Quarkus provides a compatibility layer for Spring dependency injection in the form of the spring-di extension. Quarkus: módulos para Spring Quarkus Extension for Spring Scheduling API While you are encouraged to use the Scheduler or Quartz extensions to schedule tasks, Quarkus provides a compatibility layer for Spring Scheduled in the form of the spring-scheduled extension. Quarkus Extension for Spring Security API While you are encouraged to use the Quarkus Security layer to secure your applications, Quarkus provides a compatibility layer for Spring Security in the form of the spring-security extension. Quarkus Extension for Spring Web API While you are encouraged to use Jakarta REST annotations for defining REST endpoints, Quarkus provides a compatibility layer for Spring Web in the form of the spring- web extension. Reading properties from Spring Cloud Config Server Quarkus provides a compatibility layer for Spring Cloud Config in the form of the spring-cloud-config-client extension.
  • 29. 29 Este chat es muy útil. Hay varios canales. ● #dev es para el propio desarrollo de Quarkus ● #users es para las preguntas que hacen los usuarios. Revisa el historial, porque tu pregunta seguramente ha sido respondida con anterioridad y si no, planteala, y verás como alguien pronto te ayuda. Comunidad STACK OVERFLOW Las guías están muy bien documentadas y cubren el 95% de los casos. Pero en ocasiones, necesitas preguntar sobre algún comportamiento extraño, y el tag de quarkus es ampliamente usado en Stack Overflow. Hay un montón de gente revisando este tag dispuesta a ayudarte. QUARKUS ZULIP CHAT QUARKUS DEVELOPMENT MAILING LIST Esta lista de correo es para los propios desarrolladores de Quarkus, no es para preguntar dudas acerca del funcionamiento. Pero es muy interesante estar suscrito para conocer de primera mano, las decisiones que se toman sobre el lenguaje, o ver las novedades de una y otra release.
  • 32. 32 ¿Qué hemos aprendido de Quarkus? Es muy liviano y consume muy pocos recursos Ya sabes Quarkus Es muy sencillo Muy agradable para el desarrollador Una documentación muy buena Con una gran comunidad detrás Turno de preguntas