- Home
- LLBLGen Pro
- Architecture
Distributed Applications
Joined: 26-Oct-2003
Hi, all. Aside from specific needs, what are the general criteria and considerations to take into account when deciding whether to place the business logic/service layer on the client or on the server? I understand that development time will increase, debugging will be more difficult, etc. But I'm sure there are reasons to do it...what are they? And what are the reasons not to?
Jeff...
Joined: 17-Aug-2003
jeffreygg wrote:
Hi, all. Aside from specific needs, what are the general criteria and considerations to take into account when deciding whether to place the business logic/service layer on the client or on the server? I understand that development time will increase, debugging will be more difficult, etc. But I'm sure there are reasons to do it...what are they? And what are the reasons not to?
The reasons not to do it are: - performance - security - debugging / development - client/server versioning
Performance, because you need some sort of marshalling of the data between client and server applications. Security, because you're sending data over the wire and exposing a server service on the network, which requires a per-connection/action security plan. Debugging/development, see your own text . Client-server versioning: if the server is updated with a new API, all clients have to understand that new api.
the reasons to do it are: - maintainability - scalability - data / functionality consistency
Maintainability, because you have a single datastore/service, so you can update just one of these, not 500. Scalability, because if the datastore is growing you only have to branch out on the service, which can be transparent to the users. And data/functionality consistence (to me the most important one), because you have a single place on the network where the data is: no more databases per division which are not synchronized, just 1 with all the data related to eachother which also offers ability to datamine on the server.
I perhaps missed a few though
Joined: 26-Oct-2003
OK, so how much more difficult is it? Let's say that implementing the business tier on the client takes 100 days. How much longer (on average, and without specific requirements) would it take to implement it on the server?
Also, it seems to me that certain things lend themselves well to creating your business tier on the server: proactive concurrency schemes (i.e, don't wait until the data is saved to alert the user concurrency might be an issue), notifications, e-mail and faxing, etc.
However, how about threading issues? I've never implemented a commercial application in a distributed format. Is threading only a concern for shared resources, such as static variables, shared methods, files, things like that? Am I asking for trouble thinking I can do this without a lot of experience? If it's doable, what sort of things should I watch out for?
Jeff...
Joined: 17-Aug-2003
jeffreygg wrote:
OK, so how much more difficult is it? Let's say that implementing the business tier on the client takes 100 days. How much longer (on average, and without specific requirements) would it take to implement it on the server?
Using remoting? Not that much more, in theory. The problem is debugging and the security mechanism you are going to implement. This will be a problem perhaps, as you need access security for the service, data encryption perhaps for the packets send over the network...
Also, it seems to me that certain things lend themselves well to creating your business tier on the server: proactive concurrency schemes (i.e, don't wait until the data is saved to alert the user concurrency might be an issue), notifications, e-mail and faxing, etc.
Yes, you can create some sort of threaded system with a connection manager which dispatches connections to a worker thread which handles it further, creating more throughput. (these are always great to write btw, but can get out of hand, when time is short)
However, how about threading issues? I've never implemented a commercial application in a distributed format. Is threading only a concern for shared resources, such as static variables, shared methods, files, things like that? Am I asking for trouble thinking I can do this without a lot of experience? If it's doable, what sort of things should I watch out for? Jeff...
Threading is very simple, you have a single code base and multiple 'current execution position' pointers in that codebase, 1 per thread. What you have to make sure is that you keep 'thread state', that is the state of teh application according to a given thread, separated, i.e.: don't share objects among threads if they can manipulate these, unless you create a 'critical section' around the object access code (i.e. just 1 thread can access the object at any given time). For database access and such, it's no big deal, just don't share an open data-access-adapter among threads.
the biggest mistake in threaded apps is sharing data among threads. So if you have that covert, it's ok. Debugging can get nasty, so be sure you have tracelisteners in place.
If you keep your service as stateless as possible, you should be fine. As soon as you keep state on the server, you'll need extra code to make sure that state is OR common to every thread, OR only known to 1 thread.
Joined: 26-Oct-2003
Otis wrote:
Yes, you can create some sort of threaded system with a connection manager which dispatches connections to a worker thread which handles it further, creating more throughput. (these are always great to write btw, but can get out of hand, when time is short)
Yea, that does sound like fun...
Threading is very simple, you have a single code base and multiple 'current execution position' pointers in that codebase, 1 per thread. What you have to make sure is that you keep 'thread state', that is the state of teh application according to a given thread, separated, i.e.: don't share objects among threads if they can manipulate these, unless you create a 'critical section' around the object access code (i.e. just 1 thread can access the object at any given time). For database access and such, it's no big deal, just don't share an open data-access-adapter among threads.
the biggest mistake in threaded apps is sharing data among threads. So if you have that covert, it's ok. Debugging can get nasty, so be sure you have tracelisteners in place.
If you keep your service as stateless as possible, you should be fine. As soon as you keep state on the server, you'll need extra code to make sure that state is OR common to every thread, OR only known to 1 thread.
OK, so an example of an area of concern would be a server-side cache of objects that can be updated and read from multiple connections...
Jeff...
Joined: 04-Feb-2004
Security is always a big concern. WSE2.0 allows one to use SOAP over TCP/IP. WSE also allows you to encrypt data both ways without writing any code.
That being said, COM+ has built in support for security, administration, and deployment.
Logging and debuging is always an area for concern. Microsoft has create a service called the Enterprise Instrumentation Framework, which traces and logs across threads and application domains, so therefore, you can trace and log events using EIF.
Making your application stateless is the best approach. If you do need to cache things on the server, dont let things write back to the cached objects, and you wont have multi-threading issues.
** Things to watch out for** Always keeping your interface standard, as to not break your code. In .NET there is no "binary compatibility" but there is implied backward compatibility. If you create a services layer with 5 methods, and you change one methods footprint, then you need to redeploy to all of the clients because the interface is broken. But, if you add a 6th method, all previously deployed clients will function normally, but your new clients can work with the old and the new services layer.
Because COM+ uses COM and the registry, you need to be really familiar with interop, native .NET interaces, hiding native interfaces, and publicly exposing your interface
With regards to remoting, leases and lease renewal gets wierd sometimes.
With regards to COM+ know when to use transactions and not to. Know when to use auto commit or when to take control of the transaction and voting, etc.
** My excuses for creating a distributed application** There really isnt a right or wrong answer as to wether or not you should create a distributed application. It really comes down to your needs. \
If your web application is experiencing a high volume and load in memory, CPU, and Disk IO, then you might want to consider moving the DB and services to a different server. In this scenario, distributed applications will help.
If you need to support updating and deleteing records from multiple databases, then you probaly need a distributed application using COM+ and distributed transactions.
If you want to position the application in such a way that when you need to move from 1000 concurrent users to 3000 concurrent users without changing code, you just want to add a new server and run a load balanced application, you should create a distributed application.
If you have 1000s of transactions per minuite and new objects are always being created and destroyed to facilitate these transactions, then you could probably save some work on the server by using object pooling and COM+.
If you need to run an application in multiple departments in an organization that has many domains and distributed networks, you probably need a distributed application OR a .NET Connected application that uses BizTalk, but thats 25k in licensing not including hardware.
** The good news** If you have used the adapter and LLBLGen, you should be able to wrap and distribute your application any way that you desire. You could build a .NET Connected APP using SOAP, WSE, and XML Web Services, or you could create a pure remoting solution, or you could leverage the scalability and power of COM+.
** The bad news** These types of applications arent for the faint of heart and they take a lot of long nights and hair pulling sessions. So you really need to consider wether or not you need all of the scalibility features of a distributed application.
I will tell you though, that most of the distributed applications that I have build and worked on make maintenance and deployment a snap, because everything is black box and module. They take longer to build, sure, but they typically support more users, are more stable, and stand the test of time a bit longer, plust they typically have the power to grow with your business.
Joined: 26-Oct-2003
Thanks, DevilDog. I appreciate the info. Have you ever built a distributed app for situations where scalability and size weren't an issue? I'm thinking here primarily about proactive concurrency, and other features that would necessitate a server-based business layer. If you have, was it worth it? In my case, the application I'm confronted with would probably only be used by approximately 10 people at a time. However, if the price isn't too high, I'd like to place the BL on the server in order to make some features work...
Jeff...
Joined: 04-Feb-2004
I havent really build a "meaningful" application where scalability and growth werent an issue, most clients that are going to pay the big bucks are planning for long term investment, and growth in their business.
Given that you only have 10 concurrent users, I would write a pure service based application using remoting for internal clients. You could then run a web app on a DMZ that comminicates with the services layer via remoting. You could also write a watered down SDK version of your app that exposed a set of XML Web Services, and consequently, the XML Web Services could also be based on your services layer.
The services layer shouldnt be that time consuming. Your set of interfaces is already defined by the Adapter LLBLGen DB Generic Code Gen Objects. Now all you need is a few classes that group functionality and all these classes do is expose your CRUD operations externally, and internally they use DataAccessAdapter Objects. Youll probably want to base your service/controller classes in interfaces, so youll only need to push the DB Generic Objects and the service layer interface down to the clients.
Now, when you pass objects from server to client, then modify the object on the client, and pass it back to the service layer, you can write additional code to intercept and validate the objects server side. This will definately centralize your coding efforts and provide you with less moving parts.
Youll need a remote component host to host the services layer, this would normally be a .net service running on the server, which should be all of about 100 lines of code or so. You can also host a few singleton objects server side, to share some data between clients, just be careful with threading.
Youll need a way to log method calls through your business process workflows, i.e. you want to see the state of an object on the client, then in all of the methods it passes through in all layers, thats where the Microsoft EIF comes in.
Youll need to secure the communications, and you can write a simple remoting encryption sink, to encrypt and decrypt the TCPIP packets as they pass back and forth between remote endpoints.
So IMO, depending on the complexity of the application you are probably looking at 2 to ??? months of dev time. Also, would this be worth the time? I think so, because you application is still scalable, and robust. We said at the beginning of this thread that simply by choosing to implement a service based architecture, you have 3 different types of applications that you could create right out of the gate, so I dont think you would be loosing anything.
The only bad thing, IMO about using pure remoting, is the day your client says we want to take these 5 clients and limit them to only the shipping side of the application and business logic, and take the other 5 and grant them permission only to the receiving side of the application, and then take these 2 new guys and give them access to the whole application, and oh yeah, we want you to authenticate them using their NT Domain Accounts and we now have 2 different domains. EEEK. Thats what COM+ does. Another nightmare is when your client says OMG you application has saved us soooo much money and time, that we are so much more productive now, we now have 50 employess and we want to run a load balanced application. EEEK thats what COM+ does, rolling your own load balancing with remoting isnt all that bad though.
So honestly, your worst case scenario, is that youll probably learn a lot and your client will get a proper application that will grow when / if they need it to.
So, Thats my story and Im sticking to it.
Joined: 26-Oct-2003
OK, sounds good. I appreciate the time you took to lay that out. I'm leaning towards using remoting to accomplish this. One more question: I've read (Ingo Rammer, I believe) that it's not a good idea to use events in remoting scenarios. Is that your impression as well? I have a feature that I'd like to develop that would lend itself very well to using events between the "server" and the "client" (or the "client" and the "server", as the case may be). Essentially, it's a UI-level notification/broadcast system that's triggered by new objects that are introduced into the system. An example of this would be a procurement officer being notified of a new requisition that needs to be filled. Thoughts?
Jeff...
Joined: 17-Aug-2003
jeffreygg wrote:
OK, sounds good. I appreciate the time you took to lay that out. I'm leaning towards using remoting to accomplish this. One more question: I've read (Ingo Rammer, I believe) that it's not a good idea to use events in remoting scenarios. Is that your impression as well? I have a feature that I'd like to develop that would lend itself very well to using events between the "server" and the "client" (or the "client" and the "server", as the case may be). Essentially, it's a UI-level notification/broadcast system that's triggered by new objects that are introduced into the system. An example of this would be a procurement officer being notified of a new requisition that needs to be filled. Thoughts? Jeff...
Events make the server call the client, as the eventhandler gets a pointer to the client's event handler routine, which doesn't work if the client isn't a 'remoted server' for the server. (still with me? )
So I think if you want notification from the server to the client, use old-skool notification services: sockets! The client has a listener thread subscribes to the server's notification thread. The network layer is based on simple sockets (easy to do in .NET) So when the server has something to say to the clients, it simply pushes a message to the subscribers, which in fact is nothing more than sending some data over the socket connection to the listeners. The client receives the message and fires locally an event, which triggers the refresh of the data. (It will get a little complicated with a lot of listeners, but that's the idea)
Joined: 18-Aug-2003
Ordinarily I'd agree with Frans, especially if I were just using the native .NET remoting tools, which do not make eventing with remoting easy because ... well for lots of reasons.
However, for events with remoting there's a tool (there's always a tool) called Genuine Channels, http://www.genuinechannels.com.
Description of GC vs .NET native remoting: http://www.genuinechannels.com/Content.aspx?id=17&type=1
Basically, it's a layer on top of .NET remoting. The calls are very similar, but it expands the feature set. The best use is the Broadcast Engine, which allows clients to subscribe to events from a server's dispatch object. You call the dispatch object's method and it's broadcast to all the clients as events. Other features include automatic client reconnection, queueing of events (that are re-fired on the client after re-connection) and some engine-level stuff like sending several messages in one packet via http.
It's a monster cheap $100 USD per developer. Well worth it. I used it recently to move LLBLGen MS Access data and it worked great. It's so cool to see the broadcast kick in and all the clients update at the same time.
Joined: 17-Aug-2003
Thanks Scott, I didn't know that! Great info It's always better to use a ready-to-rock tool than to write this stuff yourself, as it solves you from the problems you have to solve/debug.
Joined: 18-Aug-2003
jeffreygg wrote:
Mr. Wallace, you're worth your weight in gold .
Thanks, that makes my day!
jeffreygg wrote:
Have you used GC in any production applications? How well did it work?
Also, what are some reasons why native remoting doesn't work well for events?
Jeff...
I used GC in a production app used by about a half dozen people within a firewall. It worked well, but I wouldn't say it was a high-stress environment. I had the natural headaches, like remembering that events out of GC were operating within threads not within the main app's thread.
GC comes with a ton of documentation, all of it surprisingly bad. This was my first introduction to remoting, and GC's documentation did nothing to help me. It assumed tons of prior knowledge, none of which I had. Ingo's book is worth it's weight in gold. The more I learned, the more helpful the GC documentation became.
As I understand it (insert standard qualifier here), under .NET data flows in one way, meaning the person who makes the connection can request data and receive a response, but cannot be reached by the server on server initiation. This means that I can invoke a remote object on the server, call it's method and get a return value, but cannot participate in the object's events. There are work-arounds in .NET involving making each client a server then opening two connnections, one in each direction, but it's tricky, especially across firewalls.
The GC stuff allows two-way communications on the client-opened connection. The client has a proxy to a server-created dispatch object, which is a GC object type. The client can handle events from the dispatch object. Decendants of the dispatch object therefore can handle events. Because multiple clients can reach the server's dispatch-decendant object singleton, all or any clients can receive the events, even if they are initiated by a single client. The way I used it was, when a client updates a record call:
client->dispatchobject->updateRecord( myrecordEntity );
which had a line in it to call the event handler ( on the server, which is propagated to all the clients handling that event):
server->dispatchobject->databaseWasUpdated( myrecordEntity );
the clients then received the event that a record was updated (with the updated record). If they were showing the list of records they could update it on their screen. I also, under certain circumstances, would pop something before the user, "Dude, the record was changed!", or words to that effect.
How does it work inside? That's a mystery to me. I'm new here.
Because the two-way communications connection is initiated by the client (the server does not try to connect back to the client), and if you use HTTP as the protocol, you sidestep firewalls. This I have not done, but I guess I could.
Anyway, it's ticking along amongst these half dozen people, and since I worked out the threading of the data it's been working without incident.
It comes with source, but I'm afraid of it. To me, somethings are best left in the black box...
Truly, though, what makes this possible, and as (relatively) easy as it was, is Frans' Adapter model product. WooHoo!
One other thing: I agree with Devildog74: Services, services, services!
(BTW, that's not just 271 posts, that's 271 posts averaging 500 words or more!)
Joined: 26-Oct-2003
Given the small size of the user base, why did you choose a distributed architecture?
BTW, Frans. Ever thought of implementing a chat service for your customers/forum users? I'm sure we could waste much more time if our conversations were in real-time. Especially if the topics stray toward arguing the relative merits of FPS vs. RTS games.
Jeff...
Joined: 18-Aug-2003
Given the small size of the user base, why did you choose a distributed architecture?
Immediate notification. They were going to be speaking to some live server (rather than a database) because of that, and once you have that you can do anything. Could I have given each client the ability to communicate directly with the database? Probably, but don't tell my customer that(!) When I saw they wanted to know of changes within seconds (similar to Outlook was the requirement, used DesktopPopup component from DevelopedComponents.net (http://www.developedcomponents.net) for the popup window) I took it to the hilt from there. In addition, this way people offsite can have the same immediate notification, etc.
You have less than 10 people. How about you?
Joined: 26-Oct-2003
swallace wrote:
You have less than 10 people. How about you?
Heh, for reasons similar to yours actually. I'm building in a notifications system whereby users can get notified of new events (new requisition that needs to be filled, a PO that needs to be approved, a critical stock item dropped below reorder level, etc). I'm wavering between doing direct database polling from the client (shudder) and a server-based BL with events - the events being the notifications back to the clients. I was considering using a toaster control like you used as well.
The other thing that's making me lean toward a server-based services layer is the concept of proactive concurrency. If it's not too much more difficult to use remoting here, it makes sense to build in concurrency control where the users are notified before there's a potential collision.
Jeff...
BTW, how did you like that toaster control you used?
Joined: 18-Aug-2003
The other thing that's making me lean toward a server-based services layer is the concept of proactive concurrency. If it's not too much more difficult to use remoting here, it makes sense to build in concurrency control where the users are notified before there's a potential collision.
Interesting...
BTW, how did you like that toaster control you used?
Eh, pretty good. It doesn't allow the bold headline and anchor link subheadline like Outlook. Instead everything is an anchor link (or not). Hasn't been updated in too long a time.
There's another one out there, the name escapes me, but it's not any more mature. The one I bought doesn't have source, so I couldn't make it better. I wish there were more choices here, but I think it's early yet.
Wait, here's the other one:
http://www.developerfood.com/forms/controlabstract,c244fbf5-673c-4a4c-9930-93d05985f5ab.aspx
(That's right, I'm referring you to my own site, and don't be afraid to click the ads!)
Note that Frans' site doesn't continue URLs with commas. Be sure to get the full link.
You might also check out a free control:
http://www.developerfood.com/forms/controlabstract,8be5258b-7b53-48b7-85e8-d673cd0f5340.aspx
Could be used as a toaster I guess.
Joined: 23-Apr-2004
Hi guys,
BTW, how did you like that toaster control you used?
I haven't read this entire thread so ignore me if this is of no use... You were talking about Toaster controls and I recall seeing two projects on Code Project that give you some examples of how to do this yourself. Looks pretty easy.
http://www.thecodeproject.com/jscript/myalerts.asp and http://www.codeproject.com/cs/miscctrl/taskbarnotifier.asp
Just thought you might be interested!
Marcus
Joined: 04-Feb-2004
jeffreygg wrote:
what are some reasons why native remoting doesn't work well for events?
Honestly, I havent really found this to be the case. I have found that there are certain things that you need to watch for, and there are some things that are very perplexing.
Here are the big things you need to handle with a remote event service.
- How will the client subscribe to the server?
- How will the server notify clients?
- What will happen if the server raises an event to a client that no longer exists
- How will clients unregister themselves from the server?
- How can we raise only certain events to certain clients, i.e. users in department A get events related to action A, etc.
Those are really the biggest issues that I have had to deal with. Scenarios 1-4 can be dealt with using a multicast delegate and a server activated singleton object. Question #5 can be handled 2 ways, you can have a server for each type of event, OR your can have one hashtable of multicast delegates, and you use the hashtable to "filter" the list of delegates to invoke.
The client and the server could share an interface, a delegate, and a MarshalByRefObject that is a wrapper for the delegate. Basically here is how it would work:
- The server has a singleton object with an event in it which conforms to the shared delegate
- The shared wrapper would have an event handler and an event
- When the client starts, it creates an instance of the remote server, and the shared wrapper
- The client wires an event handler for the shared wrapper's event, to the clients event handler
- The client wires an event handler for the server's event, to the shared wrapper
- There can be an unlimited number of clients, registering, as well as raising events
The server uses a MultiCast Delegate, and the MultiCast Delegate's Invocation List, to notify all clients. Internally, when a client performs an action on the server, the server calls an internal method, and iterates through it's invocation list. When the delegates are invoked, they point to a client specific instance of the shared wrapper. When the event is handled by the specific wrapper, the wrapper raises its event, which in turn, gets handled back on the client side for the client holding the reference to the wrapper.
In the event that the server tries to invoke a delegate, but the client isnt there, the server simply removes the handler. When a client closes, it can remove it's handlers in the OnClosing.
So basically, thats how you can handle scenarios 1-4.
Scenario 5 is a bit difficult, and what it boils down to, is that you need to come up with a scheme to "key" the delegates that are stored in the invocation list. When the cleint performs an action on the server, it passes the "key" along to the server, and the server only invokes delegates that have matching "keys".
I have a sample application that I would be more than happy to share with you. Its about 300 lines of code, in C# that demonstrates most of the things in this post. If you want the code, just contact me using the forum here or my profile.
I had actually considered purchasing the genie suite at one point but I did not, because I realized that I really didnt need to. One reason is because I felt like it was important for me to understand what was going on unde the covers of remoting, and the other reason, is they really only had 2 features that I was interested in, which was encryption and multicasting, both of which I figured out on my own.
Joined: 15-Oct-2004
interesting thread...
I came across this article by Mr. Lhotka (Everyone Into the Pool) that I think is relevant to some of the issues mentioned by Devildog
I don't know if Mr. Lhotka's article answers all these concerns... I guess I have to do my homework
What do you think Devildog ?
Omar
sorry... forgot to post the link
Joined: 04-Feb-2004
omar wrote:
I came across this article by Mr. Lhotka (Everyone Into the Pool) that I think is relevant to some of the issues mentioned by Devildog
What do you think Devildog ?
I think the article is a great article on ObjectPooling and COM+. Jeff is leaning toward more of a pure remoting approach, so he wont have COM+ ObjectPools available to him (unless he codes it himself)
I will tell you this, raising an event from a COM+ server back to a client is dependent upon DCOM Security Settings and is a real nightmare.
In regards to object pooling, it has it benefits. In many service based applications there are certain areas of code (server side) that get called very frequently, so putting these particular objects in a pool can save time and resources. The objects in the pool do need to be identical.
Swallace: the code is in the mail.