As an outstanding PAAs platform in the industry, cloud foundry has made outstanding achievements in application scalability.
Specifically, when an application needs to be scaled horizontally, cloud foundry can easily help users do a good job of stretching, that is, to create multiple instances of an application, and the status of multiple instances is equal, multiple instances serve users, while multiple instances share the access pressure.
Generally speaking, it can be considered to share the access pressure together, but not all accesses to the application are balanced and distributed to different application instances. For example, when a cloud foundry user accesses an application, gorouter distributes requests to an instance of the application for the first access. However, if the user's subsequent access is stateful, you do not want the subsequent access to be distributed to other instances of the application. In response to the above situation, cloud foundry provides its own solution, using stickysession to ensure that requests are still distributed to the specified application instance.
This article analyzes how gorouter implements stickysession in cloud foundry.
This part requires a certain understanding of gorouter. For more information, see the author's previous blog post: gorouter source code analysis in cloud foundry.
About stickysession, gorouter's work is divided into two parts: how to add stickysession to the HTTP request, and how to identify the specific instance of the application through stickysession.
How to add stickysession to an HTTP request
When analyzing this problem, we need to raise another question: under what circumstances should we add stickysession to the HTTP request?
First, let's look at the go language implementation of setupstickysession:
func (h *RequestHandler) setupStickySession(endpointResponse *http.Response, endpoint *route.Endpoint) { needSticky := false for _, v := range endpointResponse.Cookies() { if v.Name == StickyCookieKey { needSticky = true break } } if needSticky && endpoint.PrivateInstanceId != "" { cookie := &http.Cookie{ Name: VcapCookieId, Value: endpoint.PrivateInstanceId, Path: "/", } http.SetCookie(h.response, cookie) }}
Next, check the code for when the setupstickysession method is called:
func (h *RequestHandler) HandleHttpRequest(transport *http.Transport, endpoint *route.Endpoint) (*http.Response, error) { h.transport = transport h.setupRequest(endpoint) h.setupConnection() endpointResponse, err := transport.RoundTrip(h.request) if err != nil { return endpointResponse, err } h.forwardResponseHeaders(endpointResponse) h.setupStickySession(endpointResponse, endpoint) return endpointResponse, err}
In the setupstickysession method, you can see that: first, enter a loop statement block. When the cookie in endpointresponse contains the name stickycookiekey, set the needsticky field to true and exit the loop. The answer is when to add stickysession to the HTTP request. For the stickycookiekey value, you can first check the gorouter settings:
const ( VcapCookieId = "__VCAP_ID__" StickyCookieKey = "JSESSIONID")
We can see that the value of stickycookiekey is JSESSIONID, while JSESSIONID is Tomcat's name for session ID, which is not necessarily JSESSIONID in other containers. Therefore, if the platform O & M personnel customize the buildpack of a container and the session ID in the container is not called JSESSIONID, the sticky session cannot be implemented in gorouter, unless you modify this part of content, or modify the container's name for the session ID.
In setupstickysession, a cookie is created for response through a judgment. The created cookie includes the name field, value field, and path field. Finally, HTTP. setcookie (H. Response, cookie) is used to add cookies to response settings.
After reading the implementation of the setupstickysession method, you can call the handlehttprequest method of this method. The main task of this method is to forward requests from the haproxy proxy to the application instance on the corresponding DEA, finally, construct the response information of the request and return the response information. Before returning the response information, gorouter sets stickysession for the response information.
The preceding section describes how to add a stickysession to an HTTP request. The following section describes how to identify an application instance through stickysession.
How to Use stickysession to identify the specific instance of an application when a request arrives at gorouter, gorouter must first identify whether the request contains stickysession information. If yes ,, gorouter analyzes the corresponding information in the request, obtains the information of the specified application instance, and forwards the request to the specified application instance. The specific implementation code is as follows:
func (p *proxy) lookup(request *http.Request) (*route.Endpoint, bool) { uri := route.Uri(hostWithoutPort(request)) // Try choosing a backend using sticky session if _, err := request.Cookie(StickyCookieKey); err == nil { if sticky, err := request.Cookie(VcapCookieId); err == nil { routeEndpoint, ok := p.registry.LookupByPrivateInstanceId(uri, sticky.Value) if ok { return routeEndpoint, ok } } } // Choose backend using host alone return p.registry.Lookup(uri)}
From the source code, we can see that the URI is extracted from the request first, and then the request is analyzed to determine whether the request carries stickycookiekey, that is, JSESSIONID. If yes, continue to analyze whether the request carries vcapcookieid, that is, _ vcap_id __. If yes, it indicates the stickysession supported by gorouter. Find the value corresponding to the value attribute from sticky, that is, apply privateinstanceid, use this ID to find the specific instance of the application, and then return the specific information of the application instance, including the IP Address: port of the instance. If the preceding stickycookiekey or vcapcookieid does not exist, that is, the request does not support stickysession. Then, you can use URI to search for an application instance to serve the request.
In cloud foundry, The gorouter supports and implements stickysession.
Indicate the source for reprinting.
This document is more out of my understanding and is certainly flawed and wrong in some places. I hope this article will be helpful to anyone who has access to gorouter in cloud foundry V2 to implement stickysession. If you are interested in this aspect and have better ideas and suggestions, please contact me.
My mailbox: [email protected]
Sina Weibo: @ lianzifu ruqing