This microservices branch was initially derived from AngularJS version to demonstrate how to split sample Spring application into microservices. To achieve that goal we used Spring Cloud Netflix technology stack.
Every microservice is a Spring Boot application and can be started locally using IDE or mvn spring-boot:run
command. Please note that supporting services (Config and Discovery Server) must be started before any other application (Customers, Vets, Visits and API).
Tracing server and Admin server startup is optional.
If everything goes well, you can access the following services at given location:
- Discovery Server - http://localhost:8761
- Config Server - http://localhost:8888
- AngularJS frontend (API Gateway) - http://localhost:8080
- Customers, Vets and Visits Services - random port, check Eureka Dashboard
- Admin Server (Spring Boot Admin) - http://localhost:9090
You can tell Config Server to use your local Git repository by using local
Spring profile and setting
GIT_REPO
environment variable, for example:
-Dspring.profiles.active=local -DGIT_REPO=/projects/spring-petclinic-microservices-config
All services including the AppDynamics Java Agent can be started with a start script:
Open a CMD and execute the script:
start_all_with_appdynamics.bat
.
The services can be stopped by closing the CMD.
Open a Terminal and execute the script:
start_all_with_appdynamics.sh
.
The services can be stopped by executing the following script:
stop_all.sh
The macOS users need to first perform following commands (see vishnubob/wait-for-it#15) in order to solve the problem of missing timeout
function on their OS:
brew install coreutils
alias timeout=gtimeout
Please also use the customized startup scripts for Mac.
In order to start entire infrastructure using Docker, you have to build images by executing mvn clean install -PbuildDocker
from a project root. Once images are ready, you can start them with a single command
docker-compose up
. Containers startup order is coordinated with wait-for-it.sh
script.
After starting services it takes a while for API Gateway to be in sync with service registry,
so don't be scared of initial Zuul timeouts. You can track services availability using Eureka dashboard
available by default at http://localhost:8761.
A JMX JMeter file for the Petclinic can be found inside the jmeter directory and is called pet_clinic_load_test.jmx
. The JMX file can be parameterized with the following parameters and their default values inside the brackets:
JHOST
- The host of the system under test (localhost)JPORT
- The port of the system under test (8080)JUSERS
- The number of users (3)JRAMPUP
- The rampup time in seconds (10)JINFLUXDB_HOST
- The influx database host (localhost)JLOOPCOUNT
- The number of iterations (30)JDURATION
- The duration of the test in seconds (100)JDELAY
- The delay of the thread creation in seconds (10000)
To start a JMeter load test use the following command:
jmeter -t jmx_file -n -JHOST="localhost" -JPORT="8080" -JUSERS=3
You can then access petclinic here: http://localhost:8080/
Our issue tracker is available here: https://github.com/spring-petclinic/spring-petclinic-microservices/issues
This project comes with a sample configuration exported from AppDynamics 4.3.8 (PetStore_AppDynamics_Application.xml)
The default sample runs on HSQLDB, which is often not recognized by AppDynamics out of the box. In order to add the monitoring you need to add node specific configurations:
jdbc-callable-statements=org.hsqldb.jdbc.JDBCCallableStatement
jdbc-connections=org.hsqldb.jdbc.JDBCConnection
jdbc-prepared-statements=org.hsqldb.jdbc.JDBCPreparedStatement
jdbc-statements=org.hsqldb.jdbc.JDBCStatement
Operation | Request | Method | AppDynamics BT matching |
---|---|---|---|
Home | / | URL equals / | |
List Owners | /api/customer/owners | GET | URL equals and type equals |
Register Owner | /api/customer/owners | POST | URL equals and type equals |
Select Owner / Edit Owner Screen | /api/gateway/owners/{id} or /api/customer/owners/{id} or /owners/{id} | GET | URL regex (/api/gateway|customer/owners/\d*|/owners/\d*), method equals |
Edit Owner | /api/customer/owners/{id} | PUT | URL regex /api/gateway/owners/\d*, method equals |
Show All Pets of Owner | api/customer/owners/{id}/pets | GET | URL regex /api/gateway/owners/\d*/pets, method equals |
Select Pet Of Owner | /api/customer/owners/{id}/pets/{pet-id} | GET | URL regex /api/gateway/owners/\d*/pets/\d*, method equals |
Edit Pet Of Owner | /api/customer/owners/{id}/pets/{pet-id} | PUT | URL regex /api/gateway/owners/\d*/pets/\d*, method equals |
Add Pet to Owner | /api/customer/owners/{id}/pets | POST | URL regex /api/gateway/owners/\d*/pets, method equals |
Show Visits | /api/visit/owners/{id}/pets/{pet-id}/visits | GET | URL regex /api/gateway/owners/\d*/pets/\d*/visits, method equals |
Add Visit | /api/visit/owners/{id}/pets/{pet-id}/visits | POST | URL regex /api/gateway/owners/\d*/pets/\d*/visits, method equals |
Show Vets | /api/vet/vets | GET | URL equals and type equals |
Get Pet Types | /api/customer/petTypes | GET | URL equals and type equals |
Part / Section | Identification |
---|---|
Templates | contains template.html |
Status Update | Method invocation on de.codecentric.boot.admin.registry.StatusUpdater.updateStatusForAllApplications() |
Health Check | /health |
Scripts | starts with /scripts |
Basically just changing the ootb configuration to only use the first part of the URI is enough to have a good first start.
For demonstration sake this example includes some information points as well. The idea is that for every pet type that is saved a unique information point is created.
Pets are saved in the class org.springframework.samples.petclinic.customers.web.PetResource in the method save. The save method takes as second parameter an instance of PetRequest, which provides a getTypeId() method returning the pet type There are six different pets: Cat (1), Dog (2), Lizard (3), Snake (4), Bird (5), Hamster (6)
This example can run locally. If it does not, please check the following:
The default configuration service (ConfigServer) gets the configurations from the internet. The setting is done at
spring-petclinic-appdynamics-demo/spring-petclinic-config-server/src/main/resources/bootstrap.yml
Note that a local configuration can be given. By default the local configuration expects that the configuration repository resides in your users home folder, but you can easily change that in the file.
You can tell Config Server to use your local Git repository by using local Spring profile and setting GIT_REPO environment variable, for example: -Dspring.profiles.active=local -DGIT_REPO=/projects/spring-petclinic-microservices-config
This example also provides a startup script that sets the spring.profiles to local
Sometimes (at least on Macs) the local name resolution of the services cannot be performed as they use the host name, which is not necessarily mapped to the loopback device. You can easily check this by navigating to the Eureka server and checking if you can reach the services:
http://localhost:8761/
If you cannot reach a registered service, note the logical it is invoked with and simply add an entry to your hosts file (/etc/hosts). If you are on Mac you can flush your DNS cache:
sudo /usr/bin/dscacheutil -flushcache
This extension includes some very simple performance problems on purpose to visualize how APM tools can detect these and show them to the user.
- Creating a new pet with the type Snake will impose a 1s delay. This is interesting if you have a look at the defined information points.
- Finding a customer with a customer ID that can be divided by 11 wil impose a 1s delay. The base setup only created 10 users, so these will all be fast.
- Vets have a performance problem that is increasing with load. A wait within synchronized block simulates synchronized work. With higher loads on the service, the problem will heavily increase. To showcase this problem there is a specialized load test available that heavily accesses the vets page.
- Please make sure to install the Lombok Plugin
In its default configuration, Petclinic uses an in-memory database (HSQLDB) which gets populated at startup with data. A similar setup is provided for MySql in case a persistent database configuration is needed. Note that whenever the database type is changed, the data-access.properties file needs to be updated and the mysql-connector-java artifact from the pom.xml needs to be uncommented.
You may start a MySql database with docker:
docker run -e MYSQL_ROOT_PASSWORD=petclinic -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:5.7.8
Spring Cloud components | Resources |
---|---|
Configuration server | Config server properties and Configuration repository |
Service Discovery | Eureka server and Service discovery client |
API Gateway | Zuul reverse proxy and Routing configuration |
Docker Compose | Spring Boot with Docker guide and docker-compose file |
Circuit Breaker | TBD |
Graphite Monitoring | TBD |
The issue tracker is the preferred channel for bug reports, features requests and submitting pull requests.
For pull requests, editor preferences are available in the editor config for easy use in common text editors. Read more and download plugins at http://editorconfig.org.