42

I'm currently developing an ASP.NET SessionState custom provider that is backed by Redis using Booksleeve. Redis seemed like a perfect fit for SessionState (if you must use it) because:

  • Redis can store durably like an RDBMS, however it is much faster.
  • A Key/Value datastore better fits the interface of SessionState.
  • Since data is not stored in-process (like the default Session provider), SessionState can live out web server restarts, crashes, etc.
  • Redis is easy to shard horizontally if that becomes a need.

So, I'm wondering if this will be useful to anyone since we (my company) are considering open sourcing it on GitHub. Thoughts?

UPDATE:


I did release a first version of this yesterday: https://github.com/angieslist/AL-Redis/blob/master/AngiesList.Redis/RedisSessionStateStore.cs

NathanD
  • 8,061
  • 7
  • 30
  • 26
  • 1
    Would be very useful - in fact, I began investigating this myself not too long ago, so I'd definitely contribute to the project quite a bit. I'd highly recommend that if you dive into this, you build on top of the ServiceStack ICacheClient interface. Redis is one of a few included cache clients, including an in-process in-memory cache which would be great for debugging. – bsiegel Nov 09 '11 at 17:51
  • 2
    If it's useful to you, it will be useful to others. Do it. – John Sheehan Nov 09 '11 at 17:52
  • So far I have stuck with Booksleeve as the Redis client lib. I initially looked at using SS's ICacheClient, but I realized quickly that Redis's hash data type was the perfect fit for SessionData. So I needed a lower level, Redis-specific client. Also, since I will need to do per-HttpRequest locking in order to 'properly' implement the same functionality as the built-in ASP.NET Session providers, I figured I should stay closer to the metal. Eventually, however, I'd like to make locking optional/configurable. – NathanD Nov 09 '11 at 18:22
  • Surprised this question wasn't immediately closed as not constructive by SO mods...(great project idea btw) – B Z Nov 09 '11 at 18:27
  • I do plan on using ServiceStack.Text to provide a range of choices for serialization. I get a native serialization already using SessionStateItemCollection.Deserialize/Serialize. Then I can add JSON and JSV using SS.Text, as well as an interface to implement so anyone can create their own custom serializer. – NathanD Nov 09 '11 at 18:29
  • Funnily enough I intend talking about this topic tomorrow at Øredev 2011. We (SE) did not add a session state provider, simply because we do not use the inbuilt session-state model, but it would be a handy thing to add. Of course, I also have some ideas on candidate serializers ;p – Marc Gravell Nov 09 '11 at 18:59
  • Marc, on my TODO is pluggable support for different serializers. I'm currently thinking that built-ins would include the JSON from @demisbellot and your Protobuf – NathanD Nov 17 '11 at 16:57
  • Hi, when you gonna add a download for this project? – Daniel Casserly Apr 01 '12 at 11:40
  • @MarcGravell "we do not use the inbuilt session-state model". Kevin writes in http://meta.stackexchange.com/a/69172/51 that "local cache contains things like user sessions. So you used to use sessions and now you don't? – Yaakov Ellis Jun 06 '12 at 06:56
  • @NathanD - have you tested this with sharing the session across multiple servers (and if so, did you have to do anything special in order to allow it to associate the user session stored on redis with the same user on multiple servers?) – Yaakov Ellis Jun 06 '12 at 07:04
  • @YaakovEllis you misunderstand; we make limited (small) use of the concept of session-state, but we don't use the ASP.NET session-state model to do this. – Marc Gravell Jun 06 '12 at 07:19
  • @MarcGravell Do you store your conceptual session state (per user) in Redis? Or on the ASP.net Application cache (on the server itself)? – Yaakov Ellis Jun 06 '12 at 12:23
  • @YaakovEllis as it happens *no*, but that is simply because our session state usage pre-dates our redis usage, and we haven't had need to revisit it. Redis would make a perfectly sensible and reasonable session-state store - much better than a RDMBS, for example. – Marc Gravell Jun 06 '12 at 12:37
  • Is this in nuget? I see there is one using ss as well, but I like using booksleve because of it being asyn – Justin Homes Jan 03 '14 at 00:49
  • I think this project needs an update because some of the methods of `Booksleeve` is obsolete, and suggestions are using `Stings API`. – Zafar Mar 06 '14 at 19:00
  • For anyone reading this, it looks like Microsoft is releasing their own Redis Session State provider. See the prelease [here](http://blogs.msdn.com/b/webdev/archive/2014/05/12/announcing-asp-net-session-state-provider-for-redis-preview-release.aspx) – chue x Jun 17 '14 at 18:32

2 Answers2

16

I've created a Redis-based SessionStateStoreProvider that can be found on GitHub using ServiceStatck.Redis as the client (rather than Booksleeve).

It can be installed via NuGet with Install-Package Harbour.RedisSessionStateStore.

I found a few quirks with @NathanD's approach. In my implementation, locks are stored with the session value rather than in a separate key (less round trips to Redis). Additionally, because it uses ServiceStack.Redis, it can used pooled connections.

Finally, it's tested. This was my biggest turn off from @NathanD's approach. There was no way of actually knowing if it worked without running through every use case manually.

TheCloudlessSky
  • 18,608
  • 15
  • 75
  • 116
  • Did you test the session store in an environment with significat concurrency for the same session id? I'd be interested to find out how you handle locking and if is safe to use the Redis session store in apps with significant load. – Robert Mircea Jul 14 '12 at 11:09
  • @RobertMircea - I followed the examples and best practices on MSDN for implementing SessionStateStoreProviders. The locking is done roughly the same as the SQL and Azure session state providers as well (since they all roughly implement the same example from MSDN). To your question - yes I have tested with a couple of apps with significant load (even for the same session ID). I've had zero issues with the provider. However, if you do find a problem, please let me know and open an issue on Github. – TheCloudlessSky Jul 14 '12 at 13:37
  • My single worry is that Redis does not support transactions as databases do and, in this case, state can change between two Redis operations. I took a look in the code and you seem to have code like this in GetItem: var stateRaw = client.GetAllEntriesFromHashRaw(key); [do something with data] ...save changes in Redis... Between read operation from Redis and save, a lot can happen and, I believe, that you are not guaranteed to find the same session state data in Redis as at the moment of the initial read... Is Redis the proper store for session state? At least without using Lua atomic scripts? – Robert Mircea Jul 14 '12 at 21:40
  • @RobertMircea - I understand you now. Good catch for this. I wrote this before I fully understood `WATCH`. I've made some changes. Would you mind take a look at [issue #1](https://github.com/TheCloudlessSky/Harbour.RedisSessionStateStore/issues/1) and the [associated code](https://github.com/TheCloudlessSky/Harbour.RedisSessionStateStore/commit/054984e148783c34505bcec321e20fec561ab199)? I'll push to NuGet once you've taken a look at it. Thanks! – TheCloudlessSky Jul 15 '12 at 23:55
  • Is there some performance tests VS StateServer mode? – Guillaume86 Oct 18 '12 at 14:06
  • @Guillaume86 - Nope, but I'm sure it's faster since it's Redis (I've never used StateServer). – TheCloudlessSky Oct 18 '12 at 14:17
  • Well StateServer Mode is in memory (if I understood correctly) so I guess if there is a gain it's just thanks to the serializers. Compared to the SQL mode of course it would win hands down :) – Guillaume86 Oct 18 '12 at 14:47
  • Redis is atomic which mean Only one key can be accessed at the time. – dmportella Oct 25 '12 at 09:56
  • Redis also supports transactions http://www.redis.io/topics/transactions – dmportella Oct 25 '12 at 09:57
  • have you used free version of ServiceStatck.Redis? as far as i know it has 6k limit for calls. or commercial? how have you handled this? – Zafar Mar 06 '14 at 16:56
  • and also, i got a error `Already referencing a newer version of 'ServiceStack.Text'` when installing with nuget. – Zafar Mar 06 '14 at 17:04
  • @Zafar Can you please list your details on the [existing issue](https://github.com/TheCloudlessSky/Harbour.RedisSessionStateStore/issues/15)? – TheCloudlessSky Mar 06 '14 at 18:00
  • I've exactly the same issue with @aappell. I've tried to install the package for an brand new ASP.NET WebForms Application, and got that error. Actually, 'zibrohimov' on Git is me. I've reported this issue while ago. – Zafar Mar 06 '14 at 18:45
3

Not only would it be useful, but I strongly consider you look closely at the Redis' Hash datatype if you plan to go down this road. In our application the session is basically a small collection of keys and values (i.e.: {user_id: 7, default_timezone: 'America/Chicago', ...}) with the entire user session stored under in a single Redis hash.

Not only does using Hash simplify mapping the data if your session data is similar, but Redis uses space much more efficiently with this approach.

Our app is in ruby, but you might still find some use from what we wrote.

Carl Zulauf
  • 39,378
  • 2
  • 34
  • 47
  • 1
    Thanks Carl, yep I'm using the hash type - a perfect fit. Another advantage to using Hash is that if I later want to support the ability to explicitly lazy or eager load specific session items, it is just an add-on rather than a complete rewrite. – NathanD Nov 15 '11 at 14:42
  • if the user has a list of comments as well, do i still need to save it as hash as {comment_id:1,Content:text1,comment_id:2,Content:text2..} or is it okay to save those as List ? Thanks ! – user636525 Jan 03 '13 at 02:36
  • @user636525 it would be better to store an independent collection of data in an independent collection. A List should work well for that. – Carl Zulauf Jan 03 '13 at 05:24