Showing posts with label Architecture. Show all posts
Showing posts with label Architecture. Show all posts

Message Locker

Problem

Extreme requirements require interesting solutions. Sometimes there is a need to come up with hybrid solution, that not always seems to be beautiful on first sight. One example is a Message Locker solution.

In service oriented architecture, application consists of many services that interact with each other.

Inevitably comes a need to fight high latencies caused by remote calls and necessary serialization/deserialization ( in a huge chain of dependent services calls, where each call results in a network hop with required fees like data marshaling and passing data through the network, adds at least a few milliseconds extra for each call.)

Service that requires to gather output from multiple dependencies to do its job is an aggregating service.

Such service needs to be smart at how it calls dependencies. If they are called one by one, then their latencies would be accumulated. The most obvious way to prevent this is to call each dependency in parallel. Now, service own latency would be defined mostly by its slowest dependency. In this case, we say that slowest dependency is in the critical path.

Aggregating service isn’t complex because it needs to call multiple services in parallel. And usually, there is simple way to avoid creating another service, if only business value it adds is aggregating output of multiple dependencies.

But, aggregating service becomes complex when:
  1. It adds complex logic on top of the data returned by dependencies
  2. It has to be sophisticated at orchestrating calls to many dependencies.
The need to orchestrate comes from the nature of SOA: sometimes Service need to call one or more dependencies first to gather the data necessary to call another dependency. Often it’s not possible to call all dependencies in parallel and just aggregate replies once all are available. In many cases, Service needs to call dependency A, to get the data necessary to call dependency B, results from which are required to decide if Service needs to call dependency C or D and so on.

Optimal call of dependencies is often the most important thing to do when fighting high latencies. And thus, eventually comes a need to have Aggregating service, that can call multiple dependencies in a savvy way.

But, even when there is an aggregating service in use already, inevitably comes a need to fight high latencies. And there are only so many ways this can be done:
  1. decrease latency for each dependency in the critical path (often by pulling dependencies of own dependency, and call them first)
  2. call dependencies in even smarter way.

This post stops on the 2nd way. If aggregating service already parallelizes calls to dependencies as much as possible and there is no way to make it even better, then, to be honest, not much can be done anymore.

Seriously, when service A needs to call dependency B so it can call dependency C later, what else can be done to save extra 10 ms you need that much?

That’s where Message Locker comes useful. It goes to a bit nasty territory to allow save additional milliseconds in aggregating service.

Message Locker

"Message Locker" means a Locker for a Message. Service allows to store a message in the some kind of locker, so only specific client can grab it. If message is not received during certain period, message becomes unavailable.

Message Locker is a distributed service that stores all the data in the memory. Client that sends a message into the locker is called sender. Client that receives message from locker is called receiver.

Each message is stored in the locker using a unique random key. When sender puts a message into the locker, it also provides additional attributes, like:
  1. TTL - time to store the message in the locker,
  2. Reads - number of times the message can be received.

Message would be removed from the locker whenever received for defined number of times or once its TTL expired. These rules prevent Message Locker to be bloated with obsolete messages.

Even after message was removed, Message Locker is still aware of it previous presence. Whenever receiver tries to get evicted message, it gets an error immediately.

In case receiver tries to get a message that is not evicted yet, it is returned to the receiver, and number of reads is increased. This approach doesn’t handles retries properly though.

In case receiver tries to get a message that is not sent yet, then Message Locker will hold the request until message becomes available or timeout happens.

How to use Message Locker?

Given 3 services A, B and C. Service A is an aggregator service, that calls multiple other services, among them services B and C. Service B has to be called before service C, as its output is part of input for service C. Service A also uses output of service B for own needs later as well.

Normally, service A would call service B, wait for reply and then call service C. During this workflow, service A needs to do following work before it can call C. This extra work becomes part of critical path:
  1. wait for reply from service B
  2. read reply from service B
  3. construct and call service C.
Network and extra serialization/deserialization are often expensive operations, and when one works with large amounts of data, could take 5-10ms. In this case, construction request and making remote call to service C also can add additional 5-10ms.

Without Message Locker

This is where Message Locker becomes helpful. Workflow is now changed: service A calls service B with key K, and in parallel calls service A with key K, B puts its reply into MessageLocker using key K, service C receive this reply using key K. Service A also receives service B’s reply from Locker using key K, and does this in parallel with service C call.

With Message Locker

In this case, there are following notable changes:
  1. time to construct and call service C happens in parallel with call to service B, and as such is removed from critical path
  2. time to deserialize request and do necessary initial work by service C is also execute in parallel with call to service B, and as such is removed from critical path
  3. time to deserialize reply from service B in service A also happens in parallel with call to service C, and as such is removed from critical path
  4. time to call to Message Locker, receive and deserialize received data by service C are added to critical path. This would eliminate savings added by #2.

Using Message Locker also adds complexities:
  1. Service A, B and C need to be integrated with Message Locker
  2. Service A or B needs to know how many times message would be received from locker or what timeout to use in order to not overload Message Locker with not need message and not cause issues with message being removed to fast.

Why not use existing solutions like...

Message Locker by itself is very similar to well known existing solutions: Message Broker and Distributed Cache. Although similarities are strong, there are a few differences, that make Message Locker to stand out for its own very specific use case.

Message Broker?

Message Broker would usually have a predefined list of queues. Producers would send messages to the queue and Consumers would consume. It is possible to create temporary queue, but it is usually expensive operation. Message Broker usually assumes processing latencies are less important than other traits, like persistence or durability or transactionality.

In this case Message Broker can’t be a good replacement for Message Locker.

Distributed Cache?

Message Locker is more like a distributed cache, with additional limitations. Message is stored only for 1 or few reads or very limited amount of time. Message is removed from locker as soon as it becomes “received”.

In ordinary caching, it is expected that content becomes available for much longer period than it is in Message Locker.

Summary

Message Locker is a way to decrease latencies in aggregation services by enabling additional parallelization. This is possible, as dependency between services are organized through a proxy - Message Locker. It holds the replies from dependencies and provides them to the receiver as soon as they are available. This allows to further hide expensive operations: network call and serialization/deserialization.

This comes with additional complexities:
  1. Right value, for timeout and number of reads to evict, can be error prone to define,
  2. Message Locker development and support can be cumbersome as well,
  3. Restructuring services to benefit from Message Locker.

But when there is no other choice and latencies had to be increased, Message Locker could be a solution.

Structure101

I've found today my post on project wiki from Sept 1, 2008 about Structure 101. Structure101 is really a useful piece of software. Here is a post, which was written to introduce this program to other team members.

Structure101 is used to visualize the structure of application in graph of modules/packages/classes or in dependency matrix presentation. It is also hepls to build the architecture diagram with violations check support, find the tangles, fat packages, classes and methos in code-base.
Structure101 also provides web application that helps to find the information about current status of codebase, watch for changes in code-base, code complexity and dependencies. The web application shows information in informative tables and charts, helps to watch the changes from previouses versions etc.
Structure101 provides the plugins for IDE (Eclipse and IntellijIdea. Plugins can synchronize with public repository (it can be configured to use web application to get data from repository), so any updates to repository are available to developers and developers are always updated with the last architecture desicions.
Plugin can check for architecture violations while IDE builds the project and show the messages as warnings or errors (depends on configuration).

Using Structure101 were created few diagrams (Dao and Services, Functional Presentation, Layers Diagram, Current architecture diagram] that helps to see the architecture almost-complete-view.
In picture you may see the screenshot of Structure101 with architecture Layers Diagram:

Layered Diagram Structure101


IntellijIdea and Structure101
Developer's IDE (IntellijIdea) with installed Structure101 plugin can help to prevent not permitted dependencies within code:

Violatins of Layered Diagram IDEA


Structure101 web application
Structure101 has also web application that can be used to view the project code-base status using WEB. Web application gives to the architect and project manager complete information about dependencies, changes after previous version, tangles, XS etc.

Pricing
- Structure101 is payable. See more http://www.headwaysoftware.com/products/purchase.php.
+ Structure101 web application as plugins for Eclipse and IntellijIdea are free of charge.

SyncTab architecture. Part 2. Android Application

This post is a continuation for recent post with description of SyncTab server application. In this post I'm going to tell about SyncTab Android application.

As android application is very simple, I will make a very short description.

SyncTab application has a few activities only: the main activity is a list of shared links. When user first opens an application, she can either login into or register a new account. There is also a way to reset a password. User can only reset password, as original password is not stored; only salted hash of the password is stored on server. After user is signed in, she can see the list of links, edit settings and tags etc.

When user is authenticated and device is online, application starts two services: SyncService and RefreshService.

RefreshService connects to the server and checks if there are any new links to open on this device. Each device has an associated tag and opens only links with specified tag. Android device by default checks for the links with Android tag, and opens them if any. By default, RefreshService checks the server every minute if connection is up. But it is possible to change a period time or disable this service at all (if user doesn't want to receive links on device).

SyncService is used to synchronize android application status with server. Application allows to send links, when device is offline. In this case, link can't be send, but is added to the sync queue. Well, there are other operations that can be proceeded offline, like logout, remove link, re-send link, add/edit/remove tags. If device is offline, such operations are added to the sync queue. When network is app and device is online, SyncService checks the sync queue and executes each task in it. Sync queue tasks are persistent and stored in the database.

No hard coded values, except preferences names. Everything moved to the appropriate files like strings.xml, array.xml, integers.xml, colors.xml etc. Values vary not only for different localization, but for different devices (e.g. phone and tablet).

Documentation is available only online from synctab website. Website has two versions: for normal clients and for mobile clients. While, my phone will be redirected to the mobile version, a tablet will open a normal version of website.

There are two managers for each entity, a regular manager and remote manager. Application works mostly with regular manager, which itself calls remote manager if need. For example, there are TagManager and RemoteTagManager. To call an operation, activities use SyncTabFacade, while SyncTabFacade calls managers.

Activities started using special IntentHelper class, that provides a static functions like showLoginActivity(), showAboutActivity(), browseDocumentation() etc.

Links' favicons are cached as files in the cache directory. When a list of new links is retrieved, a favicon preloader thread starts. Thus, favicons are downloaded in background. If device is offline, and favicons can't be loaded, than an appropriate task is added to the sync queue for each favicon (and next time device is online, the favicons will be downloaded).

Well, looks like nothing interesting I can tell more about SyncTab android application.

So I decided to write a list of helpful facts about developing for Android as a separate post – "Tips: developing for Android".

SyncTab architecture. Part 1. Server.

This post is a continuation for my previous post with introduction to SyncTab. I'm going to describe SyncTab server application in this post.

Well, I had a desire to write a server application on python, but in result I wrote it on Grails. Why Grails? Because I was actively using it for more than a year to creating different web applications, including web API. And I knew that would be simple and fast to create such app with Grails and publish some sort of web service.

So server side is running on a single Amazon EC2 instance. Application is running under Tomcat. Nginx plays a role of proxy. MongoDB is used as a database, and mongodb grails plugin used to add MongoDB.

API is very simple. It's based on GET/POST requests and JSON result with a status flag and other values, like auth token, list of tags and links.

Some code sample:


/**
* Returns the list of last available tabs.
* Client can pass a "tabId" parameter with an id of the tab to get tags for.
*
* Returns:
*  - status: "true" if was removed, otherwise "false".
*  - tabs: an array of found tabs.
*/
def getLastTabs = {
if (request.method != 'GET') {
response.sendError 405
return
}

User user = session.user
Tag tag = getTagFromRequest()
RecentTabConditions conditions = new RecentTabConditions(user, tag, LAST_TABS_NUM)
List tabs = sharedTabService.getRecentSharedTabs(conditions)

render([status: true, tabs: prepareTabs(tabs)] as JSON)
}

An authentication token system is used in SyncTab. Each time user enters his username/password to login, a new authentication token is created and assigned to user. Auth token is invalidated after two weeks.

As both Android application and Chrome extension should support not only login but also registration, it is a part of API too. Actually, user related API contains only 4 functions: register, authenticate, logout and resetPassword.

There are more API functions related to sending/receiving links and view/edit the list of tags.

A short about tags. Tags is just a way to name the device. For example, user can create a tag for his home computer and another tag for work computer, and tags for phone and tablet. Each device/browser is subscribed only to one tag, and will receive and open only links sent with specified tag.

Server not only responsible for storing and fetching links by client applications, but also for preparing links for user. Usually, when user sends a link, information about it contains only name of the device, tag id and the link URL. Server is responsible to fetch the link title, description, favicon link and the final URL. The final URL may differ from sent URL. For example, user could send a link like http://bit.ly/xNPUeo, but user should see this link as http://blog.khmelyuk.com.

Well, looks like there is nothing interesting left that I would like to tell about SyncTab server application.

Ah, source code is not public, and I'm not planning to open source it soon. As VCS I'm using Git and BitBucket as hosting service.

SyncTab architecture. Part 0.

A few months ago I was willing to write my own android application. And I also had a need - a way to send easily links from my phone to my browser and vice versa. Well, my phone is under Android, and my favourite browser is Chrome. So I decided to create the app to satisfy my desire to create and release Android app and make my life easier.

And as result of this, I have made a set of applications that forms a SyncTab. Obviously, those applications are Android application, server-side application and Chrome extension.

This post is like a preface, and next few posts will include a short technical description of each application.

Well, the work of application is very simple: android app and chrome extensions are both clients for the server. There is no web interface for application. User can get the list of all sent links and manage them using Android application.

In most functionality, Android app and Chrome extension are similar. But the only way to see the list of sent links is using Android application.


Some links:

MOBI version of The Architecture of Open Source Applications book

The Architecture of Open Source Applications is a great book where one can find the description of the architecture of the 25 open source applications, like Eclipse, LLVM, Mercurial, HDFS and Berkley DB. This book is free to read in the HTML format online, but if you want to get a PDF or Kindle version, you'll need to buy it either at Lulu.com or at Amazon.com.

Of course the recommended way is to buy the book, as all royalties from these sales will be donated to Amnesty International. But you can download a MOBI version for Kindle of this book for free, just continue reading.

First, want to tell a short story. After I found a free SICP version for Kindle compiled from HTML files at github.com/twcamper/sicp-kindle, I was looking for a chance to create something like that myself. And then I found the AOSA book. It has an HTML version, and I wanted to have a MOBI version to read it in my Kindle.

And so I made a Kindle version of The Architecture of Open Source Applications book and currently it's available from github.com/rkhmelyuk/aosa-mobi.

Download a Kindle version of the AOSA

Lazy loading on demand in CMS

Context:
Application is responsible for generating pages from templates. User can edit such templates to show data from storage. Data shown on the page are defined by template, each template can show separate set of data (for instance, news, tasks, articles etc.)

Problem:
How to render a user defined template correctly, so any provided by user or application data can be included into template in runtime and have a good performance of rendering?

Solution:
Lets view the problem from MVC point:
View is a template defined by user, and can use any data entered by user (news, blog articles, tasks etc.)
Model is data that should be used by a template engine to render a View.
Controller is a place where user can prepare the Model, that will be sent to a template engine to generate specified View.

As we can’t predict what kind of data are used in any particular View (it could be news, blog articles etc.), the simplest implementation is to fetch all data from storage and push them as a Model to the template engine. In this case template engine will render a View correctly, as all required data are available from the Model. The bad side of this approach is a very slow performance as we need to fetch all data and put them as Model again and again for each request. The more data and different types of data we have to use to populate a Model, the more time this phase will take.

Another approach is to analyze template on save or before render, to fetch all types of data we may need to render it right. For example, before saving a template, we found that it contains a references to blog articles and latest news. Although, we may need to run such operation only once and populate the model only with specified type of data, there is a large number of case not covered by this method: using predefined macros, including other templates and access to data that will be need in runtime, for instance: a single article with specified id, a list of latest 5 articles or anything else that need to be fetched dynamically.

If we think more about the last case, where we need to fetch data dynamically, we will find that it's much easier and better to populate Model not with data, but with data access objects. Of course, in this case we will need to create these data access objects on each request, to pass a context to theme and use them while rendering, it’s still much better (and faster), then populate Model with all data.

When I say a data access object, I don’t mean this object should get the data directly from database or any other storage. But I mean that this object can store request context and can access a restricted set of data, e.g. the list of news posted by current user only or the list of tasks that belongs to current user.

OK, hope your engine template supports methods call and you can get the list of 5 latest news just as simple as saying ${news.latest(5)} or get current user information just with ${user.profile()}.

But here I would like to propose another way to access those less dynamical data. For instance, we need to show user profile information or list of active tasks. Of course, this can be done with appropriate DAO from Model, but there is another way.

This another way helps to save templates clean, - without calling all those DAO methods, but also without prefetching data on the Controller side. This way is based upon a famous Lazy Loading technique.

Although, this may look a bit harder to implement, it brings us a few valuable benefits. First of all, as I said before, code looks clean and easier for user to work with. It's much pleasant to write ${news.latest} than ${news.latest()} and ${user.profile.firstName} than ${user.profile().firstName}.

Second, and it's related to the lazy loading too, we load data once and only when it's needed. The emphasis in on the word 'once'. When we hit our object from the Model first time, it's loading data, which then are available since and to the end of rendering phase. So no matter, from what part of template you access it, it will use already loaded data without touching a storage again. When I say "any part of template", I mean it can be anything available in template engine: macro, function or included template. In this case, you don't need to use a variable or local cache to store loaded data, as you may need to do with data access objects.

Third, lazy loaded data can be complex structures. For instance, we load a current user profile. Profile object is a structure that contains user names, characteristics, address, contact information and a list of followings profiles. Here, address and contact information are embedded objects, which are stored in separate tables/collections and list of followings is a reference to another a few profile objects. If you need to output user full name, you just don't want to load address information, contact information and list of followings. That's where we can also use lazy loading to save user time and server powers. We load address information when need, we load the list of followings when need, we load contact information of some following only when need.


In my next article I’m going to show a simple implementation of lazy loading technique for FreeMarker template engine, which is my favourite one for many years.

Book Review: 97 Things Every Software Architect Should Know

More then year ago I bought book 97 Things Every Software Architect Should Know for myself. I was expecting to get a book with some useful technical advices how to create cool software architecture,- that's what was always interesting for me.

Instead I've got the book with 97 small articles, each 2 pages long. No technical advices, no silver bullet, no advices on what and how use design patterns or modern technologies. Truly say, after reading few articles, I was upset. And leaved the book on my bookshelf and move on.

A year later, ie a month ago, I've took this book into my hands and decided that it's time to try to read it again. (Yes, I have a habit to re-read books again a year or two later, as found that it helps to understand much more and see the forest behind the trees).

I'm still reading this - few articles per week,- but decided to note my thoughts as review in this article.

In this attempt, book is very interesting. A year later my vision was changed cardinally again and now, I think, I can understand what those guys mean when they were writing their posts. These all can be said simply in one sentence:
Software Architects are bridges between business needs, software needs, technical needs and team needs.

Especially interesting were next articles for me (remember, I'm still reading):

  • Don't Put Your Resume Ahead of the Requirements

  • It Is All About The Data

  • Pattern Pathology

  • If You Design It, You Should Be Able to Code It

  • Empower Developers

  • Chances Are, You Biggest Problem Isn't Technical

  • Business Drives

  • Great Content Creates Great Systems

  • Start with a Walking Skeleton

  • Communication Is King; Clarity and Leadership, Its Humble Servants

I'm sure articles' titles are saying enough, so will not describe them. Want know more - just go and buy (as I did :)

A week ago I was reading "Business Drives" article. And especially remembered the summary of this article: "The long-term interests of the software development team are best served when business drives". And I agree with this summary. It's sad to know, that many software developers are still in the race for better skills and modern technologies if this is in damage for the project and business.

It's one of that books, that reminds that software is making by humans for humans.

So, my advise is to get and read this book; hope you're ready for it and hope I'm too :)

PS: Just found another review of this book http://dotnet.dzone.com/news/97-things-every-software

Presentations and articles about scalable software architecture

Last week was searching for interesting articles and presentations with samples of scalable and failure tolerant architecture. As result, my bookmarks increased with a number of new links to articles and videos.

Articles:

  1. Scalability Principles
  2. SEDA
  3. Large codebase organization with Spring
  4. Building Scalability and Achieving Performance: A Virtual Panel
  5. Scalability Worst Practices
  6. Shard Lessons
  7. Asynchronous Architectures [4]
  8. Thoughts on Development
  9. Hitting the scalability wall - Amdahl's Law
  10. 10 Lessons in Scalability from MySpace
  11. Twitter as a scalability case study


Videos & presentations:

  1. Randy Shoup on eBay's Architectural Principles
  2. Architecture Evaluation in Practice
  3. Availability & Consistency
  4. Architecting for Latency
  5. The Design and Architecture of InfoQ
  6. Architecture Quality: Operational Manageability
  7. How to scale your web app
  8. Behind the Scenes at MySpace.com
  9. Scaling Twitter





Cловники в предметній області

Словники предметної області займають вельми важливе місце при проектуванні та розробці програмного забезпечення. Не менш частіше використовуються словники в предметній області. В даному випадку, словниками можуть виступати невеликі набори даних в стилі ключ-значення, або більш складні, де кожному ключу відповідає набір значень. Прикладів таких словників є безліч, наприклад, словник країн, словник типів кредитних карточок, словник пріоритетів задач, і більш складніші словники матеріалів та продукції (за окремими вийнятками) тощо.

Ця стаття розповідає про моє бачення такого "патерна" як Словник. Важливо визначитися, що саме слід вважати словником в предметній області.

Словник – це набір термінів пов’язаних між собою певною областю використання, які проте рідко змінюються. Частіше всього, словники використовуються, для того, щоб надати користувачам вибір значень з певної множити, наприклад, країну проживання, стать, посаду тощо.

Словники складаються з записів, які собою являють пару ключ-значення. В залежності від значення словники бувають простими та складними. Простий словник, це коли певному ключу відповідає одне значення, а складний словник – ключу відповідає набір значення. Наприклад, якщо коду країни відповідає тільки назва цієї країни, то цей словник є простим, де ключем виступає код країни. Прикладом складного словника є словник матеріалів, де коду товару відповідає його назва, вартість, країна виробник, маса тощо.

Складні словники можуть бути складеними. Складеним словником називається такий, в якого одне із значень є елементом іншого словниками. Наприклад, дано складний словник країн, в якому певному коду відповідають назва та код типу країни (республіка, федерація, королівство тощо). Код типу країни вказує на словник типів країн, таким чином словник країни можна вважати складеним та залежним від словника типів країн.



Рис 1 – Різні типи словників.


Словники часто використовують при розробці програмного забезпечення, адже дають можливість групувати набори даних в окремі групи, використовувати їх в групах та асоціювати певне значення з групою. В предметної області певний набір даних може бути словником, якщо він не виступає центральним в даній предметній області. Словники повинні залишатися максимально спрощеним та піддававтися мінімальним змінам в процесі використання, в той час як центральні сутності предметної можуть бути дуже складними та змінювати часто.

Чим складніший словник, тим більше програмний продукт залежить від нього. Словники можуть з часом переростати на повноцінні набори даних. При цьому збільшується або їх складності або кількість даних.

Зі словників часто починається проектування та кодування програм, вони є об’єктом перевикористання. Якщо використовувати необхідні словники спроектовані та закодовані на попередніх проектах, то можна скоротити час на написання нових проектів. Розроблений словник може виступати незалежним компонентом, але подібні компоненти буває тяжко спроектувати, адже вони вимагають гнучкості в роботі, а також тісної залежності від них іншого коду.

Існує кілька способів зберігання даних словників: набори констант, енумерації, файли, база даних тощо. Використання констант та енумерації для зберігання елементів словника пожуть значно покращити процес кодувати та збільшити читабельність коду, але при цьому частіше всього ми втрачаємо можливість швидкої зміни «захардкодженого» набору даних. Звичайно, словник статей, може бути спокійно закодований у вигляді енумерації, але словник країн ні. Те, що словники змінюються рідко не значить, що вони ніколи не міняються. В окремих випадках є необхідність добавити нові елементи або виконати користування існуючих, і в залежності від типу програми, найкращими будуть тут зберігання словників у файлах та базах даних.

Ще однією хорошою практикою є змістовні ключі словників. Простіше працювати та підтримувати в роботі словники, що містять ключі, які легко зрозуміти та отримати інформацію про сам елемент словника. Цього тяжко досягнути якщо використовувати числові ідентифікатори. Наприклад, для словника типів кредитних карточок ключі VISA, MSTR, AMEX тощо зручніше використовувати, ніж, наприклад, 1, 2, 3. У випадку використання бази даних для зберігання словників також простіше писати запити.
Оскільки словники містять невеликі набори даних і в основному рідко змінюються, то вони частіше легко піддаються кешуванню. Але тут слід не забувати, що словники теж можуть міняти, тому програма повинна підтримувати або можливість обновити дані в кеші або виконати інвалідацію кеша або ж увімкнути підтримку дати закінчення терміни дії кешу, після якого нові дані будуть знов закешовані.

Для зберігання та використання словників можна також використовувати і інші способи. Наприклад, якщо використовується MySQL, то для роботи із таблицями з словниками можна використвувати MyISAM engine, адже він найкраще підходить для даних, що рідко змінуюються, але частіше зчитуються. Таблиці із словниками частіше піддаються повному кешуванню СУБД, а використання сладених індексів на всі колонки БД може взагалі позбавити необхідность у фізичному вводі-виводі. Збереження словників у базі даних та використання зовнішніх ключів покращує цілісність даних, і знову ж таки, не сильно впливає на ресурси для виконання запитів.

Spring MVC and RESTful web service.

This article is a result of my experience on building small RESTful web service using SpringMVC 2.5. Web service is simple, it supports only few operations, most of them just retrieves data and sends back it in XML.

Well, the task is simple enough:

  1. build secured web service for mostly getting and sometimes posting data;
  2. REST interface is required
    • but SOAP could be added later (I think that if you build SOAP web service you should wait that you'll need to provide REST API for this web service too and vise versa).

As web service is build with REST philosophy, than we need to support processing of GET, POST (well, for me it's enough) requests and return data as XML or JSON. Spring MVC as well others REST web service frameworks and API help with this too. So, what's next?

As application is build with Spring 2.5, it was the best to have some framework for building REST web service easily and easily to integrate it with Spring. Not a secret, that Spring MVC integrates with Spring better that any other web framework or REST web service framework (hm, maybe it's because it is build on Spring). Well, this is cons for using Spring MVC and it is good, but truly - this not enough yet.

Yet one requirement: SOAP web service could be added later. And if it could be added than (in most cases) it will be added. This is important, very important, because we want to build easy-to-extend software. And in case of SOAP WS I prefer to use Spring WS, that is well integrated with Spring MVC. Need also to take into consideration that some REST web service frameworks hardly integrates with Spring MVC or wanted to process all requests. That is a great pros for using Spring MVC.

You may understand what I'm implying. Yes, Spring MVC will be used to build RESTful web service.

Architecture


The main goals of architecture are:

  • be scalable (not to much, but enough to process thousands of requests per hour)
  • be extendable (SOAP must be easy to add)
  • do what is required and nothing more


Next decisions were made:

  • request should be stateless
  • each request should be processed as quick as possible
  • there will be 2 levels of caching: one cache for entities and queries (used by web service backend service), and another cache for rendered XML response (used by web service endpoint).
  • everything that could be changed is configured through simple XML configuration (i.e. cache configuration, security configuration, business logic configuration etc.)


The main result of made decisions & rules is request processing lifecycle, that consists of next few phases:

  1. Authentification & Authorization (security filter)
  2. Getting request parameters. Web service endpoint (in our case it is SpringMVC controller) parses request parameters and validates them.
  3. If everything is okay than it tries to get XML response from cache and sends it as response to the client. This step is optional and is processed only if cache is enabled and client does not specify request as such that ignores cache.
  4. Endpoint determines the appropriate WebService backend service and run it and get results.
  5. Endpoint converts results into XML, prepare response and stores it at cache (if cache is enabled). After the XML response is send back to client.




So, if the request response is cached in 2nd or 1st cache levels, than response will be generated without hitting database. In my development environment caching helps to increase performance up to 1500%. In production this number is less - just 300-500%. Still these is very well.

This lifecycle helps to build a scheme of responsibilities and modules. Later each responsibility could be processed by own server or a set of servers.



Simple implemenation


Spring 2.5 gave us possibility to use annotations as for declaring services as for declaring SpringMVC controllers. Spring's annotations Controller, RequestMapping, RequestParam and flexible politic on request handle method parameters gives us brilliant instrument for building web service endpoint.
Ofcourse, hardcoding of URLs in annotations looks as not the best way for building flexible and configurable application. But, this is quite pardonable, because we will use UrlRewriteFilter. UrlRewriteFilter is very useful tool, as it will helps to rewrite URLs, get parameters from URL and do other interesting things. But for our the most important are next 2 features:

  1. flexibility while mapping external URLs (used by users) to internal URLS (processed by endpoint controllers)
  2. possibility to catch parameters from URL, e.g. http://example.com/book/edit/12 ->
    http://exampl.com/book/edit?boodId=12 etc.


Lets look how we could use this features:
Let we have RESTful web service that returns XML with information with specified by id book. Web service clients could get this information by requesting url
http://ourservice.com/ws/rest/book/{bookId} (e.g. http://ourservice.com/ws/rest/book/12). Our application should handle this call and the information about book wit specified id.

Here is our web service controller:

@Controller
public class WebServiceEndpoint {

@Autowired
private BookService bookService;

@RequestMapping(value = "webservice/book", methods = RequestMethod.GET)
public ModelAndView getBook(@RequestParam(name="bookID", required=true)int bookId, Map<String, Object> model) {
model.put("book", bookService.getBookById(bookId));
return new ModelAndView("template/ws/bookInfo", model);
}
}

Code is very simple, but it's good as for sample.

So, we have controller that processes all GET requests for 'webservice/book' resource, that should have request parameter of type integer with name 'bookID'. Endpoint just call backend service, gets information about book, put it to model map and return the ModelAndView instance with simple template that will be rendered and returned to client.

This endpoint controller can't be default process web service request. To redirect web service client request to our endpoint we will use UrlRewriteFilter

<rule>
<from>^/ws/rest/book/[0-9]+$</from>
<to>/webservice/book?bookID=$1</to>
</rule>


so request for resource http://ourservice.com/ws/rest/book/12 will be rewrited by filter to http://ourservice.com/webservice/book?bookID=12.


That's about all for now. The story looks to long. Most of us do not have enough time to read long articles :)