Showing posts with label community. Show all posts
Showing posts with label community. Show all posts

Wednesday, 10 October 2012

Multiplexed transactions in BookSleeve

UPDATE

BookSleeve has now been succeeded by StackExchange.Redis, for lots of reasons. The API and intent is similar, but the changes are significant enough that we had to reboot. All further development will be in StackExchange.Redis, not BookSleeve.

ORIGINAL CONTENT

Short version, for the impatient

BookSleeve now has support for transactions using WATCH and pre-conditions. If you don’t know what BookSleeve or redis is, this won’t be of interest to you.

Background

We use redis extensively as part of our caching (and a few other things) technologies at Stack Exchange, and as part of doing that efficiently, we put together BookSleeve, which is a high-performance multiplexer over a redis connection. In English, what that means is: you can share a single redis connection from lots of different threads, and it will worry about delivering the commands efficiently and shipping results back to the appropriate callers, without 200 commands having to pay the penalty of 200 latency. Redis even includes transaction support for complex operations, however, previously I’ve always been a bit stumped how to fit this into BookSleeve…

How do transactions work in redis?

You see, redis transactions are not like SQL transactions. A transaction is defined by a MULTI … EXEC block, with everything between the MULTI and the EXEC being processed as a single atomic unit (meaning: redis doesn’t process any requests from other connections during that time - don’t worry if that sounds draconian, redis manages extraordinarily well on a single thread anyway). That’s pretty easy to fit into a multiplexer, as we can just have a structure to buffer up commands, and send them when complete – so that already exists in BookSleeve:

using (var tran = conn.CreateTransaction()) 
{
tran.Strings.Set(0, "foo", "abc");
tran.Strings.Set(0, "bar", "def");
tran.Execute();
}

But here’s the gotcha: between the MULTI and the EXEC, you don’t get results – you only get results when you commit the transaction. This means that you can’t easily request information in the middle of a transaction and then make a decision on that for what you do next – which makes a lot of sense really, since while you’re doing that thinking and network-IO, every other connection would be stalled. A sane decision really.

To get around this limitation, redis transactions actually allow a bit more cleverness… you can issue a WATCH command against keys of your choice, and then if somebody changes that key, your transaction automatically gets killed. So, a typical cycle might be:

WATCH SomeKeyName
GET SomeKeyName
{some test on the value back in your client code, then}
MULTI
SET SomeKeyName SomeNewValue
EXEC
{or if you decided you didn't like it after all}
UNWATCH

And importantly, because of the WATCH, if another connection comes along and changes SomeKeyName, then the EXEC does nothing, and returns a reply that robustly indicates the cancellation. This actually allows a lot of very subtle usage, while allowing everything to happen at the server as a single unit of work.

So what is the problem? And what did you do?

The painful bit here is simply: WATCH doesn’t work in a multiplexer. As soon as one caller issues a WATCH, either you need to stop accepting work from other callers, or you now have no idea what each caller thinks it is watching (which is very important). Another approach would be to somehow have the user write callbacks that happen as part of a transaction, but what I absolutely don’t want to do is expose anything in BookSleeve that inadvertently allow one caller to break everybody, by being too slow – so callbacks: not really an option. So for a long time, BookSleeve only made use of WATCH etc internally, and didn’t expose it to the caller. But that has finally changed!

I’ve just committed my first stab at improving this, basically by implementing a number of pre-canned pre-conditions that can be enforced on a transaction. The “pre-canned” is there to avoid the issue of opening up massive performance issues, but in reality they are very simple. For example, a previous internal usage of WATCH was to take an exclusive lock (by marking a key as in-use). Until today, that was about 100 lines of complex code that needed to know about the full gory details of the redis protocol – where-as now it is just:

TaskCompletionSource<bool> result = new TaskCompletionSource<bool>();

using (var tran = CreateTransaction())
{
tran.AddCondition(Condition.KeyNotExists(db, key));
tran.Strings.Set(db, key, value, expirySeconds);
tran.Execute().ContinueWith(takeLockContinuation);
}
return result.Task;

where takeLockContinuation is just a static delegate instance that take the Task<bool> result from the Execute call, and sets that into result (plus handling task faults, cancellation, etc). Crucially, the condition (Condition.KeyNotExists in this case) takes care of both the WATCH steps, and the actual validation / enforcement. Basically, if there are pre-conditions (there can be multiple), then they are all sent to the server, and only if they all return the expected results is the MULTI / EXEC block sent – otherwise an UNWATCH is sent instead. Simple, elegant (IMO), and efficient.

The available pre-conditions are pretty limited at the moment, but I’ll try to add all the obvious ones I can think of (exists/not-exists for keys/hashes, equals/not-equals for keys/hashes, maybe a few inequalities, maybe something involving ttl). But finally I have a WATCH implementation that isn’t entirely sucky for a multiplexer. At the moment this is in the code repository only; I'll push to NuGet when I have a few more pre-conditions implemented.

Wednesday, 8 June 2011

Profiling with knobs on

A little while ago, I mentioned the core part of the profiling tool we use at stackexchange – our mini-profiler. Well, I’m delighted to say that with the input from Jarrod and Sam this tool has been evolving at an alarming rate, and has now gained:

  • full integration with our bespoke SQL profiler, which is now also included
    • basically, this is a custom ADO.NET DbConnection that you wrap around your existing connection, and it adds logging
  • an awesome UI (rather than html comments), including a much clearer timeline
  • full support for AJAX activity
  • some very basic highlighting of duplicated queries, etc
  • webform support
  • and a ton of other features and enhancements

To illustrate with Jarrod’s image from the project page:

miniprofiler

The custom connection has been exercised extensively with dapper-dot-net, LINQ-to-SQL and direct ADO.NET, but should also work with Entity Framework (via ObjectContextUtils, provided) and hopefully any other DB frameworks built on top of ADO.NET.

We use it constantly. It is perhaps our primary tool in both understanding problems and just keeping a constant eye on the system while we use it – since this is running (for our developers) constantly, 24×7.

All too often such fine-grain profiling is just “there’s a problem, ask a DBA to attach a profiler to the production server for 2 minutes while I validate something”.

Enjoy.

http://code.google.com/p/mvc-mini-profiler/

Thursday, 24 September 2009

Numeric keypads; what is the point?

As I hinted the other day, I've recently had some stress/RSI symptoms in my arm. Nothing too serious, just definitely worth fixing ASAP. I'm by no means crippled with RSI or anything, but I am on a mini-crusade for programmer-health, and want to help others avoid unnecessary stress / irritation.

I had a very productive session with a physiotherapist today, who made some really constructive and pragmatic points (for example, demonstrating quite simply and clearly that the curve on my corner-desk points the wrong way, and simply swapping to a mirrored desk could help hugely).

But one startling point she made while observing me; as a programmer, I move frequently between the keyboard (in my case a decent ergonomic split jobbie) and the mouse (now a shiny new "vertical" model) - code a few lines, use the mouse to click a few buttons, test a few things via the UI - rinse, repeat.

Sure, I use the keyboard shortcuts, but I would struggle to remember the hundreds of magic key-presses and "chords" that drive Visual Studio.

Very rarely do I use the numeric keypad. Heck, I also use a laptop, and the only time I find myself looking for Num Lock is when my password inexplicably doesn't work. Yet every time I move between keys and mouse I have to travel this pointless distance.

Lets not do that

Numeric keypads; absolutely useless. Underused, oversized, badly placed, and they don't agree with 'phones on which way the numbers should go.


Goldtouch Keyboard

She gave me a tip to simply try a keyboard without one, letting me have the mouse much closer. You can pick up a "Goldtouch" ergonomic keyboard (sans keypad) for about GBP25 at Amazon. This is so simple and so obvious that I'm just stunned that people insist on still including it, even on "ergonomic" keyboards. If it is so ergonomic, why is it causing unnecessary travel?!?!


USB Numeric Keypad
If you want a keypad (and I do find them handy occasionally), then buy a USB keypad (like they sell for laptops) - roughly GBP10, and that is for the models that double as a handy USB hub. If you're right-handed, stick it on the left, or on the far side of the mouse - whichever you prefer and find most comfortable. Plus you can move it to either side if a "sinister" shows up at your desk.

Join the revolt! I invite you to ditch (or move) your keypad today!

Wednesday, 16 September 2009

protobuf-net vs NetDataContractSerializer

In a user-group meeting yesterday, I was talking briefly (in a “grok” session) about “protocol buffers” (protobuf-net in particular), and I was asked a question about the comparison to NetDataContractSerializer. I didn’t have the answer to hand (I only had numbers vs DataContractSerializer), so promised to find out…

First; note that the key difference between DataContractSerializer and NetDataContractSerializer is (as I understand it) that NetDataContractSerializer includes more type metadata. This makes it possible to do a few things involving “object” and unanticipated subclasses (which can be useful), but renders it .NET-specific (and less version-tolerant).

The test

As per my existing test rig, I test 1000 iterations of a moderately large extract from the Northwind sample database (into some pretty-standard POCO types); I simply extended this rig to incude NetDataContractSerializer. For completeness, I have 3 variants of the tests, tested separately each against a different set of serializers:

  1. LINQ-to-SQL generated classes with serialization enabled at the data-context; suitable for protobuf-net, DataContractSerializer and DataContractJsonSerializer
  2. as the first test, but with the LINQ-to-SQL bits hacked out and [Serializable] added (to make it suitable for the core binary .NET serializers); suitable for protobuf-net, NetDataContractSerializer, DataContractSerializer, DataContractJsonSerializer, BinaryFormatter and XmlSerializer
  3. as second test, but with ISerializable and IXmlSerializable implemented to support BinaryFormatter and XmlSerializer via protobuf-net

The numbers and analysis

Since only the second test supports NetDataContractSerializer, that is the one I’ll focus on (with results from the 3rd test included for interest only, marked *); here’s the numbers:

Serializer Size (bytes) Serialize (ms) Deserialize (ms)
protobuf-net 133,010 10,769 23,511
NetDataContract
Serializer
992,203 29,343 91,453
DataContract
Serializer
772,406 16,272 66,755
DataContractJson
Serializer
490,425 29,604 135,125
BinaryFormatter 276,366 67,151 56,253
XmlSerializer 1,043,137 29,257 38,528
BinaryFormatter* 133,167 12,095 24,653
XmlSerializer* 177,41012,189 31,827

Some interesting points; firstly, for my sample data it is a myth that WCF’s binary type-centric serializer (NetDataContractSerializer) is going to improve things over xml (DataContractSerializer). Both in terms of bandwidth and processing time it is worse on every front. The biggest advantage of NetDataContractSerializer (in this case) is that the type model is more flexible in terms of interfaces, “object” and unknown subclasses; but this also makes it entirely non-interoperable. Of course, some details of the SOAP envelope used by the binary type-centric WCF transport may be more efficient – but I’m looking at payload for these tests.

Secondly (and fortunately for me) it yet again proves that google know how to do data transport; with protobuf-net being the clear winner for both bandwidth and processing time.

But for me, another point that I’d like to highlight is versatility and compatibility; the same classes can be used happily by a wide range of serializers (above), and presumably a few others too. For the record, the entities in the above test don’t even have any protobuf-net-specific attributes (the outer-most wrapper does have them, but only because at some point in the distant past I wanted a way to compare/contrast some protocol-buffers-specific details, which can only be controlled via the custom attributes).

Other thoughts

As with all performance tests, your specific environment and data may be an important factor. But based on the above numbers it may be reasonable to assume that protobuf-net stands a good chance of holding its corner.

Finally; following some unrelated conversations at the same user-group (they kept me pretty busy), I stress that tight serialization is only part of the story:

  • It can help reduce bandwidth costs and CPU costs associated with (de)serialization, but it won’t help if latency is your issue; protobuf-net makes no claim to change the speed of light.
  • While protocol buffers may be supported on a range of platforms, it is by no means ubiquitous; if your biggest demand is portability, perhaps use SOAP/WSDL (or offer both SOAP and protobuf-net on separate endpoints).
  • By itself it won’t solve all your disconnected woes; although it can presumably be used in tandem with any message-queue based solution you might dream of.

Wednesday, 9 September 2009

Stickers – now what to do with them?

For any stackoverflow users, the stickers are real – Jeff was kind enough to send mine directly, rather than wait for DevDays. I knew that ♦ would be useful!

Compulsory wooden-table shot:

SDC10088

They’re a little smaller than I expected, being only slightly longer than my mobile ‘phone. Now… if only I can think of what to do with them… so far, I’m wondering if they might make serviceable plasters (band-aid if that doesn’t translate). Or (edit) maybe a laptop-chassis emergency repair kit? (my last laptop survived 2 large cracks for a considerable time). Or I might drag them along to a user-group and see if there are any takers.

All other suggestions welcome…

Wednesday, 27 May 2009

Hectic Weeks, Charisma; and Trolling

(not much code here - if you're after a "fix", come back soon ;-p)

A busy week...

First, I somehow got elected as a community moderator on stackoverflow. In reality, this mainly means that I get more visibility of where people flag spam / etc. You can probably guess at some of the obvious trolls and other personalities that appear (hopefully briefly before being deleted). Fortunately, it isn't keeping me too busy! The main down-side is that I can no longer cast a regular "close this" vote; but that's OK.

I'm not sure whether I should feel guilty when I click the button to delete/destroy an account... even if there is clearly no doubt to "give the benefit of"; hmm - I must get over that ;-p
(this only applies to clear and indisputable spam/troll/puppet accounts, usually with no e-mail, etc)


Then on the weekend, I was at DDD South West; I'm afraid I bombed out of the balloon debate; I must concentrate less on specific details, and more on delivery/charisma (persuasion trumping fact in a debate). It was won for VB by Microsoft's Eric Nelson, who stepped in after the scheduled VB warrior had to drop out. I'll blame my defeat on his charms ;-p A fun diversion in a busy day.

I also presented a session on the Expression API in .NET 3.5 (and 4.0) - which was daunting (not least because my laptop was throwing a BSOD hourly until Friday). I don't think I did as good a job on this presentation as I have in the past, but it seemed to be received OK. The eval forms show that it is a bit of a divisive one, though - presumably because it is quite complex; either you "grok" it or you don't. But from some after-presentation conversations I know that it clicked with the people who come to talk to me , which is cool. I must make sure I describe it as a "deep dive" (or similar) if I do this one again...

Now I just need a few weeks quiet to catch up ;-p



Wednesday, 11 March 2009

Back to the coal face

With the summit now over, back to the day job - but first some thoughts (taking NDA etc into consideration):
  • It is no secret that the big theme in .NET 4.0 is the DLR; despite some C# dabbling (here, here), I need to get my head around this "proper"... to that end, I've secured a copy of IronPython in Action, which I hope will set me on the one true path. Besides which - it is good to look at other languages occasionally (and I never really got far with F#).
  • It is no secret that there are lots of changes afoot with Entity Framework and ADO.NET Data Services; now that I've had chance to see them, I'm encouraged that they might be a lot more usable in 4.0 - still waiting on the "bits" though ;-p
  • Windows 7 continues to look very good; I've got the beta at home, and it runs very well on my ancient machine - and the newer builds look even better. Microsoft stand a good chance of actually getting some forgiveness for Vista.
  • The EMP is very, very... odd. Beer, a live-rock/karaoke, an Xbox Rock Band arena and a robot museum all in one.
Other than that - back to the day job. Oh; and planning for a few user group sessions - so if you're in the UK and near Gloucester or Taunton, then I'll be talking about Expression. Feel free to say hi ;-p I also seem to have become involved in the "Balloon Debate" at the latter, so you can watch me try to defend the very existence of C#.

Monday, 23 February 2009

Get busy in the community

Do you make use of the user-groups near you? No, not web-sites, but the real world? If not, perhaps you should? They are a fantastic opportunity both to get up to speed on technology with the help of experts, and for networking. And maybe think about speaking about your own areas of interest/expertise.

I normally pop along to NxtGenUG (Oxford), but with a new baby that has been a bit tricky lately, so I was surprised to see a new user group more local to me - GL.net. So in the unlikely event that you live local to Gloucester, UK - why not pop along? I've also signed up to jump on the soap box in March, talking about the Expression API, which I plan to repeat at DDD South West.

Now; geography probably dictates that you can ignore all those links... but why not take the opportunity to double-check what groups might be near you? Go on... step outside into the daylight; it might not hurt ;-p