天天看點

carmine Carmine

CHANGELOG | API | current Break Version:

Please consider helping to support my continued open-source Clojure/Script work? Even small contributions can add up + make a big difference to help sustain my time writing, maintaining, and supporting Carmine and other Clojure/Script libraries. Thank you! - Peter Taoussanis

Redis is awesome and it's getting more awesome every day. It deserves a great Clojure client.

Small, simple all-Clojure library

Fully documented, API with full support for the latest Redis versions

Great performance

Industrial strength connection pooling

Composable, first-class command functions

Flexible, high-performance binary-safe serialization using Nippy

Full support for Lua scripting, Pub/Sub, etc.

Full support for custom reply parsing

Command helpers (<code>atomic</code>, <code>lua</code>, <code>sort*</code>, etc.)

Ring session-store

Simple, high-performance message queue (v2+, Redis 2.6+)

Simple, high-performance distributed lock (v2+, Redis 2.6+)

Pluggable compression and encryption support (v2+)

Includes Tundra, an API for replicating data to an additional datastore (v2+, Redis 2.6+)

Link

Description

@lantiga/redlock-clj

Distributed locks for uncoordinated Redis clusters

@danielsz/system

PubSub component for system

Your link here?

PR's welcome!

Add the necessary dependency to your project:

And setup your namespace imports:

You'll usually want to define a single connection pool, and one connection spec for each of your Redis servers.

A simple example spec with no pool and one server using redistogo.com would be:

Executing commands is easy:

Note that executing multiple Redis commands in a single <code>wcar</code> request uses efficient Redis pipelining under the hood, and returns a pipeline reply (vector) for easy destructuring, etc.

If the number of commands you'll be calling might vary, it's possible to request that Carmine always return a destructurable pipeline-style reply:

If the server responds with an error, an exception is thrown:

But what if we're pipelining?

The only value type known to Redis internally is the byte string. But Carmine uses Nippy under the hood and understands all of Clojure's rich datatypes, letting you use them with Redis painlessly:

Types are handled as follows:

Clojure type

Redis type

Strings

Redis strings

Keywords

Redis strings (v2+)

Simple numbers

Everything else

Auto de/serialized with Nippy

You can force automatic de/serialization for an argument of any type by wrapping it with <code>car/serialize</code>.

Like labs-redis-clojure, Carmine uses the official Redis command reference to generate its own command API. Which means that not only is Carmine's command coverage always complete, but it's also fully documented:

Redis 2.6 introduced a remarkably powerful feature: server-side Lua scripting! As an example, let's write our own version of the <code>set</code> command:

Script primitives are also provided: <code>eval</code>, <code>eval-sha</code>, <code>eval*</code>, <code>eval-sha*</code>. See the Lua scripting docs for more info.

The <code>lua</code> command above is a good example of a Carmine helper.

Carmine will never surprise you by interfering with the standard Redis command API. But there are times when it might want to offer you a helping hand (if you want it). Compare:

Both of these calls are equivalent but the latter counted the keys for us. <code>zunionstore*</code> is another helper: a slightly more convenient version of a standard command, suffixed with a <code>*</code> to indicate that it's non-standard.

Helpers currently include: <code>atomic</code>, <code>eval*</code>, <code>evalsha*</code>, <code>info*</code>, <code>lua</code>, <code>sort*</code>, <code>zinterstore*</code>, and <code>zunionstore*</code>. See their docstrings for more info.

In Carmine, Redis commands are real functions. Which means you can use them like real functions:

And since real functions can compose, so can Carmine's. By nesting <code>wcar</code> calls, you can fully control how composition and pipelining interact:

Carmine has a flexible Listener API to support persistent-connection features like monitoring and Redis's fantastic Publish/Subscribe facility:

Note the map of message handlers. <code>f1</code> will trigger when a message is published to channel <code>foobar</code>. <code>f2</code> will trigger when a message is published to <code>foobar</code>, <code>foobaz</code>, <code>foo Abraham Lincoln</code>, etc.

Publish messages:

Which will trigger:

You can adjust subscriptions and/or handlers:

Remember to close the listener when you're done with it:

Note that subscriptions are connection-local: you can have three different listeners each listening for different messages, using different handlers. This is great stuff.

Want a little more control over how server replies are parsed? You have all the control you need:

Carmine's serializer has no problem handling arbitrary byte[] data. But the serializer involves overhead that may not always be desireable. So for maximum flexibility Carmine gives you automatic, zero-overhead read and write facilities for raw binary data:

Redis makes a great message queue server:

Guarantees:

Messages are persistent (durable) as per Redis config

Each message will be handled once and only once

Handling is fault-tolerant: a message cannot be lost due to handler crash

Message de-duplication can be requested on an ad hoc (per message) basis. In these cases, the same message cannot ever be entered into the queue more than once simultaneously or within a (per message) specifiable post-handling backoff period.

See the relevant API docs for details.

Again: simple, distributed, fault-tolerant, and fast.

Redis is a beautifully designed datastore that makes some explicit engineering tradeoffs. Probably the most important: your data must fit in memory. Tundra helps relax this limitation: only your hot data need fit in memory. How does it work?

Use Tundra's <code>dirty</code> command any time you modify/create evictable keys

Use <code>worker</code> to create a threaded worker that'll automatically replicate dirty keys to your secondary datastore

When a dirty key hasn't been used in a specified TTL, it will be automatically evicted from Redis (eviction is optional if you just want to use Tundra as a backup/just-in-case mechanism)

Use <code>ensure-ks</code> any time you want to use evictable keys - this'll extend their TTL or fetch them from your datastore as necessary

That's it: two Redis commands, and a worker! Tundra uses Redis' own dump/restore mechanism for replication, and Carmine's own message queue to coordinate the replication worker.

Tundra can be very easily extended to any K/V-capable datastore. Implementations are provided out-the-box for: Disk, Amazon S3 and DynamoDB.

Note that this API makes it convenient to use several different datastores simultaneously (perhaps for different purposes with different latency requirements).

Redis is probably most famous for being fast. Carmine hold up its end and usu. performs w/in ~10% of the official C <code>redis-benchmark</code> utility despite offering features like command composition, reply parsing, etc.

Carmine's SQL-interop features (forthcoming) were developed with the help of Navicat, kindly sponsored by PremiumSoft CyberTech Ltd.

Carmine was developed with the help of the YourKit Java Profiler. YourKit, LLC kindly supports open source projects by offering an open source license.

ClojureWerkz is a growing collection of open-source, batteries-included Clojure libraries that emphasise modern targets, great documentation, and thorough testing.

Please use the project's GitHub issues page for all questions, ideas, etc. Pull requests welcome. See the project's GitHub contributors page for a list of contributors.

Otherwise, you can reach me at Taoensso.com. Happy hacking!

- Peter Taoussanis

Distributed under the EPL v1.0 (same as Clojure).

Copyright © 2012-2016 Peter Taoussanis.

本文作者:陳群

本文來自雲栖社群合作夥伴rediscn,了解相關資訊可以關注redis.cn網站。

下一篇: Erldis