Client-Server-Kommunikation mit dem Command Pattern

Post on 24-Jun-2015

1.419 views 2 download

Tags:

description

Eine Client-Server-Architektur stellt besondere Anforderungen an die Client-Server-Kommunikation. Einerseits wird Sparsamkeit angestrebt, andererseits absolute Flexibilität, Wiederverwendbarkeit und Wartbarkeit. Gerade im GWT-Umfeld fehlen clientseitig eine vollwertige JVM und das Reflection-API. Hinzu kommt noch der teilweise ungewohnte Umgang mit den asynchronen Aufrufen. In diesem Vortrag wird das Command Pattern vorgestellt. Es werden konkrete Lösungsansätze für Batching, Caching, Security und Journaling vorgestellt.

Transcript of Client-Server-Kommunikation mit dem Command Pattern

Client-Server-Kommunikation mit dem Command Pattern

p.g.taboada | pgt technology scouting GmbH

Papick G. Taboada

pgt technology scouting GmbH!http://pgt.de

Orientation in Objects GmbH!http://oio.de

http://gwtreferencelist.appspot.com

‣Client-Server communication

‣Command pattern

‣Versioning

‣Batching, Caching

‣Scaling

Browser Server

user action

full html response

full html response

full html response

user action

user action

classi

c web !

development

Browser Server

event

first request

full html response

data

data request

data

data request

event

event

event

RIA web

development

Honor the A in JAX

‣ Javascript does not block !Get over it

‣ Latency is not a myth

‣ Results must not arrive in the call order

BUILDING A GENERIC FRAMEWORK FOR MARSHALLING/ UNSMARSHALLING DATA SUCKS

MARSHALLING / UNMARSHALLING IN JAVASCRIPT IS SLOW

DON‘T BIND YOU NEXT 3 YEARS OF

WORK AGAINST SOME

COMMUNICATION PROTOCOLL

LOADING TOO MUCH DATA WILL ALWAYS

HURT

‣Client-Server communication

‣Command pattern

‣Versioning

‣Batching, Caching

‣Scaling

GWT-RPC is a good solution if handled with care

SomeResult someMethodName(SomeParameter spo)

GWT-RPC binds many

methods into one interface

Interface Versioning

is a monstrous

thing

SomeResult someMethodName(SomeParameter spo)

this will be an object

this will be an object too

SomeResult someMethodName(SomeParameter spo)

the method names bind the requests to the result

typesafety all the way

USING GENERICS FOR !

TYPESAFETY, !

GET RID OF METHODS !

AND INTERFACES

<A extends Action<R>, R extends Result> R execute(A action);

now we just one interface with one method

typesafety all the way

!

command pattern

GOF Pattern !

commonly used in Rich Clients

!

someAction

someResult

someActionHandlerEXECUTE

someAction

someResult

someActionHandlerPOJOS

someAction

someResult

someActionHandler

GWT-RPC

client server

batching caching security

caching exception translation security

GWT client

someAction

someResult

someActionHandler

RMI / HTTPInvoker

client server

batching caching security

caching exception translation security

Java client

someAction

someResult

someActionHandler

JSON-servlet

client server

batching caching security

caching exception translation security

Mobile client

public class TerminLoadAction implements Action<DataResult<TerminData>> { ! private String terminId; ! public TerminLoadAction(String terminId) { this.terminId = terminId; } ! public String getTerminId() { return terminId; } }

public class DataResult<DATA extends Data> implements Result { ! private DATA data; ! public DataResult(DATA data) { this.data = data; } ! public void setData(DATA data) { this.data = data; } ! public DATA getData() { return data; } !}

aka DTOs

Action Result

Reusabletype safety

dispatch.execute( ! new TerminLoadAction(terminId), new AsyncCallback<DataResult<TerminData>>() { ! @Override public void onFailure(Throwable caught) { } ! @Override public void onSuccess(DataResult<TerminData> result) { } ! } !);

<A extends Action<R>, R extends Result> void execute(A action, AsyncCallback<R> callback)

public interface ActionHandler <A extends Action<R>, R extends Result> { ! Class<A> getActionType(); !!!! R execute( A action, ExecutionContext context) throws DispatchException; !}

Server side

type safety

handler to action

mapping

action execution

declared exception hiearchy

Execution context for server side command

execution

@ActionHandlerBean @Transactional public final class TerminDataLoadHandler implements ActionHandler<TerminLoadAction, DataResult<TerminData>> { ! @Autowired private TerminDAO terminDao; ! @Override public DataResult<TerminData> execute( TerminLoadAction action, ExecutionContext context) throws DispatchException { ! TerminBean termin = … ! TerminData data = … ! return new DataResult<TerminData>(data); ! } ! @Override public Class<TerminLoadAction> getActionType() { return TerminLoadAction.class; } !}

Server side

custom annotation

spring

access to backend

type safe result

business logic, etc…

‣Client-Server communication

‣Command pattern

‣Versioning

‣Batching, Caching

‣Scaling

RPC interface

hell?

public interface SomeNiceService extends RemoteService { ! String someService(String param); ! String someServiceV2(String param); ! String someServiceV3(String param); }

public interface SomeNiceService extends RemoteService { ! String someService(String param); !} !public interface SomeNiceServiceV2 extends RemoteService { ! String someService(String param); !} !public interface SomeNiceServiceV3 extends RemoteService { ! String someService(String param); !}

easy way right way?

maintainability?maintainability?

someAction

someResult

someActionHandlerPOJOS

someAction

someResult

someActionHandlermultiple versions

someActionV2

someActionHandlerV2

same result

different versions can coexist!

someAction

someResult

someActionHandlermultiple versions

someActionV2

someActionHandlerV2

someResultV2 different results

‣Client-Server communication

‣Command pattern

‣Versioning

‣Batching, Caching

‣Scaling

why batch?

solving common problems

• one batch call is better than 10 single calls

• less data

• less roundtrip latency

• avoid connection bottleneck

• ensure server side execution order

• less roundtrips

batchAction

someAction1

batchActionHandler

someAction2

someAction3

batchResult

someResult1

someResult2

someResult3

client server

batching can be manual or

automatic

server executes actions in given order

someAction1

someAction2

someAction3

automatic batching?

GWT code execution

IDLE

browser event loop

Scheduler.scheduleEntry(…)

Scheduler.scheduleFinally(…)

Scheduler.scheduleDeferred(…)

GWT code execution

IDLE

Scheduler.scheduleFinally(…)

collect commands

fire batch command

cmd 1!cmd 2!cmd 3!cmd …

BATCH EXECUTION ALLOWS FOR FINE GRAINED COMMANDS AND REUSE

toggleTerminMetadata

reloadDashboardTermine

BooleanResult

DataListResult<Termin>

toggleTerminMetadata

reloadTermin

BooleanResult

DataResult<Termin>

toggleTerminMetadata

loadMonthStats

BooleanResult

DataResult<MonthStats>

loadMonthTermine DataListResult<Termin>

Caching

• Introduce cacheable interface

• simple marker interface,

• or more elaborate version with cache id, expiration time, etc…

• Implement caching (client or server side)

Patient 1!!

Patient 2

Patient 1 details

0101010101010101001010101010101010101010101010101!0101010101010101001010101010101010101010101010101!0101010101010101001010101010101010101010101010101!0101010101010101001010101010101010101010101010101!0101010101010101001010101010101010101010101010101!0101010101010101001010101010101010101010101010101!0101010101010101001010101010101010101010101010101!0101010101010101001010101010101010101010101010101

Ops.

action 1

action 2

result 2

result 1

execution 1

execution 2

action 2

Ensure „only last“ resultaction 1

result 1

action 1 handler

action

result

„smart dispatch“

result 2

check resultdeliver if last!

last action is:

result 1

Re-Auth

• If server exception is security exception, try to reauth and than re-execute commands

‣Client-Server communication

‣Command pattern

‣Versioning

‣Batching, Caching

‣Scaling

• Every client brings his own CPU power

• The client does the page rendering

• GWT provides different ways to reduce number of requests even more

• The server must „only“ authenticate the user and provide the data, perform the actions requested by the client

GWT scaling is easy...

WHAT CAN POSSIBLY GO WRONG?

LETS TALK HIGH TRAFFIC... HIGH TRAFFIC IS WHEN ONE SERVER IS NOT ENOUGH

• Bandwith issues

• Connection pool bottlenecks

• Thread pool bottlenecks

• CPU bottlenecks caused by reflection API calls

• High JVM garbage collection CPU usage

HIGH TRAFFIC PROBLEMS

NOT REALLY GWT PROBLEMS, BUT WHAT CAN WE DO?

TX TX

TX TX

TX

TX

TX TX

TX

TXavoid „tx collisions“

5 gleichzeitige Transaktionen

TX TX TX TX

TX

TXTX

TX TX

TX

TX

TXTX

TX

TX

load small portions of data, do it often

IMPLEMENT REAL LOAD BALANCING EACH REQUEST GOES TO THE NEXT AVAILABLE SERVER

• Don‘t stick a session to a server. Why send a user over and over again to a possible overloaded server?

• Don‘t store anything on the HTTP session. Share session content outside web container

• Session replication is expensive and does not scale well

• Let the load balancer distribute calls to available servers

SCALING HOW-TO

Webserver

Webserver

LB Webserver

Webserver

Webserver

Session Cache

STATELESS WEBAPP

Webserver

Session Cache

Session state could contain user id, client id, session id, user roles

If session cache becomes bottleneck, use distributed cache

Session Cache

Session Cache

Thanks!