Hacker News new | past | comments | ask | show | jobs | submit login

CouchDB. It's rare that a piece of software is bad enough to give its language and runtime a bad name, but it's actually that bad.



Any complaints in particular? I had been contemplating CouchDB for a new application at work, maybe you have a link I could read about it? I thought that the incrementally updating mapreduce style views looked really powerful, especially when combined with the changes subscriptions / long polling features.


God, where to start.

Map/reduce views ("secondary indexes") are currently built by serializing JSON down a pipe to an external process called couchjs that links against a seven year old version of Mozilla Spidermonkey (1.8.5, released on March 31st 2011, and the only version it currently works with). This external process then pipes the map results back, again as JSON. Forget zerocopy; we're serializing and deserializing twice per document. Almost all of this "external view server" (the only kind AFAICT) is actually written in Javascript on that seven year old engine. Nothing is streaming; your map function is sandbox-evaled in that process, the results of a single call are stuffed into a Javascript array via .push, then stringified and printed on standard output as a single line. The entire internal "view server" protocol is based on a pipe of single-line JSON commands and data payloads. Performance (and likely security, due to age of the engine) in this subsystem is extremely poor IME.

You can write map/reduce views in Erlang itself as an alternative, but that engine is disabled by default due to security concerns – it's "not sandboxed". Performance in this area also appeared to be proportional to the code size of the map function, which sounded a lot like it was being serialized down a pipe with no caching.

If you make a change to a single view in a design document, the database system will rebuild all indexes in that design document unconditionally, even if the other view code hasn't changed. The only way to prevent this is to store a single view per design document, and manage those documents yourself.

Once you've endured your multi-day index rebuild on a couple million documents, you'll also have to issue an extra "cleanup" command to delete the old (now essentially useless) indexes. It's a full rebuild, so you need 2x the space at a minimum to pull it off.

The data itself is stored in a single file per shard, opened in O_APPEND mode, effectively serializing all writes on the shard. You also will not see kswapd active, ever, because the OS VMM is not being used effectively – no shared memory for IPC, and no use of mmap AFAICT.

Server-side changes feed filters appear to be extremely slow when compared to just filtering the results in the client.

Authorization: limiting read access will be difficult at best. Transactional behavior: no, aside from a single bulk write feature (make sure to use "all or nothing" mode though).

Logging: signal to noise ratio is poor. Giant stack traces for minor events. You may even see strings emitted as UTF-32 arrays of integers in base 10. Hope you brought an ASCII table at least.

Documentation: The following passage from section 5.2.5 of the CouchDB v2.1.1 manual just about says it all: "Views with the JavaScript query server are extremely slow to generate when there are a non-trivial number of documents to process. The generation process won’t even saturate a single CPU let alone your I/O. The cause is the latency involved in the CouchDB server and separate couchjs query server, dramatically indicating how important it is to take latency out of your implementation." I can't say anything nice here about that last sentence, so I'm just going to keep my mouth shut.

But worst of all: every time it starts up, it tells me "it's time to relax". Nothing about this is relaxing.

(These are my own private individually-held views, and do not reflect the views of any employer or organization)


> Nothing is streaming

Except CouchDB entire REST API, where nearly every endpoint streams result row by row, which is great.

> Performance (and likely security, due to age of the engine) in this subsystem is extremely poor

As of security: wrong guess. Go compare number of critical CouchDB CVE for last, say, 5 years, with any other DB you want.

As for query server: indexing is slow for the reasons you pointed out. Requesting persisted index is ok. Taking in account CouchDB persists everything, it‘s not in-memory DB (which is again great), I‘d say it‘s even fast.

> Performance in this (Erlang) area also appeared to be proportional to the code size of the map function

Performance in this area depends much more on how branchy is the json doc being processed. It‘s not about CouchDB itself, it‘s about json parser used. There might be a situation when you have better perf using JS views.

> Nothing about this is relaxing.

Indeed. But then it just works, for years, with zero maintenance even for replications – the result I‘ve never even nearly achieved with any other DB I used.


> Except CouchDB entire REST API, where nearly every endpoint streams result row by row

I'm talking about the internals of couchjs.

> As of security: wrong guess. Go compare number of critical CouchDB CVE

I'm talking about Spidermonkey 1.8.5, which is seven years old. Multiple CVEs have been reported including a full RCE, which was patched in later versions. If you believe these are patched in libmozjs185, I'd love to see a link to the source package showing where the fix was applied. Because I can't find it.

Further: https://www.cvedetails.com/vulnerability-list/vendor_id-45/p.... Another full RCE in CouchDB.

> Performance in this area depends much more on how branchy is the json doc being processed

Citation needed. There's an issue specifically about this in the CouchDB issue tracker if you'd like to read more.

> As for query server: indexing is slow for the reasons you pointed out.

Right. It is not performant. That's my point.

Curious what kind of database sizes you're working with too; you won't see this stuff with a few hundred documents.


> I'm talking about the internals of couchjs.

_list functions stream, and was specifically designed to be able to stream. However, streaming does not help much in this case, moreover too small chunks dramatically reduce already awful _list perf.

Taking this in account I see no value for views to stream. Sending all emitted KVs for the doc to Erlang bits in one turn seems both much more predictable and safe.

> Multiple CVEs have been reported including a full RCE, which was patched in later versions

Last CVEs has nothing to do with Spidermonkey. BTW they may be patched without upgrade, with 5LOC long design document in Erlang.

The main reason of last CVEs is inconsistency in parsing improper JSONs by Erlang parser. Namely, most JSON parsers process '{"abc":1, "abc":2}' as {abc:2}, but old jiffy parses it as {abc:1}. BTW severe inconsistencies in parsing JSON are pretty common across implementations, please read http://seriot.ch/parsing_json.php for more details.

> Citation needed. There's an issue specifically about this in the CouchDB issue tracker if you'd like to read more.

I‘ll give you no cite, sorry, because we discovered the effect during internal tests. Reason is simple: accessing values in deep branchy JSONs is generally faster in JS, because it‘s native format. JSON in Erlang is a monster like {[{<<"abc">>, 1}]} for {abc:1}, which, when has a lot of levels and nodes at each level, performs bad for selecting random node.

> Curious what kind of database sizes you're working with too

We sometimes measure number of docs with M postfix ) Not very often, however. In my humble opinion, if you plan to have CouchDB with, say, 100M docs in a single bucket, you probably chose wrong solution.

BTW, same for large kitchen DBs for buckets with, say, 10K docs.


> I‘ll give you no cite, sorry, because we discovered the effect during internal tests

We discovered the issue in internal tests and reported it upstream where it was confirmed; there's nothing to discuss here.

> BTW they may be patched without upgrade, with 5LOC long design document in Erlang.

I don't have to hand-patch other database systems. Further, as of now there are no functioning packages for multiple versions of Ubuntu. Multiple competitors do not have any of these problems.

> Last CVEs has nothing to do with Spidermonkey

It was a full RCE that didn't have vendor packages ready in time.

Sorry, but using seven year old language runtimes is daft. It might be fine for you, but it's not appropriate in environments where you care about security and performance, or care about the overhead of making your team reason about these things unnecessarily.

> We sometimes measure number of docs with M postfix

Yeah, we did this in 2003 on commodity hardware, and even it built indexes faster than CouchDB builds map/reduce indexes. Fix the external view server protocol or be honest with people and kill it off – the status quo is unacceptable.

Finally, here's a five year old issue that's still open admitting what I just explained: https://issues.apache.org/jira/browse/COUCHDB-1743


100M docs? Of json format? On commodity hardware? In 2003?

Hahaha, hello long waited friend from parallel universe!


Easy enough to convert on the way out, using a mature database system without these performance flaws. The app got done and performed well, and we weren't at the mercy of an unresponsive community that leaves seven year old dependencies in critical paths.

Keep going; it'll bite you eventually. Don't say you weren't warned.


Correction: the library is too old for that specific CVE to be exploitable. There may be others, there may not be. I don't know – and that's actually the problem.

The chief complaint here is that it's very hard to reason about the security of seven year old software that distros are pulling out of their package repositories citing security issues (e.g. Alpine Linux). Advisories tend to say "versions before X", and you're left to either wonder or read tickets/code. Not everyone wants to sign on for that, and it's work that isn't going toward writing your app.


For balance: there is a newer query/index system called Mango in Apache CouchDB 2.0+, that IIRC is internal and doesn't rely on any external view server. It wasn't in 1.7.1, though, so if you're coming from there, it's very much a "switch query APIs to get tolerable performance" situation.


Also for balance: it's unclear if there are CVEs. There may not be any that are exploitable due to the age of the library (i.e. the bugs landed post-release). However, it's also very tricky to rule these out one by one, and the dependency is slated for removal from some distros.

There may be no material security issue. But the age of the software does not instill confidence, and newer engines are likely far more performant.


> You can write map/reduce views in Erlang itself as an alternative, but that engine is disabled by default due to security concerns – it's "not sandboxed".

I get the impression the author(s) of this DB were still at the stage of needing to brow-beat the infrastructure into submission, or somesuch :S


One of the stated goals on their Spidermonkey replacement issue (N.B. it still won't fix the view server protocol performance, but at least it'll be a modern engine) is "Get my C skills back out of the closet", and will require https://github.com/jquery/esprima.

It's depressing.


> You can write map/reduce views in Erlang itself as an alternative,

Or you can use a query language mostly similar to what MongoDB uses http://docs.couchdb.org/en/2.0.0/api/database/find.html

> If you make a change to a single view in a design document, the database system will rebuild all indexes in that design document unconditionally,

That's a feature. If they don't usually change together put them in a separate design documents.

> and manage those documents yourself.

It's a document database. So managing documents yourself is kind of what you do. Isn't it?

> he data itself is stored in a single file per shard, opened in O_APPEND mode, effectively serializing all writes on the shard.

So have more shards? A lot of databases use append only mode. There is a reason for that. Having uses the db for a good number of years, it had never lost data. Even during power outages or brutal restarts. That's more than I can say about other databases.

> no shared memory for IPC,

Shared memory IPC doesn't magically solve problems but it is a minefield of bugs.

> use of mmap AFAICT.

Large blocks of allocated memory use malloc instead of brk so memory allocation uses mmap. For file IO mmap isn't a panacea either. If data is not there, reads will still go to the disk. If it uses regular reads through data should end up in the page cache

> kswapd active,

Hmm, seeing kswapd being active is not something I look forward on a production server. From what I remember I have seen page cache utilized correctly and that's what should matter. Not kswapd.

> Transactional behavior: no, aside from a single bulk write feature

bulk docks is not a transactional feature. The database is not CP database so it doesn't have transactional feature.

> But worst of all: every time it starts up, it tells me "it's time to relax". Nothing about this is relaxing.

Yeah that is silly never liked that. From what I remember it was a DB that was built when MySQL ruled the open source DB world and many of the current DBs were not there. It was actually pretty relaxing being able to insert regular json object in it, index them, have master to master replication (which most dbs still don't support), have a nice built in web dashboard to inspect and query documents.


> Or you can use a query language mostly similar to what MongoDB uses

Yes, provided you started on 2.0, as I specifically stated in a reply.

> That's a feature. If they don't usually change together put them in a separate design documents.

Unnecessary computation and I/O is not a feature. They should hash the views individually. A database that makes me do extra work to keep it from doing unnecessary work is not helpful.

> So managing documents yourself is kind of what you do. Isn't it?

This doesn't have anything to do with the unnecessary index rebuilds. CouchDB has all of the information it needs to avoid this unnecessary computation and I/O.

> So have more shards

More shards spending time serializing and deserializing JSON instead of doing useful work. Throwing shards at inefficient code might help, but it doesn't address the underlying problem.

> Shared memory IPC doesn't magically solve problems but it is a minefield of bugs.

Lots of database systems manage to use it just fine. You probably use one of them. And it does solve a problem: it avoids serializing and deserializing all of your data down a pipe.

> Large blocks of allocated memory use malloc instead of brk so memory allocation uses mmap.

Yes, with MAP_ANONYMOUS. I'm not talking about anonymous mappings.

> Hmm, seeing kswapd being active is not something I look forward on a production server.

For swap? Sure. For file-backed mmap pageout guided by madvise? I actually do. It means the VMM is being used for its intended purpose.

> bulk docks is not a transactional feature

It was an example of the one way to achieve an atomic write of multiple documents, which comes in very handy for any nontrivial application.

I'd honestly be fine with them just deprecating the entire external view server protocol – but as it stands now, it's a supported feature, the performance documentation in 5.2.5 of the manual is nonsensical, and it performs very very poorly due to excessive serialization/deserialization and inefficient IPC.


Huh? I have never heard of anyone saying erlang is bad because of couchdb. I've heard criticisms of couchdb itself, sure. But they've been more along the lines of "MVCC multi-master document stores are not a good solution for this problem" more than "CouchDB is a bad MVCC multi-master document store".


It doesn't use real node-local/shard-local MVCC AFAICT. It's O_APPEND on flat files.


It _is_ append only. But doesn’t use flat files. The main storage files have 2 different immutable btrees to find documents (by id and by sequence num). And it does have mvcc for both storage and secondary indexes. Internally it has transactions but they aren’t exposed to the user, as multi document transactions don’t make sense for the replicated document model.


Thanks for the clarification. Can I ask how the MVCC is implemented (e.g. WAL, MVTO, MVRC, etc.), or if there's documentation around that might give some additional insight?


Here’s a link that describes the Couchstore file format. It’s the storage engine for Couchbase and is essentially the same design as CouchDB. https://github.com/couchbaselabs/couchstore/wiki/Format


Thanks a lot; this is super-helpful.


Sorry, wasn't clear if you were talking about MVCC in a replication context or in a node-local context. It does the former, it definitely does not do the latter.


I don't know that much about databases, could you go into more detail?


From the point of view of a single cluster or node (ignoring replication for a moment), it just doesn't have any strong notion of transactions. There's no write-ahead log, no rollback, and no situation where you'd be able to operate in a mode equivalent to something like `SERIALIZABLE` on a relational database.


oh right, I understand what you mean now.

I guess most people should know that going in. Are their good master-master systems out there with local transactions?


The claim from daimenkatz was that transactions and MVCC are supported internally, but not externally. It's unclear to me if any of this is accurate. Here's the information that was offered: https://github.com/couchbaselabs/couchstore/wiki/Format. Let me know if you see MVCC or transactional behavior in there.


I've tried to use it. I hadn't realized it was erlang based, but now I respect erlang less


I haven’t used it personally, but I looked at it enough to know that its goals are different from most DBs.

Isn’t it supposed to be mainly REST based and have a goal of being able to sync multiple nodes with expected connection loss in between?

I’ve never needed that on a project but it seems like it would work for some use cases. I hear good things about PouchDB.


I don't quite get pouchdb. Do you need to store multiple revisions of the same document in a browser database? Locks/transactions seem like a better approach here for writing to data client side.


The main point is to sync server side data to a client side database, smoothly, so that the application can continue to function offline and then resync once the connection is re-established.

Couch has always been good at this use case where systems on both ends may have changed in the disconnect time.


Realm looks like a much more modern solution to that problem.


Not familiar with Realm


but you could store Ids and revisions on any key/value store on the client. Why does the client need pouchdbs multiple revisions?


Not entirely sure what you misunderstand, PouchDB stores multiple revisions because thats how CouchDB's sync protocol works, the point of PouchDB was to match CouchDB semantics. PouchDB (as CouchDB) provides options to control how much you track (revs_limit, auto_compaction) and there are improvements we could do to handle tracking less information better

We use transactions under the hood actually writing data to indexeddb


I mean I both get it, and don't get it. CouchDB is all about master-master, and pouchdb just brings that to the browser. But at the same time I don't understand why you'd want a 'master' at the edge of the network, or the overhead of multiple revisions when a users browser isn't going to have tones of concurrent connections.

I fully admit I'm not very well-versed on databases or distributed computing, happy to have things clarified.


I had to make that distinction fairly early on wether PouchDB would be an edge client or a full node and I decided full node, tradeoffs either way but pros of being a full node:

1. Additional (p2p) use cases, honestly I dont use CouchDB much these days, I use express-pouchdb-server so I can embed pouchdb into my server easier than any other database, there is also pouchdb-server and p2p projects like Thali (http://thaliproject.org/)

2. CouchDB existed, sync is super hard, writing an edge client would have meant designing it myself, writing a couchdb clone meant I needed to make a lot less decisions about how it worked while being very confident it would work, The test suite runs the same tests against pouchdb/couchdb to ensure compatibility (and replication via each configuration)


I don't follow your reasoning here: why would the badness of an application propagate up to the technology it's based on? Even the best systems in the world can be abused.

I can understand it working the other way around, e.g. an application initially seems good, but opinion of it drops when finding out it's written in COBOL.

I can understand if the CouchDB authors agreed with criticism of their application, and explained them as being inherent to the language. AFAIK they haven't. EDIT: Ah, looks like the author wrote CouchDB!

I can understand if Erlang and its proponents held CouchDB up as a shining example of their philosophy. AFAIK they don't (e.g. it doesn't appear on https://www.erlang.org/community ).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: