Remote Observer

download Remote Observer

of 5

Transcript of Remote Observer

  • 8/13/2019 Remote Observer

    1/5

    Design and Implementation Considerations in aDistributed Observer System

      ∗

    Karl Ridgeway

    James Madison UniversityDept. of Computer Science

    Harrisonburg, [email protected]

    David Bernstein

    James Madison UniversityDept. of Computer Science

    Harrisonburg, [email protected]

    John Magnotti

    §

    James Madison UniversityDept. of Psychology

    Harrisonburg, VA [email protected]

    ABSTRACT

    The observer pattern is widely used to decouple objects ina publish/subscribe relationship. Because many distributedsystems contain such relationships, this pattern is a naturalexpression of these systems. However, implementing a dis-tributed observer system places unique constraints on boththe implementation of the pattern and the remote proce-dure call framework that is used to support it. This paperexplores these constraints and discusses some idioms to workaround them while maintaining the semantics of the originalpattern.

    Categories and Subject Descriptors

    D.2.8 [Software Engineering]: Design—methodologies 

    General Terms

    Design

    Keywords

    Obsever Pattern, Proxy Pattern, RPC

    1. INTRODUCTIONThe observer pattern as described in [2] is one of the sim-

    plest, most powerful, and most frequently employed patternsin the pattern literature. Its ability to decouple a subjectfrom its observer and to broadcast state changes transpar-ently makes it an essential component pattern of many com-mon higher-level architectures. The model/view/controller(MVC) architecture is widely considered one of the seminal

    ∗Use with permission only.†Current affiliation: Rosetta Stone, Inc.‡Corresponding author.

    §Current affiliation: Auburn University

    Technical Report IVSL-2 (April 2007)Immersive Visualization Systems LabJames Madison UniversityHarrisonburg, VA 22801

    use-cases for the observer pattern. The MVC architectureis composed of three basic elements:

    Model  The data being presented

    View  The presentation of the model to the user

    Controller  The translation of user commands into actionson the model

    Since the primary purpose of MVC is to reduce couplingbetween these three components, this architecture is widelyemployed when there is a need to locate one or several of these on disparate physical machines. Since most of theinter-object messages in an MVC system are notifications of changes in objects’ state (e.g. The model notifying the viewof a change in the data), the observer pattern is often themechanism used to connect these components. Therefore,to ensure the correctness of a distributed MVC system, it isessential to examine the implementation of the underlyingdistributed observer system.

    This paper discusses the distributed observer pattern inthe context of the four phases of the observer lifecycle: boot-strapping/discovery, normal execution, handling failure cases,and gracefully shutting down the system. During each phase,we will discuss the additional constraints placed on both thepattern and on the remote procedure call (RPC) mechanism.

    2. THE THREADING ENVIRONMENTAs discussed in [1], the most significant difference be-

    tween an application running on a single computer and adistributed application is that the distributed application isby nature executed in multiple threads, at least one per com-puter. While it is possible to implement an ”observer-like”system in which multiple threads are executing simultane-

    ously, the observer pattern is normally described in the con-text of a single thread of execution. Therefore, this paperonly discusses systems composed of a single ”logical” thread.Specifically, we assume that we are using an RPC frame-work that supports synchronous, blocking method invoca-tions (e.g. Sun’s RMI) to guarantee that only one computermay be executing code that is part of the pattern at a time.

    Note that this assumption does not preclude the develop-ment of a ”hybrid” multiprogrammed and distributed appli-cation (see [1], for example). Instead, this assumption placesa limit on the observer system in that application.

  • 8/13/2019 Remote Observer

    2/5

    3. BOOTSTRAPPING THE OBSERVERIn order to initialize a group of objects in a pattern, the

    participating objects need to be constructed and related toone another. For obvious reasons, we refer to this as “boot-strapping.” In the case of the observer pattern, the boot-strapping process can be described as follows:

    1. A subject is created;

    2. One or more observers is created;

    3. The observer obtains (or is given) a reference to thesubject; and

    4. The subject is given a reference to the observer (or theobserver “registers” itself with the subject).

    We now discuss these steps in the context of a system thatincludes distributed observers.

    3.1 Creating the ParticipantsBecause the creation of a subject and observers is gen-

    erally done dynamically during the execution of a program(i.e., new observers can be constructed and registered at

    runtime), the RPC framework employed must support thedynamic promotion of an Object from local to global acces-sibility. Fortunately, most systems we encountered (RMI,CORBA, DCOM, .NET Remoting, etc...) do provide sup-port for this feature.

    3.2 Obtaining a Reference to the SubjectAfter creating the subject and observers, the program

    should provide some way for the observers to register them-selves with the subject. To accomplish this, the observerneeds to obtain a reference to the subject. In general, thereare two approaches:

    Discovery (Observer-Pull)  The observer uses a remote

    object discovery mechanism to locate the subject andobtain a reference to it (or another object discovers thesubject and injects that reference into the observer).

    Smart References (Subject-Push)  The subject initiatesa remote method call that sends a back-reference to themachine running the observer.

    Distributed systems commonly use a discovery mechanism(e.g., Sun’s JNDI) to obtain references, even though it doesmake the code more complex and introduces additional par-ticipants. The shortcoming of this approach, especially inthe context of distributed observers, is that it significantlydifferentiates the distributed and non-distributed implemen-tations. That is, non-distributed systems that use the ob-

    server pattern rarely use a discovery mechanism. Hence, inorder to maintain the semantics of the classical pattern, weoften advocate the use of smart references.

    Not surprisingly, most Java-based RPC frameworks do notsupport arbitrary reference-passing across remote methodcalls. This is due to the fact that Java’s pass-by-value se-mantic breaks down when passing a reference to an object(its address in memory) out of its original address space.However, there are approaches that make this possible. Forexample, Moxaic  has a command pattern-based RPC mech-anism that provides a facility for transporting references to

    services in a remote method call (see [3]). As another exam-ple, Java’s RMI can be extended to pass a direct referenceto the remotely accessible object by copying the RMI stubs(as in JNDI).

    3.3 Registering with the SubjectIn order to finish the bootstrapping process, an observer

    must be registered with the subject. Typically, a messagecontaining a reference to the observer is sent to the subject.Hence, we again need a mechanism for passing references inan RPC framework.

    Obviously, we could use the mechanism discussed above topass references. However, since the observers are typicallyrunning in separate threads (indeed on different machines),these registrations are not naturally atomic (relative to oneanother and/or update notifications).

    Given our assumption that the RPC framework confinesthe participants in the (distributed) observer pattern to asingle logical thread, this natural concurrency does not causeany problems.

    4. NORMAL OPERATIONThe two major additional constraints that distributing an

    observer implementation places on the design of the observerand on the RPC framework involve enforcing the implicitcontracts of the Observer and optimizing implementationdetails for performance.

    In order to enforce the operational semantics and pre-serve transparency of the pattern, it is essential to examineits dynamic behavior. In general, any collaboration of thesubject/observers involves:

    1. Changing the sub ject’s state through an invocation of setState().

    2. Invoking the subject’s notify() method (which causesthe subject to iteratively invoke the  update()  method

    in each of its observers).

    3. Each observer responding by either ignoring the up-date, querying the subject for the changed state, orusing the information passed as an argument to itsupdate() method.

    4.1 Enforcing the Observer ContractsThere are several constraints, some explicit and some im-

    plicit, that make up the set of “contracts” for the observerpattern.

    Probably the most important of these is the assumptionthat no observer may change the subject’s state during anupdate notification, thus triggering another (potentially re-cursive) round of update notifications. In practice, this con-tract can be strengthened by employing the use of the“push”model (see [2]) to supply observers with the information theyneed to react to a subject state change. By not providing theobservers with a back-reference to the changed subject, wecan prevent them from triggering another state change andbreaking this contract. However, since each remote methodinvocation is potentially expensive in a distributed program,this “push” model is less attractive.1

    1The use of a true broadcast mechanism will be discussedshortly.

  • 8/13/2019 Remote Observer

    3/5

  • 8/13/2019 Remote Observer

    4/5

    S u b j ec t s u bj =   new   C o n c r e t e S u b j e c t ( ) ;

    /∗∗   By p l a c i ng a l l t h re e s e t S ta t e ∗ ( ) c a l l s i n si d e∗   o n e S u bj ec tM ut at o rC o mm an d , w e a v o i d c a u s i n g

    e x c e s s i v e∗   u p da te n o t i f i c a t i o n s .∗/

    s u b j . m u t a t e ( new   SubjectMutatorCommand (){

    p u b l i c v o i d   m u ta t e ( M u t a b l e S u b j e c t s u b j ){

    s u b j . s e t S t a t e 1 ( new   O b j e c t ( ) ) ;s u b j . s e t S t a t e 2 ( new   O b j e c t ( ) ) ;s u b j . s e t S t a t e 3 ( new   O b j e c t ( ) ) ;

    }}) ;

    In this example, access to the mutator methods in   Con-creteSubject   is limited by the convention of always us-ing the  Subject   interface type instead of   MutableSubjector  ConcreteSubject. This approach is advantageous be-cause it preserves the semantics of placing the  notifyOb-servers()   call inside the subject, and enables client codeto create a ”transaction” out of multiple mutations (callsto  setState*()). This technique avoids excessive calls tonotifyObservers()  which have the potential to be very ex-pensive in the context of a remote observer implementation.

    However, it is important to note that this solution is spe-cific to the “pull” model. That is, it assumes that observerswill call back to the subject to obtain further information

    about the state change. This system could be extended tosupport a “push” model by logging calls to each mutatormethod and using that information to provide an aggregatelist of state changes that occurred. However, this variationof the push model assumes that observers only care aboutthe modifications made since the last notify().

    The possibility of using a true broadcast communicationsmechanism to support efficient notify() calls is mentioned in[2]. Since there usually exists a one-to-many relationship be-tween subject and observer (and an RPC mechanism makesremote calls expensive), this option seems attractive at firstglance. Unfortunately, there are some serious drawbacks tothis approach. Most importantly, any such system wouldhave to be painstakingly written by hand, since most RPC

    frameworks (e.g., RMI, CORBA, Moxaic) do not supportbroadcast communication. RPC frameworks do not sup-port broadcast communication because this style of messageis fundamentally different from a procedure call. A broad-cast message naturally executes concurrently for multiple re-ceivers and it generally receives no return value (and cannotcommunicate error conditions through exceptions). In fact,the concurent nature of the broadcast message breaks oursingle-logical-thread rule by causing truly concurrent callsto  update(). While such a system may in fact prove veryefficient, it breaks the Observer contract by not being a trueprocedure call and reduces application code transparency bycircumventing the RPC framework.

    Another common performance optimization involves cre-ating a return type for the update() method (often a boolean

    value). This technique is usually used one of two ways: to“handle” an event notification (for example, in an event bub-bling scenario), or to “unregister” an observer after this callto  notify(). Adding a return type to the update methodplaces the additional burden of supporting return values onthe RPC framework.

    5. HANDLING FAILURE CASES AND SHUT-

    DOWNIn this section, we will examine the behavior of two general

    failure cases:

    •  An exception thrown by the subject; and

    •  An exception thrown by the observer.

    We break it down in this manner because code executingin these two objects will, in a distributed observer system,be executing on separate machines. As a result, distributed

    observer systems will exhibit different failure patterns fromnon-distributed systems. On a single machine, both of thesescenarios will result in an exception bubbling up to the rootof the call stack and either being handled or causing theapplication to exit.

    A failure in the subject code on a remote machine will be asilent failure by default. In effect, the observers simply stopreceiving update notifications. Hence, there is no semanticdifference between the subject shutting down and failing re-motely. There is no chance for an exception to bubble upto the observers because they are not present in the “logicalcall stack” (having initiated, directly or indirectly, an activecall through the failed subject).

    While the RPC mechanism could very well detect a re-mote subject failure, adding a failure message dramaticallychanges the pattern and creates a serious burden for pro-grammers using the system. Alternatively, one could con-struct a polling system to routinely check the subject for“liveness”. However, this is well outside the domain of thetraditional observer pattern implementation, and would re-quire a serious amount of additional code and decidedly in-elegant modifications to the original system.

    When a thread fails while running inside an observer, mostRPC mechanisms will report the exception back to the sub- ject (since it is part of the “logical call stack”). At thispoint, the exception can be handled gracefully, the observerremoved from the list, and the application can continue run-ning. Since observers are on separate machines, this situa-tion is slightly preferable to the single-machine model. That

    is, observer machines can go down unexpectedly, but theapplication can continue running.To shut down a system using the observer pattern, it

    is necessary to either de-register all observers, or simplydelete the subject through some special shutdown mecha-nism. Deregistration is similar to the above section on ob-server registration. Deleting a subject seems to be similarto the traditional implementation. Since a subject can beremoved silently, the only concern here is to inform the ob-servers of the deleted subject (which can be done through anotify() call (see pg. 297 in [2]).

    6. CONCLUSIONThis paper explored some of the implications of employing

    the use of an RPC framework when developing a distributedimplementation of the observer pattern. We considered itsimpact on the design of the pattern and the requirements itplaces on the RPC framework through the various stages of the observer lifecycle.

    Several considerations arise during the bootstrapping/ini-tialisation phase. To facilitate the dynamic nature of ob-server registration, the RPC framework must support dy-namic promotion from local to global accessibility. Luckily,this seems to be widely supported. We also discussed twopossible strategies for providing a subject reference to the

  • 8/13/2019 Remote Observer

    5/5

    observers (and for providing observer references to the sub- ject during registration). An active discovery mechanismsuch as JNDI is easily implemented and places no additionalconstraints on the RPC framework, but somewhat changesthe reference-passing semantic of the pattern. Alternatively,the use of a passive reference-injecting mechanism in whichthe subject pushes a back-reference to itself (indirectly) toa remote observer implies that the RPC mechanism has afacility for transporting remote references.

    When considering the operational phase of the Observerin a distributed environment, we examined some additionaldifficulties that the RPC framework imposes on the enforce-ment of the Observer “contracts”. One such contract speci-fies that no observer may change the subject’s state duringa notification. A natural method of strengthening this con-tract is to employ the use of the “push” model mentionedin [2]. Unfortunately, this option becomes less attractive ina distributed situation due to the expense of sending addi-tional information in a remote procedure call. A common vi-olation of the observer contract is the misuse of the  update()method on the observer by a participant that is not the sub- ject. We discussed some potential methods to strengthenthis contract, including package visibility/friend classes, an

    authentication system, and the use of a Command to triggerthe update. Unfortunately, the most attractive option, theCommand, is not usually feasible in a distributed environ-ment.

    The additional cost of method invocations places signif-icant constraints on the design of a distributed Observersystem. We therefore examined several design aspects of the Observer that can be optimized to reduce the number of method invocations. To avoid additional redundant invoca-tions of the update() method on observers, we can employ atransactional strategy that can be adapted to work in a dis-tributed environment by employing the Command pattern.Another common idiom for reducing the volume of subjec-t/observer message passing is to make use of a return valuefor the   update()   method. This can become an issue if the

    RPC mechanism does not support return types. Finally,we considered employing a true broadcast communicationmechanism to facilitate observer updates. Unfortunately, abroadcast message is functionally too different from a tra-ditional message to be considered a functionally equivalentreplacement.

    Finally, we considered the behavior of the distributed ob-server during the termination phases. These included failurecases and graceful shutdown. We noted that a subject fail-ure on a remote machine will fail silently, unlike a subjectfailure on a single-threaded application. A remote observerwill also fail ’silently’. However, this could potentially bean improvement on the single-threaded model. Fortunately,gracefully shutting down the system poses no additional con-cerns beyond those already covered.

    7. REFERENCES

    [1] G. R. Andrews and F. B. Schneider. Concepts andnotations for concurrent programming.  Computing Surveys , 15(1), 1983.

    [2] E. Gamma, R. Helm, R. Johnson, and J. Vlissides.Design Patterns:Elements of Reusable Object-Oriented Software . Addison-Wesley Publishing Company,Reading, Massachusetts, 1995.

    [3] K. Ridgeway, D. Bernstein, and J. Magnotti. Designand implementation of a remote procedure callframework. Technical Report 3, ImmersiveVisualization Systems Lab, James Madison University,2007.