|
|
Subscribe / Log in / New account

Bose and Kubernetes

By Jake Edge
January 2, 2019

KubeCon NA

Dylan O'Mahony, the cloud architecture manager for Bose, opened a presentation at KubeCon + CloudNativeCon North America 2018 by noting that many attendees may be wondering why a "50-year-old audio company" would be part of a presentation on Kubernetes. It turns out that Bose was looking for ways to support its smart-speaker products and found the existing solutions to be lacking. Bose partnered with Connected, "a product development company from Toronto", to use Kubernetes as part of that solution, so O'Mahony and David Doyle from Connected were at the conference to describe the prototype that they built.

Problem

[Dave Doyle, Dylan O'Mahony, and the devices]

As a way to demonstrate the problem they were trying to solve, O'Mahony spoke to an Amazon "Alexa" device (an Echo Dot) and asked it to play a particular song "on stage". That led the nearby Bose smart speaker to start playing the tune. Since both devices have wireless interfaces, it would seem like making that work would not be all that difficult, he said. But it turns out to be harder than it looks. There is no direct interface between the two devices; it all must be handled in the cloud. So it takes hundreds of miles of cable to bridge the three-foot gap between the two devices on stage.

The Amazon device does all of its voice processing in the Amazon cloud, which then hands off instructions to the Bose cloud. The speaker is not directly exposed on the internet; it can send out messages, but it is unable to receive random messages from the net. The easiest way to handle that is to have the speaker make a persistent connection to the Bose cloud when it powers up. MQTT was chosen as the protocol; a persistent bidirectional WebSocket connection is made between each speaker and the cloud service.

The "crux of the problem" is scaling; solutions abound for thousands of connected devices. When he looked around a few years ago for Internet of Things (IoT) products, he couldn't find any that could handle the five-million (or more) connections envisioned for the system. Some managed services would scale to hundreds of thousands of connected devices, but not to millions, he said. That is why Bose engaged with Connected, which was able to help prototype a system that could handle that many connections using Kubernetes.

Solution

Doyle then stepped up to fill in what was done—and how. He noted that scaling for web applications is largely a solved problem, but that is not the case for scaling messaging applications. Four people at Connected worked on the project in two teams: makers and breakers. The makers were tasked with building the system, while the breakers were building the "test rig". People moved around between the teams to get exposure to both sides of the problem.

There were a lot of choices they could have made for the different parts that made up the stack, but their methodology was to find the first thing that would work and run with it. The Bose cloud infrastructure (nicknamed "Galapagos") was Kubernetes on AWS; it does not use Amazon's managed Kubernetes product (EKS). That part was handled by a small team at Bose. Each of Doyle's team's members had a full rollout of the stack available to be used; Minikube is fine, but "if you are going to build something at scale, you really have to test at scale", he said.

As O'Mahony had mentioned, MQTT was used. It is the dominant communications protocol for IoT applications because it is lightweight. The devices set up a persistent WebSocket connection to the cloud, but something other than "magic" is needed to handle all those connections. For that, they used VerneMQ.

The high-level picture (which can be seen in their slides [PDF]) has HAProxy as a front-end load balancer feeding VerneMQ acting as a message broker. They created their own "uncreatively named" service, called "the listening service", which picks up the device status messages from the speakers and stores a "shadow state" of the device in an Apache Cassandra database. The shadow state consists of the speaker volume, what it is playing, its firmware revision, and so on.

There are plenty of examples of configuring Kubernetes for HTTP ingress handling, but there were not many examples for ingress handling of straight TCP, he said. They were not using HTTP, but could not find examples of what they were trying to do so they chose HAProxy since it is the de facto standard for proxying and load balancing. It has been a good choice; it is "rock solid" and uses a "ridiculously low" amount of resources for a huge number of connections.

VerneMQ stood out as a message broker for a number of reasons. It is written in Erlang and the Open Telecom Platform (OTP), which were originally used in telephony applications; that makes it a good base for clustering and concurrency, he said. It also easily scales both vertically and horizontally. In addition, it is an open-source solution, which was important. Other solutions did not fit the bill because they were proprietary or lacked other features needed. VerneMQ provides bridging, which will be useful in some of the future plans as well as shared subscriptions (from MQTT version 5). The latter allowed VerneMQ to load balance between the different listening services in a round-robin fashion. Beyond that, VerneMQ maintained the time order for messages, which is important when handling speaker commands.

[Dylan O'Mahony and Dave Doyle]

The glue is the listening service, which they wrote in Go. It is pretty straightforward; it only contains about 100 lines of code. It simply subscribes to the VerneMQ stream as a shared subscription, processes any status change messages, and writes the changes to the shadow state to the database. It is lightweight and scales easily.

The shadow store is a digital duplicate of the state of the device in the cloud. One of the questions they had was whether Cassandra could keep up with the volume of messages, which it handled easily. It is a non-relational database that turned out to be performant and fault tolerant, while also being "massively scalable" and quite stable. It was an important part of the proof of concept, but Doyle said he would not be mentioning it much more in the talk since they had few problems with it.

He then described how they put it all together on Kubernetes. The container images were all built from scratch using Alpine Linux, which resulted in small images. Because they are clustering services, VerneMQ and Cassandra are run as Kubernetes StatefulSets; that way, Kubernetes brings them up in order and gives them a consistent name in DNS. HAProxy was configured as a DaemonSet to ensure that it was deployed on each ingress node. The listening service, Prometheus, and Grafana were handled as Deployments; the latter two provided visibility into the cluster for management and diagnosing problems.

Testing

For the "test rig", they chose Locust. The "breakers" half of the team looked into other options, such as MZBench and Apache JMeter, but found them to be less flexible and not made for publish/subscribe (pub/sub) models. Locust is Python-based with a master node that instructs workers to simulate various loads and types of traffic. These were deployed on bare AWS EC2 instances and were not part of the production Kubernetes cluster.

Doyle then described some of the problems that were encountered on the way to supporting five million connections, but noted that it was "by no means an exhaustive list"; there were plenty of other problems in both the production code and the testing setup that were encountered and surmounted.

To start, they used one Locust worker to see how many connections it could make; the first result was an "underwhelming" 340. It turned out to be a problem with Python file-descriptor limits; three were consumed for each MQTT connection and Python was limited to 1024 in total. They tried replacing select() in the Eclipse Paho MQTT library with asyncio, but that did not play nicely with the Locust concurrency model. In the end, they simply rebuilt Python to increase the hard-coded size of file-descriptor sets. That resulted in roughly 10,000 connections per worker.

Moving on to a multi-worker test, they hit a barrier at around 700,000 concurrent connections. That was due to configuration defaults for HAProxy and VerneMQ as well as some problems with an additional layer of network address translation (NAT) because VerneMQ was set up as a Kubernetes Service abstraction. The workaround for that was to reconfigure everything, add more listeners for VerneMQ, bypass the Service abstraction, increase the network and I/O bandwidth of the HAProxy nodes, and ensure that HAProxy was doing a round-robin of VerneMQ nodes.

That allowed them to break the one-million barrier, but only to 1.1 million connections. At that point, subscriptions were failing due to VerneMQ nodes being terminated; Kubernetes brought them back up, but it impacted the number of concurrent connections that could be supported. This problem was harder to figure out, he said; they tried to incrementally scale VerneMQ from ten to 80 nodes, but that made no difference. Grafana and Prometheus were "absolutely key" to tracking the problem down. They eventually found that the broker would immediately subscribe connecting clients, which could overwhelm the other VerneMQ servers. The solution was modify the clients to add an exponential backoff delay between connecting and subscribing; that allowed VerneMQ to recover.

The next barrier was at 1.5 million connections; at that point, the Erlang OTP schedulers all went to 100% CPU utilization. Erlang has lightweight threads and for each CPU available to it, Erlang adds a scheduler for that CPU. Adding more resources for VerneMQ, which is the Erlang component, did not help. It turned out that Erlang OTP is not control-group aware, so even if it had 12 virtual CPUs (vCPUs) available to it, only four would be used. The solution was to directly configure the number of vCPUs in Erlang.

There were some other stopping points along the way, Doyle said, but eventually they were able to reach 4.85 million connections. One could perhaps claim that was five million ("what's 150,000 between friends?") but it still wouldn't feel quite right. The problem was resources again, but testing was expensive. It took around five hours to bring up all of the connections; at one point, they "blew through" their monthly testing budget in a day. "But we were getting so close", he said.

It came time to do an internal demo. They upped the resources one more time and were able to get to five million and one active, concurrent WebSocket connections, he said to applause. The average latency for a published message to reach a subscriber was 69ms, which is below the "magic number" of 250ms so humans will not perceive a delay. The system was publishing nearly ten thousand messages per second. There were 12 different testing scenarios that were used and one of the others could reach 25 thousand messages per second.

Lessons

There were a number of lessons that came from this project, which he wanted to pass along to attendees. First up was to pay attention to your dependencies. By design Kubernetes does not track or manage dependencies between the various parts of the system, but that was a little surprising to him as an application developer. They bring up the services in a particular order to try to get a handle on that, but there are still areas that needed some thinking. For example, when is a service actually up? Is it when one replica has started? Or half of them? Or all of them?

He recommended experimenting with resource limits. The proper values are hard to figure out; try out lots of different workloads and scenarios. "Do component-level load testing", he said; there will be a need for rate limiting, it can't be avoided for running at scale. Troubleshooting is made more difficult by all of the different layers in play. The more layers there are, the more problems there are in figuring out where problems lie. "This is why setting up monitoring early matters so much."

Starting out at scale is different than getting there via organic growth. When the system is growing, it will hit certain walls, as they did, but each needs to be surmounted before (sometimes almost immediately) smacking into the next one. Effortlessly scaling a system is a boring feature, but it is a "killer feature of Kubernetes". It is incredible to be able to simply double the size of a cluster at the snap of your fingers, he said.

Finally, he was surprised by how much cheaper their solution is compared to the alternatives; they expected the cost to be less, but the projections show it to be more expensive at the start, but decreasing (on a cost per device per year measure) over time to a much lower cost than alternatives. No actual numbers were shown, but that is what Bose has calculated. All of that was "only possible through the flexibility of Kubernetes", Doyle concluded. In the Q&A, O'Mahony noted how happy Bose is with this work and that moving to Kubernetes is a "really good choice" for the company.

A YouTube video of the presentation is available.

[I would like to thank LWN's travel sponsor, The Linux Foundation, for assistance in traveling to Seattle for KubeCon NA.]

Index entries for this article
ConferenceKubeCon NA/2018


to post comments

Bose and Kubernetes

Posted Jan 2, 2019 20:24 UTC (Wed) by rghetta (subscriber, #39444) [Link] (11 responses)

Technical prowess aside, to me this trend toward having every appliance connecting to a manufacturer server in order to work is maddening.

Bose and Kubernetes

Posted Jan 2, 2019 20:49 UTC (Wed) by rahvin (guest, #16953) [Link] (9 responses)

I agree, IOT devices should be cloud independent as much as possible. Obviously this is much harder with a speaker type product that is relying on external computer resources for data and processing but the product shouldn't simply die without cloud access.

I specifically bought the Rain Machine irrigation controller because it was cloud based, but continues to function without the cloud in place and it openly hackable by owners. In my mind this was the way to properly design a IOT device, in that it can and will perform it's primary duties without cloud access and owners have the ability to take control of the device in the event the company goes bankrupt or like Logitech decides to abandon the product.

Back on topic, I'm not familiar with the message protocol being used by Bose, does anyone know if it securely encrypted so that someone can't spy on or monitor connection traffic? These speakers are damn scary to me as owners are basically self bugging their homes and allowing these speakers to hand over all audio to internet connected clouds which may or may not be secure.

Bose and Kubernetes

Posted Jan 2, 2019 21:27 UTC (Wed) by Cyberax (✭ supporter ✭, #52523) [Link] (3 responses)

Avoid all the cloud nonsense and go ZigBee or ZWave route.

For example, I have Halo+ smart smoke alarms. Their parent company went out of business last year, btu the alarms themselves work perfectly fine and will be supported for their rest of their usable lifetime (10 years).

As an added bonus, ZigBee and ZWave are mesh networks and are more reliable than WiFi when you add enough repeaters (mains-powered devices).

> Back on topic, I'm not familiar with the message protocol being used by Bose, does anyone know if it securely encrypted so that someone can't spy on or monitor connection traffic?
MQTT is typically transferred over SSL.

Bose and Kubernetes

Posted Jan 3, 2019 0:48 UTC (Thu) by gerdesj (subscriber, #5446) [Link] (2 responses)

I agree with Cyberax: avoid "cloud" for home IoT. For me all devices should have a manual override/equiv. where possible and nothing should fail if the controller fails.

I've spent a while looking into both ZigBee and ZWave. They are not quite more reliable than wifi exactly because all three use "free air" as a medium. ZigBee is a bit more free form - any device can claim compliance but there are *ahem* versions eg Ikea Tradfri and Philips Hue (both claim to work with each other now - there are many others). ZWave requires certification but there are several revisions. So far I see ZWave as more expensive but generally more compliant with standards. Its not all happy clappy though. I also note that devices are generally better built/documented for ZWave (my opinion) and for my needs that is important.

I have decided to focus on ZWave for my gear but I do keep a ZigBee USB dongle wired up for experiments.

MQTT is an absolute belter - very clean and simple. Owntracks, Mosquitto might be keywords. You can put mosquitto behind HA Proxy (to do SSL properly)

Bose and Kubernetes

Posted Jan 3, 2019 3:28 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link]

> They are not quite more reliable than wifi exactly because all three use "free air" as a medium
ZWave and ZigBee have a much lower bitrate than WiFi so they are seriously more reliable, and they also can use sub-GHz bands that are not as polluted as the 2.4GHz WiFi band.

> any device can claim compliance but there are *ahem* versions eg Ikea Tradfri and Philips Hue (both claim to work with each other now - there are many others)
I have tested multiple ZigBee devices and so far they appear to interoperate just fine.

With ZWave it's not so much certification as the fact that there's only ONE manufacturer of ZWave chips. And these chips are based on Ye Olde Intel 8051. On the other hand, _all_ ZWave devices are compatible (even pre-ZWave-1.0 ones).

Bose and Kubernetes

Posted Jan 3, 2019 7:22 UTC (Thu) by zdzichu (subscriber, #17118) [Link]

What's wrong with TLS support in Mosquitto itself?

Bose and Kubernetes

Posted Jan 2, 2019 22:44 UTC (Wed) by adam820 (subscriber, #101353) [Link] (1 responses)

From the looks of the device in the picture, they're using a Bose Home Speaker 500 which states in the FAQ that in addition to the Wi-Fi/Cloud stuff, it also supports standard Bluetooth and 3.5mm input jack. So it looks like, in the event that the cloud stuff folds for whatever reason, it will continue to function as a regular 'ol speaker.

I do agree that anything I would purchase that is cloud-enabled should have that as something I can opt-in to using for convenience. I wouldn't want anything where the core functionality of the device stops simply because some remote service is no longer available.

Bose and Kubernetes

Posted Jan 10, 2019 15:17 UTC (Thu) by Wol (subscriber, #4433) [Link]

> where the core functionality of the device stops simply because some remote service is no longer available.

I don't know as I'm that unusual, but in my house the internet seems to fall over as a matter of course many evenings. Oh - I live in a major European capital - London ...

And I think the problem is the infrastructure outwith my house, so there's nothing I can do about it other than pay megabucks for an unwanted internet upgrade - I probably only use a fraction of what I'm paying for now ...

Cheers,
Wol

Bose and Kubernetes

Posted Jan 13, 2019 13:09 UTC (Sun) by nix (subscriber, #2304) [Link] (2 responses)

I specifically bought the Rain Machine irrigation controller because it was cloud based, but continues to function without the cloud in place
This is such apt naming. An irrigation controller that only works when it's cloudy would be less than useful :P

Bose and Kubernetes

Posted Feb 19, 2019 0:00 UTC (Tue) by rahvin (guest, #16953) [Link] (1 responses)

But don't Irrigation controllers make rain?

Bose and Kubernetes

Posted Feb 19, 2019 11:50 UTC (Tue) by nix (subscriber, #2304) [Link]

Being really pedantic, a cloud-based irrigation controller would presumably float in the cloud layer and produce irrigation by triggering rainfall. So yes, you're quite right! (I'm not sure where it gets the water from when the cloud isn't in place. Really long hoses that stretch all the way down to ground level? This modern technology, it's marvellous.)

Bose and Kubernetes

Posted Jan 3, 2019 10:33 UTC (Thu) by nilsmeyer (guest, #122604) [Link]

100% agree, especially since there seems to be no benefit to the user. Imagine buying a speaker and then having to sign up for another cloud service, sharing ever more of your personal data, then having it work only if the service is available, the speaker firmware is current and you have a working internet connection. What is the value proposition for the customer here?

Bose and Kubernetes

Posted Jan 3, 2019 6:18 UTC (Thu) by jaymell (guest, #106443) [Link] (1 responses)

Very nice write-up of the discussion. I found it interesting that Kubernetes 'services' (generally virtual IPs routed with iptables NAT'ing) ended up being discarded relatively quickly in the process of addressing bottlenecks. I have recently been dealing with scaling issues in a Kubernetes-based environment and hadn't seriously considered the bottlenecks the additional NAT'ing might be posing.

Bose and Kubernetes

Posted Jan 3, 2019 7:20 UTC (Thu) by zdzichu (subscriber, #17118) [Link]

In general, networking in Kubernetes seem like a temporary solution promoted to production. K8s started with utilizing iptables' NAT rules. This came about 15 years (!!) after Linux world noticed that iptables is not suitable for highly dynamic environments and started to work on better solutions, like nf-hipac (https://lwn.net/Articles/10951/).

Only quite recently k8s gained support for using IPVS (Linux IP Virtual Server) for networking (https://www.youtube.com/watch?v=4-pawkiazEg, Scale Kubernetes to Support 50,000 Services [I] - Haibin Xie & Quinton Hoole).

It is suprising, for Linux-native container solution to skim over Linux networkinging progress. Over the course of history, kubernetes started with obsolete solution (iptables), ignored nftables, only started to utilize a solution devised in 2002 (ipvs)… but began to flirt with eBPF :-) https://kubernetes.io/blog/2017/12/using-ebpf-in-kubernetes/

Bose and Kubernetes

Posted Jan 3, 2019 13:37 UTC (Thu) by jerojasro (guest, #98169) [Link] (1 responses)

> There is no direct interface between the two devices; it all must be handled in the cloud. So it takes hundreds of miles of cable to bridge the three-foot gap between the two devices on stage.

I feel like I'm missing something, but, it seems to me all of this kubernetes-massive-cluster effort is unnecessary, and they should just devise some scheme for delegating authority for certain commands to the user's alexa over the user's bose speaker, and then having the alexa authenticate and connect to the speaker via the local network.

Yes, it requires work on both the amazon and bose devices, but still...

Bose and Kubernetes

Posted Jan 3, 2019 18:42 UTC (Thu) by excors (subscriber, #95769) [Link]

It seems the Alexa platform is designed to make Alexa devices relatively simple, so they can be cheap and ubiquitous. Anyone can use the Alexa Voice Service API (https://developer.amazon.com/docs/alexa-voice-service/api...) to add Alexa functionality to anything with a microphone and speaker and internet connection; you just send audio to Amazon's cloud service, and implement a few interfaces to play the returned audio etc. Since most of the logic is in the cloud, users get a reasonably consistent experience across all devices. Adding more device-side logic - like a reliable performant secure authenticated way for them to proxy commands to other non-Alexa devices on the local wifi network - has both the cost of implementing it on many devices, and the cost of confusing users when some features work on some Alexa devices and not on others.

Sometimes device-side logic might be worth the costs, like how some Echoes have Zigbee support to communicate with nearby IoT devices - otherwise the user would have to buy a separate internet-connected Zigbee hub, and nobody likes buying hubs (they're expensive and don't appear to do anything). But if the IoT device is already connected to the internet, like a smart speaker whose primary function is to stream music from the internet, it's not that hard for the manufacturer to provide their own cloud to send commands to their device. (If they don't want to implement it all themselves, they can buy the service from Amazon (https://aws.amazon.com/iot-core/) or probably Google or Microsoft or whoever). Then users will be happy their new smart speaker is compatible with even the oldest or dumbest Alexa devices.

That also means the manufacturer can add support for Google Home or Bixby etc with no device-side changes at all - they just connect their own cloud to the Google cloud etc, and the device should work exactly the same. So it's good for reducing vendor lock-in and allowing competition between voice assistants.

Bose and Kubernetes

Posted Jan 4, 2019 11:59 UTC (Fri) by zoobab (guest, #9945) [Link] (1 responses)

Did they evaluate ZeroMQ?

The malamute broker can handle lots of connections, unfortunately there is no MQTT support at the moment.

Bose and Kubernetes

Posted Jan 4, 2019 12:38 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

ZeroMQ by itself doesn’t do connection balancing or anything smart. It’s more like an advanced socket rather than a messaging system.

Bose and Kubernetes

Posted Jan 8, 2019 14:58 UTC (Tue) by robbe (guest, #16131) [Link]

It’s hard to understand their choices and issues unless you already know what their product/service offers.

Does their speaker get audio from a the Bose service, or is it just a rendezvous point to route commands (from Amazon or elsewhere) to the speaker? I assume the latter … the mind boggles at the technical effort burnt because the Internet lost end-to-end in the nineties.


Copyright © 2019, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds