<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: adrian cockcroft</title>
    <description>The latest articles on DEV Community by adrian cockcroft (@adrianco).</description>
    <link>https://dev.to/adrianco</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F355857%2F0b1ebec3-295d-4a7d-9b61-bf9e438d7e23.jpg</url>
      <title>DEV Community: adrian cockcroft</title>
      <link>https://dev.to/adrianco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adrianco"/>
    <language>en</language>
    <item>
      <title>Measuring Energy Usage</title>
      <dc:creator>adrian cockcroft</dc:creator>
      <pubDate>Mon, 31 Oct 2022 23:17:27 +0000</pubDate>
      <link>https://dev.to/adrianco/measuring-energy-usage-5ip</link>
      <guid>https://dev.to/adrianco/measuring-energy-usage-5ip</guid>
      <description>&lt;p&gt;Decided to figure out how to measure the energy used by a desktop computer and see if I can figure out a way to identify different workloads.&lt;/p&gt;

&lt;p&gt;I have a Mac Studio M1 to run the workload, and an old MacBook laptop to run data collection on, so that it doesn't add to the workload.&lt;/p&gt;

&lt;p&gt;First thing we need is a power monitoring plug that has an API. The TP-Link Kasa platform seems like a good place to start. It has a python based API available &lt;a href="https://github.com/python-kasa/python-kasa"&gt;on GitHub&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% pip3 install python-kasa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ordered a &lt;a href="https://www.amazon.com/gp/product/B08LN3C7WK"&gt;Kasa KP115 smart plug from Amazon&lt;/a&gt; for $22.99.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x4Eyo7AX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://m.media-amazon.com/images/I/61%2BYr4-FRXL._AC_SL1500_.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x4Eyo7AX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://m.media-amazon.com/images/I/61%2BYr4-FRXL._AC_SL1500_.jpg" alt="Smart pług" width="880" height="1355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setup the plug using the mobile app, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% kasa
No host name given, trying discovery..
Discovering devices on 255.255.255.255 for 3 seconds
== PowerMeter - KP115(US) ==
    Host: 10.0.0.46
    Device state: ON

    == Generic information ==
    Time:         2022-10-31 15:21:56 (tz: {'index': 6, 'err_code': 0}
    Hardware:     1.0
    Software:     1.0.18 Build 210910 Rel.141202
    MAC (rssi):   10:27:F5:9C:37:12 (-49)
    Location:     {'latitude': 36.xxx, 'longitude': -121.xxx}

    == Device specific information ==
    LED state: True
    On since: 2022-10-31 12:35:15

    == Current State ==
    &amp;lt;EmeterStatus power=3.456 voltage=122.48 current=0.049 total=0.002&amp;gt;

    == Modules ==
    + &amp;lt;Module Schedule (schedule) for 10.0.0.46&amp;gt;
    + &amp;lt;Module Usage (schedule) for 10.0.0.46&amp;gt;
    + &amp;lt;Module Antitheft (anti_theft) for 10.0.0.46&amp;gt;
    + &amp;lt;Module Time (time) for 10.0.0.46&amp;gt;
    + &amp;lt;Module Cloud (cnCloud) for 10.0.0.46&amp;gt;
    + &amp;lt;Module Emeter (emeter) for 10.0.0.46&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next - you have to specify host, or it will crash, and specifying type saves it an extra API call, and you get a single result&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% kasa --host 10.0.0.46 --type plug emeter 
== Emeter ==
Current: 0.049 A
Voltage: 121.715 V
Power: 3.628 W
Total consumption: 0.002 kWh
Today: 0.002 kWh
This month: 0.002 kWh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using a csh loop to get a 1 second trace of the data it's clear that the data changes about every 4 seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% while 1
while? kasa --host 10.0.0.46 --type plug | egrep '(Time:|EmeterStatus)'
while? sleep 1
while? end
    Time:         2022-10-31 16:09:34 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=0.0 voltage=122.49 current=0.0 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:35 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=0.0 voltage=122.49 current=0.06 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:36 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=0.0 voltage=122.36 current=0.06 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:38 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.68 voltage=122.36 current=0.06 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:39 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.68 voltage=122.36 current=0.06 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:40 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.68 voltage=122.36 current=0.05 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:41 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.68 voltage=122.258 current=0.05 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:42 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.253 voltage=122.258 current=0.05 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:43 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.253 voltage=122.258 current=0.05 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:45 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.253 voltage=122.258 current=0.049 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:46 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.253 voltage=122.382 current=0.049 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:47 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.253 voltage=122.382 current=0.049 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:48 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.675 voltage=122.382 current=0.049 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:49 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.675 voltage=122.382 current=0.012 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:50 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.675 voltage=122.446 current=0.012 total=0.004&amp;gt;
    Time:         2022-10-31 16:09:52 (tz: {'index': 6, 'err_code': 0}
    &amp;lt;EmeterStatus power=3.675 voltage=122.446 current=0.012 total=0.004&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output formatting is defined in cli.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kasa --host 10.0.0.46 --type plug | awk '/Time:|EmeterStatus/{printf("%s %s ", $2, $3)}'; echo
2022-10-31 16:23:11 power=1.017 voltage=122.608 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all I have time to do for now, to be continued...&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Sustainability Transformation and DevSusOps</title>
      <dc:creator>adrian cockcroft</dc:creator>
      <pubDate>Thu, 24 Jun 2021 20:29:13 +0000</pubDate>
      <link>https://dev.to/aws/what-is-sustainability-transformation-32hi</link>
      <guid>https://dev.to/aws/what-is-sustainability-transformation-32hi</guid>
      <description>&lt;p&gt;The transformation towards sustainable development practices is an emerging area, I learned a lot in my previous roles working for Amazon, and now I'm working part time as a technology and strategy advisor, I'm planning to share some of the ideas and mental models needed to make sense of this from a developer perspective in a series of short posts here.&lt;/p&gt;

&lt;p&gt;I was part of the team that published the &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/sustainability-pillar/sustainability-pillar.html" rel="noopener noreferrer"&gt;Well Architected Pillar for Sustainability&lt;/a&gt; which has detailed advice on how to optimize a workload to be more sustainable,  I'll incorporate some of this advice as I go along.&lt;/p&gt;

&lt;p&gt;To start with, most people are familiar with the phrase "Digital Transformation". It's become over-used and is a bit tired now. In essence though, it refers to the new businesses that were enabled by pervasive Internet and mobile connected customers, and the changes needed in old businesses to compete. We've had a decade or so to get used to this, so it's well understood, even if some of the laggards are still struggling to figure it out.&lt;/p&gt;

&lt;p&gt;On the other hand "Sustainability Transformation" is an emerging topic, poorly understood and with immature solutions to support it. It refers to the changes driven by our need to reduce the impact of business on the environment, including reducing greenhouse gas emissions, clean water and zero waste to landfill. The biggest of these is carbon dioxide reduction, as we need to move from extracting and burning fossil fuels to an economy based on renewable energy. This reaches throughout business operations, from the fuel burned to heat buildings and power vehicles (which is called scope 1), to the fuel used to generate the electricity we consume (which is called scope 2), to the energy used by things we buy, own and sell (which is called scope 3).&lt;/p&gt;

&lt;p&gt;The first problem is figuring out how much greenhouse gas is being generated. There are several different gases that matter, with different impacts. The main one is Carbon Dioxide, but Methane and CFC refrigerants are also a problem. They are combined together for measurement and reporting as Carbon Dioxide Equivalent - CO2e. The methodology published by the &lt;a href="//ghgprotocol.org"&gt;Green House Gas Protocol&lt;/a&gt; is used to calculate carbon equivalents and to get detailed guidance on what to include in scope calculations.&lt;/p&gt;

&lt;p&gt;There are a few different ways to calculate carbon. &lt;/p&gt;

&lt;p&gt;The economic carbon intensity of a product or a business may be reported as the grams of carbon per dollar that is spent, gCO2e/$, or metric tonnes of CO2 per million dollars mtCO2e/$M. There are a million grams in a metric tonne, so the value is the same. Most companies start out by making an estimate of their carbon footprint using an Economic Input/Output (EIO) model that is based on the financial flows and uses industry average factors to relate spend to carbon. This is good enough for reporting, and to find out where most of the carbon is likely to be generated by the business. It's not useful for optimizing carbon reduction, because if you spend more on a low carbon energy source or raw material you will end up reporting more carbon not less.&lt;/p&gt;

&lt;p&gt;To get more accurate and actionable measurements, business processes need to be instrumented to calculate the carbon generated by raw material and product flows. For raw materials, carbon intensity is often reported as grams of CO2 per kilogram of the material - gCO2e/Kg. For fuels that are burned this provides a more accurate way to estimate scope 1 than just basing it on the total amount spent on fuel.&lt;/p&gt;

&lt;p&gt;The carbon intensity of energy for scope 2 is measured as grams of CO2e per KWh. It depends how and when that electricity was generated, and changes all the time. For example when it's sunny or windy, there's more solar and wind energy. The "grid mix" is usually reported by an energy supplier on an average monthly basis, however you have to wait for the bill, so an accurate scope 2 report will be delayed by a month or more.&lt;/p&gt;

&lt;p&gt;The embodied carbon from manufacturing is amortized over the lifetime of the item: gCO2e/year. This is part of scope 3. For example if you use something like a mobile phone for longer, the gCO2e that was emitted to make it is having a useful purpose for longer.&lt;/p&gt;

&lt;p&gt;For a sustainability transformation, a business has to figure out how to measure its carbon footprint, and come up with a plan to change the way it powers everything, and change the products it's making, and even the markets that it operates in. That takes time, and I'll talk about timescales in my next post.&lt;/p&gt;

&lt;p&gt;From a developer perspective there are three main areas of interest. The &lt;strong&gt;first&lt;/strong&gt; is that most companies start with a manual spreadsheet based approach, but new disclosure regulations are driving the need to build some kind of data lake to report their carbon footprint, and to model their risk exposure to the impacts of climate change. The &lt;strong&gt;second&lt;/strong&gt; is that sustainability is becoming a product attribute of the things companies do and build, so it's turning up in design decisions. The &lt;strong&gt;third&lt;/strong&gt; is that the efficiency of the code we write and how we deploy it affects the carbon footprint of our IT systems. I call this &lt;a href="//twitter.com/DevSusOps"&gt;DevSusOps&lt;/a&gt;, adding sustainability concerns to development and operations.&lt;/p&gt;

&lt;p&gt;That's enough to start with, there's lots more to talk about, but I'd like to break up this discussion into a bunch of short posts. To learn more, a good readable document to study is this &lt;a href="https://ghgprotocol.org/sites/default/files/standards/ghg-protocol-revised.pdf" rel="noopener noreferrer"&gt;Green House Gas Protocol paper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;photo taken by Adrian at Point Lobos, California&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sustainability</category>
      <category>architecture</category>
      <category>cloud</category>
      <category>transformation</category>
    </item>
    <item>
      <title>If at first you don't get an answer...</title>
      <dc:creator>adrian cockcroft</dc:creator>
      <pubDate>Thu, 14 May 2020 23:23:20 +0000</pubDate>
      <link>https://dev.to/aws/if-at-first-you-don-t-get-an-answer-3e85</link>
      <guid>https://dev.to/aws/if-at-first-you-don-t-get-an-answer-3e85</guid>
      <description>&lt;p&gt;give up quickly and ask someone else. That's my favorite microservices retry policy. To understand what works and doesn't work, we need to think about how distributed systems of services and databases interact with each other, not just a single call. Like my last post on &lt;a href="https://dev.to/aws/why-are-services-slow-sometimes-mn3"&gt;why systems are slow sometimes&lt;/a&gt;, I will start simple, pick out key points, and gradually explain the things that will kill your distributed system, if you don't have timeouts and retries setup properly. It's also one of the easiest things to fix, once you understand what's going on, and it generally doesn't need new code, just configuration changes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A bad timeout and retry policy can break a distributed systems architecture, but is relatively easy to fix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I often find the timeout and retry policy across an application is set to whatever the default is for the framework or sample code you copied when starting to write each microservice. If every microservice uses the same timeout, this is guaranteed to fail, because the microservices deeper in the system are still retrying when the microservices nearer the edge have given up waiting for them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't use the same default timeout settings across your distributed system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This causes an avalanche of extra calls, &lt;em&gt;work amplification&lt;/em&gt;, that is triggered when just one microservice or database deep in the system slows down for some reason. &lt;em&gt;I used to work on a system that fell over at 8pm every Monday night because the monolithic backend database backup was scheduled then, and database queries slowed down enough to trigger a retry storm that overloaded the application servers.&lt;/em&gt; The simplest way to reduce work amplification is to limit the number of retries to zero or one. I've seen defaults that are higher, and seen people react to seeing timeouts by increasing the number of retries, but this is just going to multiply the amount of extra work the system is trying to do when it's already struggling. Use zero retries in more deeply nested microservice architectures that will retry closer to the user.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Limit the number of retries to zero or one, to minimize &lt;em&gt;work amplification&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This should be a fairly easy configuration change to implement, and a good checklist question that should be answered for your inventory of microservices is to ask how the timeout and retry settings are set, and what is needed to change the configuration. It's really nice if the settings can be changed dynamically and take effect in a few seconds. That provides a mechanism that may be able to bring a catatonic system back to life during an outage. Unfortunately in many cases the configuration is set once when the application starts, or could be hard coded in the application, or is so deep inside some imported library that no-one knows that a timeout setting exists, or how to change it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Discovering and documenting current settings and how to change timeouts and retries can be a pain, but it's worth it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many people don't realize that there are two different kinds of timeout, some coding platforms and libraries bundle them together, and others expose them separately. The best analogy is to consider the difference between sending a letter, and making a phone call. If you send a letter, with an RSVP, you wait for a response. Maybe after a timeout you send another letter. It's the simplest request/response mechanism, and &lt;a href="https://en.wikipedia.org/wiki/User_Datagram_Protocol" rel="noopener noreferrer"&gt;UDP based protocols&lt;/a&gt; like DNS work this way. A phone call is different because the first step is to make a connection by establishing a phone call. The other party has to pick up the phone and acknowledge that they can hear you, and you have to be sure you are talking to the right person. If they don't pick up, you retry the connection by calling again. Once the call is in progress, you make the request, and wait for the other party to respond. You can make several requests during a call. &lt;a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol" rel="noopener noreferrer"&gt;TCP based protocols&lt;/a&gt; which underlie many APIs, work this way. If the phone line goes dead, you have to call again, and establish a new connection.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Be clear about the difference between &lt;em&gt;connections&lt;/em&gt; and &lt;em&gt;requests&lt;/em&gt; for the protocols you are using.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;em&gt;connection timeout&lt;/em&gt; is how long you wait before giving up on getting a connection made to the next step in your request flow. The &lt;em&gt;request timeout&lt;/em&gt; is how long you wait for the rest of the entire flow to complete from that point. The common case is to bundle everything into the request at the application level, and have some lower level library handle the connections. Connections may be pre-setup during an initialization and authentication phase or occur when the first request is made. Subsequent application requests could cause an entire new connection to be made, or a &lt;em&gt;keep-alive&lt;/em&gt; option would keep it around to get a quicker response for the next request.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dig deep to find any hidden connection timeout and keep-alive settings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How should you decide how to set the connection and request timeouts?&lt;br&gt;
While connection timeouts depend on the network latency to get to the service interface, request timeouts depend on the end-to-end time to call through many layers of the system. The closer to the end user, the longer the request timeout needs to be. Deeper into the system, request timeouts need to be shorter. For simple three-tier architectures like a front end web service, back end application service and database it's clear what order things are called in, and nested or &lt;em&gt;telescoped&lt;/em&gt; timeouts can be setup for each tier. The timeouts must be reduced at every step as you go from the edge to the back-end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Edge timeouts must be long enough, and back end timeouts short enough, that the edge doesn't give up while the back end is still working.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Web browsers and mobile apps often have a default timeout of many seconds before they give up. However humans tend to hit the refresh button or go and look at something else if they are staring at a blank screen for too long. Some web site data says you should &lt;a href="https://www.hobo-web.co.uk/your-website-design-should-load-in-4-seconds/" rel="noopener noreferrer"&gt;target 2-4 seconds for page load time&lt;/a&gt;. However they are waiting in an app for something like a movie to start streaming, then users will wait a bit longer, maybe up to 10 seconds. If you have too many retries and long timeouts between your services, it's easy to add up to more than a few seconds, and while your system is still working to get a response, the end user will ignore the result as they have already given up and sent a new request. The best outcome is that your application returns before they retry manually, with a message that tells them you gave up, and asks if they want to try again. This minimizes the chance that you'll get flooded by work amplification.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For human interactions, if you can't respond within 10s, give up and respond with an error. Try to keep web page load times below 4s.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One question is what to do after giving up on a call. This can be problematic, as described in the Amazon Builders Library piece &lt;a href="https://aws.amazon.com/builders-library/avoiding-fallback-in-distributed-systems/" rel="noopener noreferrer"&gt;Avoiding fallback in distributed systems&lt;/a&gt;, the fallback code to handle problems is often poorly tested, if at all. A common problem is that a system that times out calls elsewhere will crash, return bad or corrupted data, or freeze.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Injecting slow and failed responses from the dependencies of a service is an important chaos testing technique.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my last post I talked about how end to end response time is made up of residence times for every step along the way, and those residence times are a combination of waiting time in a queue and service time getting the work done. During a timeout, there is an increase in wait time, and you can think of this as an additional timeout queue, where work is being parked that can't move forward. This can clog up systems by creating very long queues of stale requests. Processing them in order from the oldest first is often a bad policy, as you may never get to do work that someone is still actually waiting for. A better policy is to discard the entire queue of requests waiting for timeout when it hits a size limit. Each retry adds to service time, as the request is processed again.&lt;/p&gt;

&lt;p&gt;If there is only one instance of a service endpoint or database, you have no-where else to go. Attempting to connect to it repeatedly and quickly is unlikely to help it recover, so in this case you need to use a &lt;em&gt;back-off&lt;/em&gt; algorithm. This causes it's own problems, so should only be used where there is no alternative. Some systems implement exponentially increasing back-off, but it's important to use &lt;em&gt;bounded exponential back-off&lt;/em&gt; with an upper limit, otherwise you are creating a big queue which will take too long to get connected, and upstream systems will already have given up waiting. This is also sometimes called &lt;em&gt;capped&lt;/em&gt; exponential back-off. Adding some randomness to the back-off is a better policy, as it will disperse the &lt;em&gt;thundering herd&lt;/em&gt; of clients that could end up backing off and returning in a synchronized manner. Deterministic jittered backoff is a way to give each instance a different back-off, but with a pattern that can be used as a signature for analysis purposes. &lt;a href="https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/" rel="noopener noreferrer"&gt;Marc Brooker of AWS describes this technique in &lt;em&gt;Timeouts, Retries and Backoff with Jitter&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Only if you have to, use random or jittered back-off to disperse clients and avoid thundering herd behaviors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Consider a deeply nested microservice architecture, where the request flow depends on what kind of request is being made, and the ideal request timeout ends up being flow dependent. If we can pass a timeout value through the chain of individual spans in the flow then dynamic timeouts are possible. One way to implement this is to pass a deadline timestamp through the flow. If you can't respond within the deadline, give up. This requires closely synchronized clocks across the system, and may be a useful technique for relatively large timeouts of tens of seconds to minutes. Some batch management systems implement deadline scheduling for long running jobs. For short latency microservice architectures a better policy would be to decrement a latency budget for each span in the flow, and give up when there's not enough budget left to get a result, but there is still time to respond back up and report the failure cleanly before the user times out at the edge. The question is how much latency to deduct at each stage, and to solve this properly would need some extra instrumentation based on analysis of flows through the system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dynamic request timeout policies are needed for deeply nested microservices architectures with complex flows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Connection timeouts depend on the number of &lt;em&gt;round trips&lt;/em&gt; needed to setup a connection (at least two, more for secure connections like HTTPS), and network latency to the next service in line, they should be very short, a small multiple of the latency itself. Within a datacenter or AWS availability zone, round trip network latency is generally around a millisecond, and a few milliseconds between AWS availability zones. Sometimes people talk about one-way latency numbers, so be clear what is being discussed, as a round trip is twice as long.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use a short timeout for connections between co-located microservices, whether direct, or via a service mesh proxy like &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.cloudping.co/grid" rel="noopener noreferrer"&gt;Round trip latency between AWS regions&lt;/a&gt; in the same continent is likely to be in the range 10-100ms, and between continents, a few hundred milliseconds. Calls to third party APIs or your own remote services will need a much higher timeout setting. Your measurements will vary, but will be limited by signals propagating at less than the speed of light, about 300,000km/s, which is about 150km round trip per millisecond. Processing, queueing and routing the network packets etc. will always make it much slower than this, but unfortunately the speed of light is not increasing so this is a fundamental latency limit!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use a longer timeout for connections between AWS regions, and calls to third party APIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you set your connection timeout to be shorter than the round trip, it will fail continuously, so it's common to use a high value. This works fine until there's a problem, then it magnifies the problem, and causes requests to timeout when they could be succeeding over a different connection. It's much better to fail fast and give up quickly on a connection that isn't going to work out. It would be ideal to have the connection timeout be adaptive, to start out large, and to shrink to fit, for the actual network latency situation. TCP does something like this for congestion control once connections are setup, but I don't know of any platforms that learn and adapt to latency, and invite readers to let us know in the comments if they do, and I'll update this post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Set connection timeouts to be about 10x the round trip latency, if you can...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The default connection retry policy is to just repeat the call. Like phoning someone over and over again on the same number. However, if that person has a home number and a mobile number, you might try the other number after the first failure, and increase your chance of getting through. It's common to have horizontally scaled services, and if you've built a stateless microservices architecture (that doesn't use sessions to route traffic to locally cached state), you should try to connect to a different instance of the same service, as your default connection retry policy. Unfortunately many microservices frameworks don't have this option, but it was built into the Netflix open source service mesh released in 2012. NetflixOSS Ribbon and the Eureka service registry implemented a Java based service mesh, Envoy implements a language agnostic "side-car" process based service mesh with a &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/faq/configuration/timeouts#http-grpc" rel="noopener noreferrer"&gt;configurable connection timeout&lt;/a&gt;, and &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#config-http-filters-router" rel="noopener noreferrer"&gt;defaults retries to one, with bounded and jittered backoff&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have horizontally scaled services, don't retry connections to the same one that just failed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's a high probability that an instance of a microservice that failed to connect will fail again for the same reason. It could be overloaded, out of threads, or doing a long garbage collection. If an instance is not listening for connections because it's application process has crashed or it's hit a thread or connection limit, you get a fast fail and a specific error return, as the connection will be refused immediately. It's like an unobtainable number error for a phone call. Immediately calling again in this case is clearly pointless.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fast failures are good, and don't retry to the same instance immediately if at all possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've seen some microservice based applications behaving in a fragile or brittle manner, that collapsed when conditions weren't perfect. However after fixing their timeout and retry policies along these lines they became stable and robust, absorbing a lot of problems so that customers saw a slightly degraded rather than an offline service. I hope you find these ideas and references useful for improving your own service robustness.&lt;/p&gt;

&lt;p&gt;Thanks to Seth and Jim at Amazon for feedback, corrections and clarifications.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo taken by Adrian in March 2019 at the Roman Amphitheater, Mérida, Spain. A nice example of a low latency, high fan-out, communication system&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>architecture</category>
      <category>microservices</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Why are services slow sometimes?</title>
      <dc:creator>adrian cockcroft</dc:creator>
      <pubDate>Wed, 29 Apr 2020 19:53:46 +0000</pubDate>
      <link>https://dev.to/aws/why-are-services-slow-sometimes-mn3</link>
      <guid>https://dev.to/aws/why-are-services-slow-sometimes-mn3</guid>
      <description>&lt;p&gt;You've built a service, you call it, it does something and returns a result, but how long does it take, and why does it take longer than your users would like some of the time? In this post I'll start with the basics and gradually introduce standardized terminology and things that make the answer to this question more complicated, while highlighting key points to know.&lt;/p&gt;

&lt;p&gt;To start with, we need a way to measure how long it takes, and to understand two fundamentally different points of view. If we measure the experience as an outside user calling the service we measure how long it takes to respond. If we instrument our code to measure the requests from start to finish as they run, we're only measuring the service. This leads to the first key point, people get sloppy with terminology and often aren't clear where they got their measurements.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Be careful to measure &lt;em&gt;Response Time&lt;/em&gt; at the user, and &lt;em&gt;Service Time&lt;/em&gt; at the service itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For real world examples, there are many steps in a process, and each step takes time. That time for each step is the &lt;em&gt;Residence&lt;/em&gt; time, and consists of some &lt;em&gt;Wait Time&lt;/em&gt; and some &lt;em&gt;Service Time&lt;/em&gt;. As an example, a user launches an app on their iPhone, and it calls a web service to authenticate the user. Why might that be slow sometimes? The amount of actual service time work required to generate the request in the phone, transmit that to a web service, lookup the user, return the result and display the next step should be pretty much the same every time. The variation in response time is driven by waiting in line (&lt;em&gt;Queueing&lt;/em&gt;) for a resource that is also processing other requests. Network transmission from the iPhone to the authentication server is over many hops, and before each hop is a queue of packets waiting in line to be sent. If the queue is empty or short, then response will be quick, and if the queue is long the response will be slow. When the request arrives at the server, it's also in a queue waiting for the CPU to start processing that request, and if a database lookup is needed, there's another queue to get that done.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Waiting in a &lt;em&gt;Queue&lt;/em&gt; is the main reason why &lt;em&gt;Response Time&lt;/em&gt; increases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most of the instrumentation we get from monitoring tools is measures of how often something completed which we call &lt;em&gt;Throughput&lt;/em&gt;. In some cases we also have a measure of incoming work as &lt;em&gt;Arrival Rate&lt;/em&gt;. For a simple case like a web service with a &lt;em&gt;Steady state&lt;/em&gt; workload where one request results in one response, both are the same. However retries and errors will increase arrivals without increasing throughput, rapidly changing workloads or very long requests like batch jobs will see temporary imbalances between arrivals and completed throughput, and it's possible to construct more complex request patterns.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Throughput&lt;/em&gt; is the number of completed successful requests. Look to see if &lt;em&gt;Arrival Rate&lt;/em&gt; is different, and to be sure you know what is actually being measured.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While it's possible to measure a single request flowing through the system using a tracing mechanism like &lt;a href="https://zipkin.io/" rel="noopener noreferrer"&gt;Zipkin&lt;/a&gt; or &lt;a href="https://aws.amazon.com/xray/" rel="noopener noreferrer"&gt;AWS X-Ray&lt;/a&gt; this discussion is about how to think about the effect of large numbers of requests, and how they interact with each other. The average behavior is measured over a fixed time interval, which could be a second, minute, hour or day. There needs to be enough data to average together, and without going into the theory a rule of thumb is that there should be at least 20 data points in an average.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For infrequent requests, pick a time period that averages at least 20 requests together to get useful measurements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the time period is too coarse, it hides the variation in workloads. For example for a video conferencing system, measuring hourly call rates will miss the fact that most calls start around the first minute of the hour, and it's easy to get a peak that overloads the system, so per-second measurements are more appropriate.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For spiky workloads, use high resolution one-second average measurements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Monitoring tools vary, however it's rare to get direct measurements of how long the line is in the various queues. It's also not always obvious how much &lt;em&gt;Concurrency&lt;/em&gt; is available to process the queues. For most networks one packet at a time is in transit, but for CPUs each core or vCPU works in parallel to process the run queue. For databases, there is often a fixed maximum number of connections to clients which limits concurrency.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For each step in the processing of a request, record or estimate the &lt;em&gt;Concurrency&lt;/em&gt; being used to process it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we think about a system running in a steady state, with a stable average throughput and response time, then we can estimate the queue length simply by multiplying the throughput and the residence time. This is known as &lt;em&gt;Little's Law&lt;/em&gt;, it's very simple, and is often used by monitoring tools to generate queue length estimates, but it's only true for steady state averages of randomly arriving work.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Little's Law&lt;/em&gt; Average Queue = Average Throughput * Average Residence&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To understand why this works, and when it doesn't, it's important to understand how work arrives at a service and what determines the gap between requests. If you are running a very simple performance test in a loop then the gap between requests is constant, Little's Law doesn't apply, queues will be short and your test isn't very realistic, unless you are trying to simulate a conveyor belt like situation. It's a common mistake to do this kind of test successfully, then put the service in production and watch it get slow or fall over at a much lower throughput than the test workload.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Constant rate loop tests don't generate queues, they simulate a conveyor belt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For real world Internet traffic, with many independent users who aren't coordinating and make single requests, the intervals between requests are random. So you want a load generator that randomizes some wait time between each request. The way most systems do this uses a uniformly distributed random distribution, which is better than a conveyor belt, but isn't correct. To simulate web traffic, and for Little's Law to apply you need to use use a &lt;em&gt;negative exponential distribution&lt;/em&gt;, as described in this &lt;a href="http://perfdynamics.blogspot.com/2012/05/load-testing-with-uniform-vs.html" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; by &lt;a href="https://twitter.com/DrQz" rel="noopener noreferrer"&gt;Dr Neil Gunther&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The proper random think time calculation is needed to generate more realistic queues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, it gets worse. It turns out that network traffic is not randomly distributed, it comes in bursts. Those bursts come in clumps. Think of what actually happens when a user starts an iPhone app. It doesn't make one request, it makes a burst of requests. In addition users taking part in a flash sale will be synchronized to visit their app at around the same time causing a clump of bursts of traffic. The &lt;a href="https://perfdynamics.blogspot.com/2010/05/load-testing-think-time-distributions.html" rel="noopener noreferrer"&gt;distribution is known as pareto or hyperbolic&lt;/a&gt;. In addition, when networks reconfigure themselves, traffic is delayed for a while and a queue builds up for a while then floods the downstream systems with a thundering herd. Update - there's &lt;a href="https://github.com/DrQz/web-generator-toolkit" rel="noopener noreferrer"&gt;some useful work by Jim Brady and Neil Gunther&lt;/a&gt; on how to configure load testing tools to be more realistic, and a &lt;a href="https://arxiv.org/abs/1809.10663" rel="noopener noreferrer"&gt;CMG2019 paper by Jim Brady&lt;/a&gt; on measuring how well your test loads are behaving.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Truly real world workloads are more bursty and will have higher queues and long tail response times than common load test tools generate by default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should expect queues and response times to vary and to have a long tail of a few extremely slow requests even at the best of times when average utilization is low. So what happens as one of the steps in the process starts to get busy? For processing steps which don't have available concurrency (like a network transmission), as the utilization increases, the probability that requests contend with each other increases, and so does the residence time. The rule of thumb for networks is that they gradually start to get slow around 50-70% utilization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Plan to keep network utilization below 50% for good latency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Utilization is also &lt;a href="http://www.hpts.ws/papers/2007/Cockcroft_CMG06-utilization.pdf" rel="noopener noreferrer"&gt;problematic and measurements can be misleading&lt;/a&gt;, but it's defined as the proportion of time something is busy. For CPUs where there are more executions happening in parallel, slow down happens at higher utilization, but kicks in harder and can surprise you. This makes intuitive sense if you think about the last available CPU as the point of contention. For example if there are 16 vCPUs, the last CPU is the last 6.25% of capacity, so residence time kicks up sharply around 93.75% utilization. For a 100 vCPU system, it kicks up around 99% utilization. The formula that approximates this behavior for randomly arriving requests in steady state (the same conditions as apply for Little's Law) is R=S/(1-U^N).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inflation of average residence time as utilization increases is reduced in multi-processor systems but "hits the wall" harder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unpicking this, take the average utilization as a proportion, not a percentage, and raise it to the power of the number of processors. Subtract from 1, and divide into the average service time to get an estimate of the average residence time. If average utilization is low, dividing by a number near 1 means that average residence time is nearly the same as the average service time. For a network that has concurrency of N=1, 70% average utilization means that we are dividing by 0.3, and average residence time is about three times higher than at low utilization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rule of thumb is to keep inflation of average residence time below 2-3x throughout the system to maintain a good average user visible response time. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a 16 vCPU system at 95% average utilization, 0.95^16 = 0.44 and we are dividing by 0.56, which roughly doubles average residence time. At 98% average utilization 0.98^16=0.72 and we are dividing by 0.28, so average residence time goes from acceptable to slow for only a 3% increase in average utilization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The problem with running a multiprocessor system at high average utilization is that small changes in workload levels have increasingly large impacts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a standard Unix/Linux metric called &lt;em&gt;Load Average&lt;/em&gt; which is poorly understood and has several problems. For Unix systems including Solaris/AIX/HPUX it records the number of operating system threads that are running and waiting to run on the CPU. For &lt;a href="https://perfcap.blogspot.com/2007/04/load-average-differences-between.html" rel="noopener noreferrer"&gt;Linux it includes operating system threads blocked waiting for disk I/O as well&lt;/a&gt;. It then maintains three time decayed values over &lt;a href="http://perfdynamics.blogspot.com/2007/04/how-long-should-queue-be.html" rel="noopener noreferrer"&gt;1 minute, 5 minute and 15 minutes&lt;/a&gt;. The first thing to understand is that the metric dates back to single CPU systems in the 1960s, and I would always divide the load average value by the number of vCPUs to get a measure that is comparable across systems. The second is that it's not measuring across a fixed time interval like other metrics, so it's not the same kind of average, and it builds in a delayed response. The third is that the Linux implementation is a bug that has become institutionalized as a feature, and inflates the result. It's just a terrible metric to monitor with an alert or feed to an autoscaling algorithm.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Load Average&lt;/em&gt; doesn't measure load, and isn't an average. Best ignored.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a system is over-run, and more work arrives than can be processed, we reach 100% utilization, and the formula has a divide by zero which predicts infinite residence time. In practice it's worse than this, because when the system becomes slow, the first thing that happens is that  upstream users of the system retry their request, which magnifies the amount of work to be done and causes a &lt;em&gt;retry storm&lt;/em&gt;. The system will have a long queue of work, and go into a catatonic state where it's not responding.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Systems that hit a sustained average utilization of 100% will become unresponsive, and build up large queues of work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I look at how timeouts and retries are configured, I often find too many retries and timeouts that are far too long. This increases &lt;em&gt;work amplification&lt;/em&gt; and makes a retry storm more likely. &lt;a href="https://www.slideshare.net/adriancockcroft/evolution-of-microservices-craft-conference/29" rel="noopener noreferrer"&gt;I've talked about this in depth in the past&lt;/a&gt;, and have &lt;a href="https://dev.to/aws/if-at-first-you-don-t-get-an-answer-3e85"&gt;added a new post on this subject&lt;/a&gt;. The best strategy is a short timeout with a single retry, if possible to a different connection that goes to a different instance of a service.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Timeouts should never be set the same across a system, they need to be much longer at the front end edge, and much shorter deep inside the system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The usual operator response is to clear an overloaded queue by rebooting the system, but a well designed system will limit it's queues and shed work by silently dropping or generating fast-fail responses to incoming requests. Databases and other services with a fixed maximum number of connections behave like this. When you can't get another connection to make a request, you get a fast fail response. If the connection limit is set too low, the database will reject work that it has capacity to process, and if its set too high, the database will slow down too much before it rejects more incoming work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Think about how to shed incoming work if the system reaches 100% average utilization, and what configuration limits you should set.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The best way to maintain a good response time under extreme conditions is to fail fast and shed incoming load. Even under normal conditions, most real world systems have a long tail of slow response times. However with the right measurements we can manage and anticipate problems, and with careful design and testing it's possible to build systems that &lt;a href="https://aws.amazon.com/blogs/database/improving-business-continuity-with-amazon-aurora-global-database/" rel="noopener noreferrer"&gt;manage their maximum response time&lt;/a&gt; to user requests.&lt;/p&gt;

&lt;p&gt;To dig deeper into this topic, there's a lot of good information in &lt;a href="https://twitter.com/DrQz" rel="noopener noreferrer"&gt;Neil Gunther's&lt;/a&gt; blog, books, and training classes. I worked with Neil to develop a summer school performance training class that was hosted at Stanford in the late 1990's, and he's been running events ever since. For me, co-presenting with Neil was a formative experience, a deep dive into queuing theory that really solidified my mental models of how systems behave.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Picture of lines of waiting barrels taken by Adrian at a wine cellar in Bordeaux.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>architecture</category>
      <category>distributedsystems</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Scaling AWS costs to match the business</title>
      <dc:creator>adrian cockcroft</dc:creator>
      <pubDate>Tue, 21 Apr 2020 17:05:37 +0000</pubDate>
      <link>https://dev.to/aws/scaling-aws-costs-to-match-the-business-f9k</link>
      <guid>https://dev.to/aws/scaling-aws-costs-to-match-the-business-f9k</guid>
      <description>&lt;p&gt;I recently wrote a &lt;a href="https://medium.com/@adrianco/cloud-native-cost-optimization-f379c2f623e9" rel="noopener noreferrer"&gt;Medium post on cloud native cost optimization&lt;/a&gt;, in part to help customers who are currently dealing with rapid large and unexpected changes in their businesses due to the impact of COVID-19. Out of the ensuing discussion, a few things emerged. One is that I should try out dev.to for developer oriented posts, so this is my first post here. Another is that there's benefits and challenges in generating a metric that reports AWS cost per unit of business, so that's the subject of this discussion.&lt;/p&gt;

&lt;p&gt;The first challenge is to decide what your business does, and whether there is a dominant metric that measures the value you provide to customers. I was at Netflix in 2011 when we started to build tooling to optimize our AWS spend, and Netflix has a very focused business model and measured customer value as the number of "streaming starts per second" (SPS). i.e. The rate at which people decide to start watching a show on Netflix.&lt;/p&gt;

&lt;p&gt;We also had an AWS deployment model which tagged and attributed all the entities we created on AWS back to individuals and teams, and produced detailed billing on an hourly basis. Starting with a total AWS cost, dividing by SPS produced an hourly average total "cloud cost of value". Digging in further, the cost could be broken down by production delivery vs. test and development vs. data science vs. movie encoding etc. and individual teams were sent a weekly report showing their own share of the total cost, and how it was trending.&lt;/p&gt;

&lt;p&gt;I've found that many customers don't have good tagging and attribution setup, so find it hard to work out what is driving their AWS bill. The first step is to come up with a percentage attribution metric for the bill, and drive it to cover most of the spend. I'd focus on this as a priority until it's in the 70-90% range, then clean up the rest over time.&lt;/p&gt;

&lt;p&gt;For a more typical complex and diverse business, with many points of value delivery, the trick is to pick a dominant expense that scales with customer activity. One of the travel industry customers I've been working with did this, and used the metric to drive a cost reduction program over the last nine months. Amongst many other optimizations they implemented autoscaling to drive up average utilization. When COVID-19 hit, their customer traffic dropped, and their autoscalers maintained high utilization on a smaller footprint, so their AWS bill for that workload automatically reduced.&lt;/p&gt;

&lt;p&gt;AWS is working with many customers and partners to help cost optimize in these uncertain times. After my &lt;a href="https://medium.com/@adrianco/cloud-native-cost-optimization-f379c2f623e9" rel="noopener noreferrer"&gt;Medium post&lt;/a&gt; Erik Peterson of CloudZero reached out to me to discuss their product which implements automatic tagging and allocation of metrics to help SaaS engineering teams continuously optimize their AWS spend. If this sounds interesting CloudZero Inc and AWS are offering through the end of May &lt;a href="//www.cloudzero.com/marketplacepromo"&gt;a 20% discount, $1k credit and a free 30-day trial with upfront waste assessment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The orignal &lt;a href="https://github.com/Teevity/ice" rel="noopener noreferrer"&gt;NetflixOSS tool that implemented this was called Ice&lt;/a&gt;, and they outgrew it, and passed it over to &lt;a href="https://www.teevity.com/" rel="noopener noreferrer"&gt;Teevity&lt;/a&gt;, who maintain their own version.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cost</category>
      <category>netflixoss</category>
      <category>cloudzero</category>
    </item>
  </channel>
</rss>
