Firstly, I'm not solving anything. I'm explaining why fallback URLs are not equivalent to CDNs.
You don't use a CDN because your site doesn't work, you use it because it's faster.
Secondly, no, doing an occasional speed test, using data you'd be downloading anyway, then selecting an endpoint between speedtests does not increase bandwidth usage by 3x.
Baffled.
That extra bandwidth is a rounding error in the grand scheme of things.
It could be important, though, for the client to signal the server to close the connection. Theoretically the connection would drop after several seconds and the server would stop transmitting, but I could imagine some middleware cheerfully downloading the whole stream and throwing it away.
Then the instruction to stop the download is not instantaneous, so by the time you realize you have downloaded 1kB on the client side, the server might already have sent the whole video segment on the other side, so this is not the way to go in order to optimize congestion
If you want to do it on a sub-asset (video segment, or image or JS file) level, it's possible by doing byte-range requests (ask bytes 0-100 from CDN A and 101-200 from CDN B), but in that case you still add some overhead for establishing the TCP connection, and in the end as you need the whole asset to use it, you'll just limit the download speed to the minimum of the two.
[0]https://blog.streamroot.io/abr-algorithms-work-optimize-stac...
As a silly limiting example, imagine that you host Netflix on your dial-up connection as url A.
It works.
Oh, okay, right, let's set a timeout then, if it takes more than 1 second to load, we try url B.
That works, but now we've got a 1 second delay on everything. Okay, we'll update the default to be url B.
Conditions are changing all the time as a result of bottlenecks in the infrastructure moving about.
What I think you'd actually need to do is something like this - initially, fetch from multiple endpoints simultaneously with an early-cancel (so you don't waste bandwidth on the slower ones).
For N seconds you just use the fastest one (perhaps with an 'if it doesn't work' mechanism, sure).
Every N seconds you re-evaluate the fastest endpoint using the multi-fetch.
And so on and so forth.
There are better algorithms, this is back of the envelope stuff.