Cloud Foundry is an opinionated Platform-as-a-Service that allows you to manage applications at scale. This article is part of a series that explores different facets of a Cloud Foundry deployment using the spring-music project as an example.
This article is Part 3 of a series on Cloud Foundry concepts:
- Deploying the spring-music webapp, Part 1
- Persisting spring-music data using Postgres service, Part 2
- Scaling the spring-music webapp, Part 3
- Logging for the spring-music webapp, Part 4
- Monitoring the spring-music webapp, Part 5
Specifically in this article, we will horizontally and vertically scale up the spring-music application and show how this affects the routing and logging.
Previous articles in the series describe basic deployment of the spring-music application, and we pick up from there.
Vertical Scaling
The simplest method for scaling is vertical, adding memory/disk resources to a single instance of the application in order to accommodate more processing or simultaneous users. This can be done with the “cf scale” command.
If we have deployed spring-music as detailed in part 1 of this series, then we have a single instance already deployed:
$ cf apps Getting apps in org fleetest1 / space development as fabian.lee@test1.com... OK name requested state instancesmemory
disk urls spring-music started 1/11.2G
1G spring-music-monarchal-mass.cfapps.io
And that single instance is using ‘1G’ of memory (1024Mb). If we want to scale that up to 1280Mb:
$ cf scale spring-music -m 1280M -f $ cf apps Getting apps in org fleetest1 / space development as fabian.lee@test1.com... OK name requested state instancesmemory
disk urls spring-music started 1/11.2G
1G spring-music-monarchal-mass.cfapps.io
Now checking ‘cf apps’ again shows that there is 1.2G (1280Mb) available for this instance.
Note that this restarts the application, so any in-memory persistence will be lost.
Horizontal Scaling
Vertical scaling only goes so far before you need to horizontally scale, creating multiple instances of the application. Incoming requests are then distributed across the instances.
To increase the number of instances of our application, use the scale command with the ‘-i’ switch.
$ cf scale spring-music -m 1024M -i 2 -f $ cf apps Getting apps in org fleetest1 / space development as fabian.lee@test1.com... OK name requested stateinstances
memory disk urls spring-music started2/2
1G 1G spring-music-monarchal-mass.cfapps.io
Now we see “2/2” instances indicating we are running two instances of the same application, each using 1G of memory.
Incoming requests and GoRouter
The component that distributes the incoming requests to the available instances of the application is called the GoRouter. By default it uses round-robin load balancing, and it can itself be horizontally scaled in order to accommodate higher usage.
Typically, the GoRouter is fronted by a highly available load balancer like an F5 or AWS ELB depending on your supporting infrastructure.
You can get a map of the GoRouter’s URL to application definitions by using ‘cf routes’:
$ cf routes Getting routes for org fleetest1 / space development as fabian.lee@test1.com ... space host domain port path type apps service development spring-music-monarchal-mass cfapps.io spring-music
Instance serving the request
Now that we have two instances of the application, tail the logs of the spring-music application. First we will get the guid, which will make more sense in a second when we look at the log output.
$ cf app spring-music --guid 5fd9e495-029b-4758-b68f-d02be86d8517 $ cf logs spring-music
Press refresh on the main application screen in your browser several times. Requests to both instance #0 as well as instance #1 will be sent to your stdout.
This log output should look similar to the line below, with the ‘vcap_request_id’ being unique for each request, the ‘app_id’ being the guid of the application we retrieved earlier, and ‘app_index’ indicating which application instance served the request (#0 or #1).
2017-11-30T17:54:53.48-0500 [RTR/0] OUT spring-music-monarchal-mass.cfapps.io - [2017-11-30T22:54:53.476+0000] "GET /albums HTTP/1.1" 200 0 4678 "http://spring-music-monarchal-mass.cfapps.io/" "...<useragent>..." "10.10.2.186:50894" "10.10.149.149:61010" x_forwarded_for:"100.1.237.157, 10.10.2.186" x_forwarded_proto:"http" vcap_request_id:"fc7ac3f8-65ed-47c5-6be9-51f6a3378506" response_time:0.011157593app_id:"5fd9e495-029b-4758-b68f-d02be86d8517"
app_index:"0"
x_b3_traceid:"cfdfecf60080bae1" x_b3_spanid:"cfdfecf60080bae1" x_b3_parentspanid:"-"
The app_index will continually change as the GoRouter sends the request to either instance #0 or #1 of the spring-music application.
REFERENCES
https://docs.cloudfoundry.org/devguide/deploy-apps/cf-scale.html
https://docs.cloudfoundry.org/concepts/http-routing.html#round-robin
https://github.com/cloudfoundry/gorouter
https://github.com/cloudfoundry/gorouter#load-balancing (default_balancing_algorithm: round-robin|least-connection)
http://docs.pivotal.io/pivotalcf/1-12/concepts/high-availability.html (recommended # instances for HA)
https://www.cloudfoundry.org/routing-performance/
https://docs.cloudfoundry.org/adminguide/troubleshooting_slow_requests.html
https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html (common spring properties, can turn off ‘X-Application-Context’ header using ‘management.add-application-context-header=false)
https://www.dontpanicblog.co.uk/2017/04/14/spring-boot-actuator-trace/ (spring Boot actuator provides advanced logging and health)