App Engine

Traffic Splitting

Traffic splitting takes incoming requests to your app’s default module and splits them among the default version and one or more other versions, according to a distribution that you specify. Traffic splitting allows you to roll out features for your app slowly over a period of time. It can also be used for A/B Testing. When you deploy a new version of your default module, you can use traffic migration to re-route requests gradually between the existing default version and the newly deployed version.

  1. Enabling traffic splitting
  2. Splitting traffic by IP addresses or cookies
  3. Caching and traffic splitting

Enabling traffic splitting

To enable traffic splitting, select the Versions tab in the Admin Console, and expand the Traffic Splitting section.

Choose whether to split the traffic by IP address or cookie, then click Add Traffic Split and specify percentages for one or more of the non-default versions that appear in the Version pull down menu.

The sum of all the percentages must be less than 100%. Requests to the default module are routed proportionally to the versions according to the percentages you supplied, the remaining traffic will go to the default version. Requests to a URL that specifies a version are not split, they are sent directly to the version - whether or not it is included in the traffic split.

For example, imagine an app named myapp with a default module that has four versions: red, blue, green, and gold. Let's say gold is the default version. You can specify that 10% of the traffic goes to blue, and 20% to red. The remaining 70% will be sent to gold. Requests to the URLs myapp.appspot.com or default.myapp.appspot.com will be split 10/20/70 to blue, red, and gold respectively. Since you ignored green, that version will not receive any traffic. Requests to a URL that specifies a version (like gold.myapp.appspot.com) go straight to that version.

Splitting traffic by IP addresses or cookies

You may choose only one method for splitting traffic per version of your app:

  • IP address. Users are routed to the app version based on their IP address.
  • Cookie. Users are routed to the app version based on an HTTP cookie.

IP address splitting is easier to set up, but delivers less precise and detailed statistics. For example, if you ask for 5% of traffic to be delivered to an alternate version, you may get a range of 3–7%. Because it is the easiest to use, IP splitting is the default setting in the Administration Console.

Cookie splitting gives you finer control, and more accurate traffic splitting. However, it is more difficult to set up than IP address-based traffic splitting.

Splitting traffic using IP address

IP splitting requires less effort to manage, because it is based simply on the user's IP address. When the application receives an address, it hashes the IP address of that request to a value between 0–999. This value determines which version a user is routed to.

IP address splitting has some significant limitations:

  • Randomization Effects. Because IP addresses are independently assigned to versions, the resulting traffic split will differ somewhat from what you specify. However, the more traffic that your application receives, the more accurate the split will be, due to the Law of Large Numbers.
  • IP addresses change. IP addresses are reasonably sticky, but are not permanent. Users connecting from cell phones may have a shifting IP address throughout a single session. Similarly, a user on a laptop may be moving from home to a cafe to work, and hence also shifting through IP addresses. As a result, the user may have an inconsistent experience with your app as their IP address changes.
  • Internal requests don't work. Requests sent to your app from outside of Google's cloud infrastructure will work normally. However, requests sent from your app to another app (or to itself) are not sent to a version because they all originate from the a small number of IP addresses. This applies to any traffic between apps within Google's cloud infrastructure. If you need to send requests between apps, use cookie splitting instead.

Splitting traffic using cookies

Cookie splitting works by using HTTP cookies to assign users a value between 0–999. This approach makes it much easier to get an accurate assignment of users to versions, and hence we allow smaller slices of traffic (as small as 0.1%). Cookie splitting also has some limitations:

  • Cookie management is required for mobile or desktop apps. If you are writing a mobile app or a desktop client of some kind, then it will need to manage cookies. When App Engine sends back a Set-Cookie header, you need to store this cookie and send it with each subsequent request. Browser-based apps work fine, as browsers automatically manage cookies.
  • Internal requests require extra work. Requests sent from your app server-side to another app (or to itself) can be sent into a version, but doing so requires you to forward the user's cookie as part of the request. However, internal requests that don't originate from the user are not recommended for versions.

Setting the cookie

The cookie is set for you automatically. The cookie App Engine uses for traffic splitting is GOOGAPPUID, and its range of valid values is 0–999. This cookie is set to a random valid value if and only if the following are true:

  • Your app is configured to use cookie splitting.
  • The HTTP request from the user does not already contain the GOOGAPPUID cookie.
  • The response from your app does not already contain a Set-Cookie: GOOGAPPUID=... header. This allows your app to control which version a user gets.

Caching and traffic splitting

When using Traffic Splitting, you need to treat cached resources carefully. The cached versions of static and dynamic resources can create an inconsistent user experience or unanticipated application behavior between versions. Caching issues exist for all apps, but traffic splitting will make subtle flaws in caching much more apparent.

You can avoid this problem for dynamic resources by setting the Cache-Control and Expires headers. These headers indicate to proxies that the resource is dynamic. It is best to set both as not all proxy servers properly support the HTTP/1.1 Cache-Control header. If you want more information on caching in general, try these web pages:

For cacheable static resources that vary between versions, you can simply change the URL for cacheable static resources that vary between versions. If each version of a static resource is serving from different URLs, then those resources can happily co-exist in proxy servers and browser caches.

Caching and Vary: Cookie

If the app sets the Vary: Cookie header, the uniqueness of a resource is computed by combining the cookies and the URL for the request. This approach increases the burden on cache servers. There are 1000 possible values of GOOGAPPUID, and hence 1000 possible entries for each URL for your app. Depending on the load on the proxies between your users and your app, this may decrease cache hit rate. Also note that for the 24 hours after adding a new batch of users to a version, they may still see cached resources. However, using Vary: Cookie can make it easier to rename static resources that are changing between versions.

The Vary: Cookie technique doesn't work in all circumstances. In general, if your app is using cookies for other purposes, then you must consider how this affects the burden on proxy servers. If codeninja had its own cookie that had 100 possible values, then the space of all possible cache entries becomes a very big number, 100 * 1000 = 100,000. In the worst case, there is a unique cookie for every user. Two common examples of this are Google Analytics (__utma) and SiteCatalyst (s_vi). In this case, every user gets a unique copy, which severely degrades cache performance and also may increase the number of billable instance hours consumed by your app.