As an outstanding PAAs platform in the industry, cloud foundry has made great achievements in application scalability.
In details, 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 together, and multiple instances share the renewal pressure.
Generally speaking, it is possible to share the pressure on the issue, but it is not balanced for all the questions of the application and distributed to different application instances. For example, when a cloud foundry consumer asks a user a question about the application, gorouter distributes the request to an instance of the application for the first time, however, if the user's subsequent renewal questions are stateful, they do not want the subsequent renewal questions to be distributed to other instances of the application. Cloud foundry provides its own solution based on the above situation. It uses 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 of content requires a certain understanding of gorouter, can refer to the author's previous blog: gorodry source code analysis in cloud Foundry
Gorouter's work on stickysession is divided into two parts: how to add HTTP requests? Stickysession: how to identify detailed instances of an application through stickysession.
How to add HTTP requests? Stickysession
When analyzing this problem, we need to raise another question: under what circumstances do we need to add HTTP requests? Stickysession?
First, let's look at the go language implementation of setupstickysession in this method:
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 an HTTP request? Stickysession. 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, and JSESSIONID is Tomcat's name for the session ID, which is not necessarily JSESSIONID in other containers. Therefore, if the platform O & M personnel define a container buildpack and the session ID in the container is not called JSESSIONID, the sticky session cannot be implemented in gorouter, unless you rewrite this part of content, or change the container's name for the session ID.
In setupstickysession, a cookie is created for response through an inference. The created cookie includes the name field, value field, and path field. Finally, through HTTP. setcookie (H. Response, cookie) to add the response settings? Cookie.
After reading the implementation of the setupstickysession method, we are now calling 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 in detail, 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.
How can I add HTTP requests? Stickysession. The following describes how to identify detailed instances of an application through stickysession.
How to Use stickysession to identify detailed application instances 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, finally obtains the information of the specified application instance, and forwards the request to the specified application instance. The detailed 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 see whether the request carries stickycookiekey, that is, JSESSIONID. If so, we can continue to analyze whether the request carries vcapcookieid, that is, _ vcap_id __. If yes, it indicates the stickysession supported by gorouter. Find the value attribute value from sticky, that is, apply privateinstanceid, the ID is used to find out which instance is corresponding to the application, and the detailed information of the application instance is returned. Of course, it includes 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.
Many others in this document, for my own understanding, must have shortcomings and errors in some places. I hope this article will be helpful to those who are using gorouter to implement stickysession in cloud foundry V2. If you are interested in this and have better ideas and suggestions, please contact me.
My mailbox: [email protected]
Sina Weibo: @ lianzifu ruqing