Ask HN: Strategies for database reliability when I have no control over the DB?
Working in a corporate enterprise type environment. Very crufty. Unfortunately my application environment, which is very modern, relies on an old, old corporate DB. I have spoken with the dbadmins and they are not willing to help out to make things more reliable, they're pretty siloed off from everything else and don't answer to anyone to help. The team has no SLOs and the best I can see is about 90% uptime. In the end this may be a policy question, but for the short term I need to manage reliability of my applications so I can hit my SLOs.
So from my perspective, how do I manage this? Back up the DBs in my environment as best as possible and serve traffic from there, or cache everything? Data is constantly being added to the old DB, which holds user data. I was thinking about creating a bunch of DB shards in my environment with LBs in front of them with long-lived connections to the old DB, and if the user makes a request, if the old DB is down, serve from the backup shard. Maybe sharding is too complicated for this scenario. Advice?
36 comments
[ 1970 ms ] story [ 1817 ms ] threadToo complicated or not, if you can get away with it I would do the sharding project for the fun/experience/learning.
1b) Where are your SLOs even coming from? If the db team offers no SLO, you have no business offering one yourself, or if you do it needs to be something that takes into account observed backend reliability, not something imposed by a pointy-haired boss.
2) I'm skeptical about the sharding solution. If the data you're using doesn't need to be shared across teams, consider just setting up your own db.
3) Aggressive caching and prefetching might improve the end user experience.
4) Graceful degradation. Build your UIs such that if one call to the DB fails, it only breaks a minimal part of the page, not everything.
This sounds more like an organizational issue, though. The most value you could provide to the company sounds like it'd be breaking through those institutional barriers. More likely than not you'd try and fail (nature of these things, not a knock on you), but it's worth a shot.
What specifically did you ask for when you say "they are not willing to help out to make things more reliable"?
If the corporate DB has 90% uptime then you need to tell your boss and internal customers that the max limit of uptime is that 90% figure. If that is not acceptable then your manager needs to deal with the db team manager. I am a little confused on how an old DB only rates 90% since mainframes and iSeries boxes are way above that. How modern your application environment is or how crufty the enterprise db is irrelevant to any talks between teams.
It sounds like you are able to deploy your own infra, and it sounds like you are not making any writes to the db.
These two factors make the app significantly easier, versus needing to hold writes (and deal with reads to that augmented database) until the backing db comes back online. (CRDTs are a nice way of expressing growing a database over time, but an old old corporate DB sounds like some mess in SQL.)
The main principle is that you're going to serve queries from your own system, and your system is informed by $OLD_DB. You're going to have, ultimately, a `last_updated_at` attribute on everything you know.
You're going to, ultimately, stream all of $OLD_DB into $NEW_DB. If a DB query to $OLD_DB is over HTTP, then the query bodies are a bit larger and slightly ungainly and very easy to cache; by sticking a caching proxy in front of that HTTP endpoint and telling it to keep EVERYTHING and serve stale content and looking at the headers that come back, now you have database queries that can be as stale as necessary.
Assuming your boss is held responsible, I would design the system to treat the database like an unreliable API. Wrap up all operations in a DAL and interact with a local database. Do regular transactional sync operations in the background. In case of data conflict, determine who wins and why in each case.
Don't spend too much time on the design. Just enough to get the point across.
Bring the design to your boss and say this is what I'm thinking given that we have an SLA but this critical dependency does not and has an observed uptime of 90%. And then let your boss decide what to do.
If you are the only one who will be held responsible and your boss doesn't support your design or go to bat for you, you work in a bad environment and should find a new job.
Here's how to do this with Kafka and Postgres: https://www.confluent.io/blog/bottled-water-real-time-integr...
A few other comments would be:
- do you have a read replica where you can do read-only queries? If not, that's also a good way to alleviate the burden on the primary db.
- would cache make sense? do you read often the same data and do joins every time? if so, I'd also consider a caching layer.
While it's easy to understand the bias to look for solutions without the aforementioned DBA, it's going to take a pretty significant, collaborative effort to define policies that works for all stakeholders.
The sooner the better! It's going to be a bit painful but I'd focus on addressing the root of the issue at hand.
My two cents :)
I ended up setting up a persistent ssh tunnel to the production server with autossh, and then writing a miniature daemon that would regularly poll tables in the production server, figure out recent changes, and write the changes to a log. A secondary process would read the log and copy the changes into the development environment.
By "regularly", I mean that it ran every minute.
autossh was used to keep the resident sysadmin from complaining about thousands of ssh logins. It also made the first daemon a little easier to write, since from its perspective, it was still connecting to a local database.
This worked surprisingly well. It wasn't fiddly or glitchy at all. Anytime there was a connection problem, things would stall for at most a few minutes until autossh could re-establish the connection, and then the reading daemon would happily work its way backward through the tables.
Essentially this is just building out a master -> slave database relationship, but with application logic instead of reconfiguring the DB environment. It didn't require a very large time investment to get it working.
If you can't reach a political solution, then you can add a band-aid with a technical solution. Just realize that this is only a patch and that in a few years someone (perhaps you) will be cursing the creator for not fixing the root issue.
You didn't specify if your app only reads from the old db, or if it writes to it as well. Either way you'll need to stand up some intermediary. What kind of intermediary really depends on throughput and data size, so we'd need more information to give useful advice.
1) When the system is down and you're asked for an explanation. You deliver a post mortem putting the responsibility on the database. The database is down. The database team is working on it.
2) If you are facing repeated major downtime. You keep track of failures caused by the database. You make a chart with a health check to the database every minute.
3) You report to your management that the database service doesn't meet expectations and it's affecting your services, supported by the previous reports you just created. It's the responsibility of the database and the management to run their services and decide where to allocate resources.
4) Make it clear that your service depends on its database. Any question about downtime or better SLA should be replied with the postmortem from 1 and/or the improvement plan from 3.
All you can do is report. You probably don't have a say. Your manager probably doesn't have a say. Maybe the database team doesn't have the power to fix anything either.
The actuall solution is tough, but I think something can be improved. First of all I would try to measure and root cause the problem. It's hard for me to believe that the DB has 90% availability, I'm not aware of any commercial DB that's this bad. I would avoid creating shards of db, it will lead to hard to debug data inconsistencies. In this regard, cache with reasonable TTL is a better choice wince it guarantees eventual consistency of the data. I would also take a deep look into retry approaches you can take, something like exponential backoff with jitter and properly adjusted number of retries can greatly increase your availability.
The OP is the customer and the database team is the service provider. It's their role to provide a service working within specifications. That's how it works in large organization. Most of everything is internal services providing services to other internal services.
Having zero control over the infrastructure and having to work with various teams can be a pain whenever you want to make a change, but they have a silver lining in that production issues are usually not your responsibility.
But with their response times, you would think it's not their responsibility either...
We took the simple approach, we had our own database server, so we had the DBAs setup a one-way replication of key tables we needed. We put stored procs and synonyms in front of those tables so in case they moved it wasn't a major expense to us, that also helped the DBAs feel better in case they needed to drop the replication. We also copied over any stored proc we needed to use, pointed them at our synonyms. This also helped to buffer any unintended consequences from an update to a stored proc. Average replication latency was 250ms, setup an alert to let us know if it went higher to let us tell the other teams they might start having issues.
The result, the entire company could be frozen from an open transaction on a key table, but our app could keep working. Effort level was low, results were amazing.
One question though: Did your app not need to propagate changes back to theirs? Like, say a customer moved from Canada to the USA and now you no longer needed to apply HST. How did you handle data going back the other way? Aren't you risking getting out of sync if the data is a two way propagation?
What software did the replication? Something built into the DB or 3rd party?
From a data protection/retention view: run a cache and use expiration in terms of weeks. Keeping the data as "backups" floating around is a recipe for heavy fines if someone decides to do an audit and finds some left over sqldumps.
If you do need a full backup/replication: get this written off by your superiors so you aren't on the hook in case someone decides to do an audit and determines you to being the one responsible.
This is NOT a technical problem to be solved with a technical solution. It is a management/organizational issue and should be solved at that level.
Some tips if you have to proceed:
1) Be clear you can promise a SLO for you app, but not it's dependancies. If the dependancies are down, some features won't work.
2) Have honest clear errors that explain the clear root cause. Cloudflare's "Web server is down" page is a great example. It pretty clearly say's "we're up, but they aren't".
As others have said, this is an organizational issue and the best way to handle it is to dig into the human politics.
Is there even any application or service that exists in your enterprise that can show high availability while using that database? Be careful to not become the pawn of a leader that is getting thrown under the bus by incumbents by being tasked with basically impossible duties and objectives. Even if the person’s intentions are noble that simply increases the chances of failure and your lessons therefore become lost (most large organizations and cultures seem to have a poor job reflecting carefully upon failures compared to trying to replicate successes no matter how circumstantial the nature of success).
Figure out how much you -really- have to sync with this database. If you can have an alternative source of truth for your apps, it will help (and you can then just best effort push back to the crufty DB)
If you can't make it so you have your own source of truth, determine if an outdated truth is better than no answer. For many problems this is the case. In that case, have all reads hit the crufty DB first, and failing that, your cache. Have a sync operation as well (or at least, everytime you read from the crufty DB, persist any return values to your cache). For writes, you can write to both as well, however, during times the crufty DB is unavailable, you'll need to decide if you should take the write to the local DB, and store the sync operation on a queue to retry, or if you should only store it on a queue to retry, hitting the crufty DB first, and only on acknowledgement there taking it to your own DB (basically, in the event of a write/read pattern while crufty DB is down, do you want it to read the last known synced value, or the last value written, even it hasn't made it to the crufty DB).
Either way, that can cause some interesting race conditions. Make sure you have good logging capabilities.
If neither of those is possible, if you absolutely -have- to rely on the crufty DB as a source of truth, that it's better to return no answer than an outdated one, you're screwed, from a technical perspective. Communicate the resulting failures fully, be clear where the fault occurred with the stakeholders, and that it's not something you control.
If not, copy the data. Reporting from a live system can cause all sorts of problems, including not being able to reproduce results.