How does the default recent posts widget work with cache?

Unless you have a memcached-type plugin installed, wp_cache_set will only store data for the duration of the current script. Call or add the widget again in the same instance & you’ll see it utilise the cache.

As for ob_get_flush(), taken from the manual:

Flush the output buffer, return it as a string and turn off output buffering

In other words, it prints and returns the buffer at the same time.