4

I'm have used WCF services before, and now I have a new project coming up. I am still in the design phase, and I wondered what the best way to handle the following scenario.

I will be having multiple clients connecting at the same time to my WCF service, firing different methods (Operation Contracts) on the service :

A. Some of the methods fired are just pure 'Read' methods (e.g. GetListOfCustomers).

B. Some are the methods fired are complex 'Read' methods (e.g. GetAllProductsByCustomerId). These kind of methods require getting the customer from the DB, checking something on him, and then getting all the products bought by him. (meaning, there are 2 calls to the database in this method).

C. Some are 'Write' methods (e.g. 'RemoveCustomer' or 'SetProductOutOfStock').

My question is - how do I synchronize all these calls so that I don't get concurrency problems?

I don't want the entire service to process calls serially, because it will damage performance on the client side (some calls may require 3-4 seconds to process). So what is my solution ?

Use a 'Single' instance for all clients with 'Multiple' threads and then use a lock object ? Won't this just result to being serial ?

Or do I need a different lock object for the 'read' and a different lock object for the 'write' ?

Or do I need a lock for the 'write' functions and some other thing for the 'read' functions ?

This is my first question ever on StackOverflow. Thanks for anyone who can help !

Update : I am going to use 'Linq-To-SQL' as my ORM.

John Miner
  • 893
  • 1
  • 15
  • 32

4 Answers4

2

You should not be worried neither about data consistency problems, nor about concurrency while performing database queries. If I understood your situation correctly, all you need to make sure of is that you use transactions consistently while performing a series of database queries which you want to be "atomic". I'll try to explain it on an example:

  1. Get all customers from the database.
  2. For each customer, perform a query updating some related data.

What you don't want to happen in this scenario is to get into a situation when data is changed by another query after the query from 1 returns and before all queries from 2 are finished. For example, if one of the customers gets deleted in the meanwhile, there's no point in updating the related data - that could even lead to some errors.

So what you need to do is to just put something like BEGIN TRANSACTION before 1 and COMMIT after 2. Look up the exact syntax for the SQL dialect you're using.

This will ensure, basically, that the data you're working with does not change. In fact, it will be locked by your transaction; and all the other queries which may work with the same data are waiting for your transaction to finish. Databases do this kind of locking intelligently, always trying to lock as few data as possible.

Dmytro Shevchenko
  • 33,431
  • 6
  • 51
  • 67
  • Thanks for the very quick reply. 1. I am using Linq-To-SQL. You wrote I should use 'BEGIN TRANSACTION' & 'COMMIT', but that is SQL. Do I need to use instead the 'TransactionScope' object with 'Commit' at the end ? 2. Do I need to use 'Transactions' only in the 'write' functions ? Or do I need it in the 'Read' functions as well ? 3. How do I prevent two different calls trying to update the same data at the same time ? If I have a customer - and only one manager can 'take responsibility' for it. How do I prevent them 'overwriting' each other ? – John Miner Apr 16 '12 at 07:55
  • First of all, Linq-To-Sql converts LINQ queries to real SQL, so if you understand how transactions work under the hood, you will easily map your knowledge on LiNQ concepts. Please start by reading responses to [this question](http://stackoverflow.com/questions/755796/how-to-create-a-linq-to-sql-transaction). If you have any questions left after this kind of reading, I'll be glad to answer them. – Dmytro Shevchenko Apr 16 '12 at 08:24
  • Thanks. I have read the link you have posted, and also the article by Scott Guthrie [here](http://weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx). But they seem to write confusing things : one of comments there wrote 'it seems that LINQ to SQL resolves all of the dependencies for you on commit'. Another one wrote 'All operations between db DataContext initialization and db.SubmitChanges() are wrapped around a Database Transaction by .Net ensuring your database to be in consistent and with propery integrity maintained across tables'. – John Miner Apr 16 '12 at 08:56
  • And on the other hand - in the link I saw mention of 'Handling Simultaneous Changes with Optimistic Concurrency'. So ... what is the real situation ? Do I need to protect against concurrency in my WCF service or not ? – John Miner Apr 16 '12 at 08:59
0

You are designing for the web and hence you need to embrace concurrency, there is no way out. Taking locks and all is not a good way to work on the web in my opinion. Concurrent access is going to happen and you need to think of how to deal with concurrency errors rather than preventing concurrency issues. Any concurrency control mechanism build over web is of limited use and hard to build correctly.

Chandermani
  • 42,589
  • 12
  • 85
  • 88
0

I suggest you read something about CQRS, which is an architectural pattern which goes some way to addressing the challenge you are facing.

As an example solution for your situation, the following diagram is a CQRS architecture which could satisfy your requirement.

enter image description here

If you want further explanation I would be happy to provide.

UPDATE

The main principal is you separate your database reads and writes into different databases.

Then you use replication to ensure your read database is up to date.

You can also achieve the above architecture by combining both databases into one and both services into one. However, your original question was about database contention based on the fact that you have conflicting database usage patterns.

So this is why I was proposing CQRS as a solution - the write side of the database is decoupled from the read side. The read side can be optimised for selects (even can be de-normalised for speed of access).

This means that you will not face the same contention issues as you would if you are doing both read and write operations through the same interface - this is your current approach.

Additionally you don't need to expose your read operations via a service - simple ADO will do fine and a service endpoint will just introduce latency.

You can still use linq2sql when you read from the read model and also when the db write service updates the data model.

tom redfern
  • 30,562
  • 14
  • 91
  • 126
  • hmmm ... not sure I understand this. I am going to use 'Linq-To-SQL' – John Miner Apr 16 '12 at 08:02
  • I see what you did there, but I am having trouble understanding it without a concrete example. Have you got anything to show me ? – John Miner Apr 16 '12 at 09:01
  • 1
    @JohnMiner have a look at [this article](http://www.udidahan.com/2009/12/09/clarified-cqrs/), it explains the basic concepts of CQRS in a straightforward way IMHO. – Filippo Pensalfini Apr 16 '12 at 10:24
  • -1 for CQRS, Try it for youself first on real project, before recomending it. I wouldn't recommend CQRS for projects with less than 1 million read's per hour and 5 years Architect experience. In fact I will not recoment CQRS for any real project. – Alex Burtsev Apr 24 '12 at 18:17
  • @AlexBurtsev, thank you for your honest assessment - I am open minded enough to change the way I think if I am shown to be wrong, but you have not supplied any valid disagreement other than you would not recommend it. Please supply one. I am currently implementing a CQRS-type design similar to that above. Additionally, I don't agree that you need 5 years as an architect to understand it. A – tom redfern Apr 24 '12 at 19:14
  • @hugh, oneway messaging for commands used in CQRS is the dead end. Here is a collection of quotes on this subject. I would like to hear how you deal with it in you project. http://alexburtsev.wordpress.com/2012/04/20/cqrsthe-other-story-appendix-fun-quotes/ – Alex Burtsev Apr 24 '12 at 20:01
  • @AlexBurtsev, thanks for the link - I can kind of see where you're going with that. You are highlighting an absurdity at the heart of CQRS - how to deal with the disconnected nature of command feedback. I must admit that when I started working on this particular design (not designed by me) I had reservations, and a colleague of mine working on the same project still does. However, until we put it into production we won't really know how good the design was. And I will have to reserve my full judgement until then. – tom redfern Apr 25 '12 at 07:34
0

My question is - how do I synchronize all these calls so that I don't get concurrency problems?

Why would you need to synchronize anything? The DBMS can handle synchronization quite well. Of course, if you know that you will have lots of writes that are going to degrade your read performance because of locks then you will have to plan for that on an architectural level, but it has not much to do with WCF. In that case, as hugh wrote, CQRS may be a fitting choice, though it is hard to say without the spec at hand.

I don't want the entire service to process calls serially, because it will damage performance on the client side (some calls may require 3-4 seconds to process). So what is my solution ?

Then use PerCall instancing and either Single or Multiple concurrency if you can. Have a look here for details about instancing/concurrency combinations.

Use a 'Single' instance for all clients with 'Multiple' threads and then use a lock object ? Won't this just result to being serial ?

Single instancing is going to give you issues with concurrency, see the article I linked above. It is mostly useful if you need a Singleton service.


UPDATE

In answer to your comment: I'm afraid I still do not understand where you expect to have concurrency issues. If you are worrying about the WCF service, just avoid using Single instancing: the most scalable option is PerCall/Multiple.

If you are asking yourself if you need to consider CQRS, feel free to read the article by Udi Dahan that I linked in another comment. Keep in mind, though, that CQRS takes some time to grok and adds complexity to your project that you may or may not need.

I would suggest not to uselessly overcomplicate your architecture, to me it sounds like a proper configuration of instancing/concurrency for your services is going to be enough. If you are unsure, write some prototypes faking the expected load for your system. Better safe then sorry, especially if it is going to be a long-lived application.

Filippo Pensalfini
  • 1,714
  • 12
  • 16
  • My scenario is this : most of the calls to the service will be 'read' calls (80%), and the rest (20%) are 'write+read' calls (meaning, update all the customers that came in yesterday). Also - there will be another thread on the WCF service that will initiate sending information to the client (like notifications from the database of new customers that have arrived). So in light of that - what do you recommend ? – John Miner Apr 16 '12 at 09:04