Cluster system architecture? - java

I would like to develop application for ~500 active users (sessions at one time). System would not process any massive calculations. It will be simple read/write to database solution. However, to application would be uploaded about 50mb of data daily per user. (it would be analysed and clean by other application every day when non users will be active). Actually I'm working on design of this application and I've got few questions about that.
Should I consider developing application working in some cluster with load balance or one server will handle this amount of usage?
If yes, is there any guidelines about developing application to work in cluster? Is there any difference than developing single server application?
Should I be worried about database of this application? What problems should I expect when 2 servers will read/write data to single database at same time? Maybe it also should work in cluster?
I would be pleased for any help and/or articles about design this mid size applications.

This depends on you NFR (non functional requirements). Next to load balancing, a cluster provides higher availability.
You'll have to make your back-end state-less so that requests from the same user can end up on another node without the user noticing. This makes it more expensive to build scaling software. So consider your options carefully.
Accessing a database from multiple servers is not different than accessing it from multiple threads.

To answer your first question, I think using an infrastructure provider that lets you easily scale (up or down) your application is always a big plus and can help you save money. My main experience with this kind of providers is with Amazon Web Services (AWS).
I don't know precisely what technology you are planning to use, but a general setup like that on AWS would make sense to me is:
A set of EC2 instances (= virtual servers) running behind an ELB (a load balancer)
An auto scaling group containing the EC2 instances. You can look it up, but an auto scaling group basically lets you automatically add and remove instances depending on various factors (server load, disk I/O, etc.)
The use of RDS for your database. It supports multiple DBMS such as MySQL and Oracle. It also provides you with nice features such as replication, automated backups and monitoring.
The use of CodeDeploy to deploy your application on the servers
(I'm voluntarly using the AWS names so that you can read the documentation if you are interested.)
This would basically let you scale to a lot more than 500 concurrent users if needed, and could save you some money when you are handling less users. Note that auto scaling groups can also be scheduled. For instance : « I want at least 5 instances during the day (max 50), but you can go down to 2 (and still up to 50) between 1am and 4am »
The services I mentionned are quite widely documented, so you can look it up if you'd like some more specific details.
I won't discuss in detail your two other questions because I'm not an expert on the subject, but the database can indeed be a bottleneck since it may involve a lot of I/Os.
Hope this helps :)

Related

AWS instance access error : The server requested closed the connection before the transaction

I have couple of questions bothering me and would like some help here of all the awesome experienced people over here.
1) I am facing this specific issue whenever I access phpMyAdmin hosted on AWS ec2 t2.medium instance (not frequently though but I feel the android app which accesses REST API to upload file to ec2 server fails to upload file and I think it's causing because of the below network drop maybe, not sure as I am new to AWS):
The server requested closed the connection before the transaction
My AWS instance is running:
UBUNTU
APACHE server
Laravel 5.3 for backend and REST API
1 instance of ec2 t2.medium server
2 EBS volumes of i) 10 GB and ii) 20 GB
no loadbalancer is being used as of now
2) I am new to using AWS and have successfully deployed my Laravel based backend on AWS and my android app access the REST API hosted on same ec2 t2.medium instance. Now what bothers me is, I am not sure how it will be auto scalable? because the app is downloaded by more than 7000 users+ when we run our marketing campaign which has been stopped now because many users face issue while uploading the media file to the server, after certain %ge the file stops to upload file and rest users are able to upload file.
The android app does everything good but most people face issue when they try to upload the file to a REST API url coded in Laravel hosted on AWS ec2 t2.medium instance and I am using the below android library to upload file to my server through my backend's file upload API :
https://github.com/gotev/android-upload-service
The file upload laravel API i've constructed is like this:
public function uploadFile(Request $request, userSubmitData $udb)
{
$creds = $request->all();
$idFromDB = $udb::where('token', $creds['token'])->value('token');
$uid = $udb::where('token', $creds['token'])->value('user_id');
$hasFile = "false";
$file = $request->file('myFile');
$extension = $file->getClientOriginalExtension();
$fileName = $file->getClientOriginalName();
$fileName = $uid."_".$fileName;
Storage::disk('local')->put($fileName, File::get($file));
$udb->where('token', $creds['token'])->update(['fileHandle' => $fileName, 'mime' => $file->getClientMimeType(), 'original_filename' => $file->getClientOriginalName(), 'approved' => NULL, 'rejected' => NULL]);
$hasFile="1";
return Response($hasFile, 200);
}
Please give me your insight in to building scalable technology and setting up AWS efficiently as fault tolerant, highly scalable and highly availbale architecture and technology.
Thank You.
PS: I am not a great coder or anything, just a novice architect who loves coding and building beautiful things, there are far great and amazing people than me out there haha. So never mind the way I am executing things here I am just in process of making things work right way thats all and make it work beautifully :)
I have two options I can propose to you, both will give you the scalability you need as well as the fault tolerance you require. It's a bit wordy but I implore you to read your way through and feel free to ask follow up questions! :)
Option one - Route53, ELBs, ASGs and redundancy.
For this solution you will need to make use of Route53 health checks, an Elastic Load Balancer and an Auto Scaling Group.
The Stack:
[Route53 DNS]
[Elastic Load Balancer]
[Auto Scaling Group]
[Application Instances]
Route53 will provide your DNS needs to the load balancer, however it can also give you some very nice health checks and auto fail-over capability. Depending on your own acceptable level of fault tolerance in your High Availability Strategy, you can use this health check to evaluate the overall health of it's target (in this case the ELB) and fail over DNS to an alternate stack that you have at all time running and standing by. This could be expensive but it depends on your business case.
The Elastic Load Balancer will target instances in your Auto Scaling Group, you should configure your Auto Scaling Group to make use of at least 2 Availability Zones. This means if an AZ fails your application remains available to your clients. It's extremely unusual for more than one AZ to fail at the same time, but it could happen. It's also important to be aware that when an AZ fails the remaining AZs will become oversubscribed very quickly. This means that if you are using 2 AZs and one of them fails, that means that your application will be running at 50% diminished capacity and due to everyone running from the failing AZ to the remaining ones, chances are your Auto Scaling Group will struggle to automatically provision additional instances in that AZ. So if your applications high availability is as paramount as your ability to serve your customers at premium quality it means based on a scenario where you are using 2 AZs you would need to provision 100% of your BAU capacity in each AZ. You can reduce this to a smaller percentage if you wish to gamble on the possibility that you will be able to provision some replacement instances in your remaining AZ if one of your AZs fails. Alternatively you can make use of another AZ (total of 3+).
I could talk for days about this, but moving on...
Lastly are your Application Instances. You need to create a script that will take them from the Ubuntu AMI of your choice right through to production ready. The Auto Scaling Group will start new instances with this script in the Instance's UserData metadata and the Instance will consume this to become ready. Without this script you would have to manually setup and configure every instance that your Auto Scaling Group creates, this isn't ideal.
Important: Just in case, if you application cannot scale because of session states in memory then you have a problem you need to remedy. There are a few ways to do this but the Amazon way is to make use of ElastiCache for session storage. Might be a little work but it will make your solution far more resilient.
This will create a Highly Available solution for your application but is reliant on you making some business decisions on cost vs HA.
Option 2 - A True Cloud and AWS approach, Serverless.
From the above you can quickly see just how expensive it can be to take an application, place it in the cloud and maintain a high level of HA and QOS. However there is a better, cheaper and less maintenance approach available to you at the cost of initial redevelopment of some parts of your application - A Serverless Design.
For this you would effectively do away with your application servers and make use of the following products:
AWS Lambda
AWS DynamoDB or Amazon RDS (depending on your need, however I'd shoot for DynamoDB if you can.)
Amazon API Gateway
Replacing your application logic and dependency on instance with Lambda will see you be able to execute your code without having to be concerned about AZs, ELBs, ASGs, Redundancy and over subscription upon failure. Lambda is extremely cost competitive and I dare to say will not even be a fraction of the cost of running instance applications with all the HA configurations etc.
Using API Gateway you can expose your Lambda functions to your users in a manageable, highly available way with very little effort and cost compared to the option above.
DynamoDB is the NoSQL offering by AWS. Its HA, fast and easily tailored by yourself to be as resourced as you need it to be. An alternative is Amazon RDS which will give you a more traditional SQL experience but at the end of the day you are still paying for instances in a cluster plus a small fee for the management.
I will summarize by saying, Option 2 is where you should be aiming however given you already have a product that is written and servicing clients you should go ahead with Option 1 for now and obtain that HA and scalable confidence and then project Option 2 for later.
Here is some additional reading on all the topics I have discussed, but feel free to ask more questions if you need.
Option 1 Documentation
Route53 Health Checks and Fail-over
http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover.html
Elastic Load Balancer
https://aws.amazon.com/documentation/elastic-load-balancing/
Auto Scaling Groups (please also checkout Launch Configurations)
https://aws.amazon.com/autoscaling/
http://docs.aws.amazon.com/autoscaling/latest/userguide/LaunchConfiguration.html
AWS ElastiCache
https://aws.amazon.com/documentation/elasticache/
Option 2 Documentation
Amazon API Gateway
https://aws.amazon.com/api-gateway/
AWS Lambda
https://aws.amazon.com/documentation/lambda/
AWS DynamoDB
https://aws.amazon.com/documentation/dynamodb/
Amazon RDS
https://aws.amazon.com/documentation/rds/
Cheers,
Xavier

Single Java Cache for multiple Application Server

We got multiple Application Server behind a Reverse Proxy. We want a single cache on another host which all Application Servers can easily use, thus the cache has to have some kind of network support. Furthermore the setup should be easy probably supporting docker, but this is not a must. The cache duration is about 1d. The API should be as easy and standardized as possible (JCache?).
In a later stage we want to prepolutate the Cache.
Which options do I have?
Background: In a first step we want to reduce load on the backend systems, which provides mainly SOAP Services. So we want to cache the SOAP response (JAX-WS). The cache hit rate will be probably about 25% in a first stage.
Later we want to use the same cache for JPA as well (we already have in memory caching enabled for each Application Servcer and use a Cache Coordination strategy).
To use even more caching we will need some sort cache categories.
In general: The question is to broad and actually you are asking for a product recommendation. Please take a look at the stackoverflow question guidelines.
About your question:
There is no "single cache" for any purpose. Furthermore, there can be many variants in software and system architecture, with a single cache product, too. The best solution depends not on the application but on the type of data access you want to cache. Some questions that come to my mind:
Do you have a mostly read or a read/write usage pattern?
What is the type of access, point, range, or a full scan? What type of operations you do on the data? What is the object count and typical object size? Are there hot spots? How many application servers you have? Is there a memory limit in the application servers? How costly is it to generate the data in the backend (latency and resource costs)?
One general recommendation: If you only have a few application servers, I would start with local caching in the application servers and ignore the fact that there may be redundant requests on the backend from different application servers. This way you can keep the existing system architecture. Putting in a separate cache server or servers needs a lot of planing and a lot considerations for staging, deployment and operation your application.
One second general recommendation: The cache hit rate will be probably about 25% in a first stage A cache with this hitrate will be pretty useless. It may happen that you don't get any performance gain from the cache at all. There may be reasons to do it anyway, e.g. to improve the application for flash crowds. This needs some more detailed elaboration. Double check you numbers!
I am looking forward for more detailed questions :)
What about using the cache server from Ehcache ?
It provides a RESTful interface and can run on a dedicated server.

Oracle JDBC Tutorial - Want to understand 2 tier JDBC vs 3 tier

I am reading the oracle JDBC tutorial here - http://docs.oracle.com/javase/tutorial/jdbc/overview/index.html
Please refer to Figure 2: Three-tier Architecture for Data Access.
It says that -
In the three-tier model, commands are sent to a "middle tier" of services, which then sends the commands to the data source. The data source processes the commands and sends the results back to the middle tier, which then sends them to the user. MIS directors find the three-tier model very attractive because the middle tier makes it possible to maintain control over access and the kinds of updates that can be made to corporate data. Another advantage is that it simplifies the deployment of applications. Finally, in many cases, the three-tier architecture can provide performance advantages.
I don't understand the bold parts. What is the logic behind those points ?
- middle tier makes it possible to maintain control over access and the kinds of updates that can be made to corporate data.
--In what ways ?
- simplifies the deployment of applications
-- How does that simplify deployment ?
- three-tier architecture can provide performance advantages.
-- You just added a layer between two tiered arch. Now, instead of direct communication between code and DB there is a middle layer. So, should'nt that reduce your performance/speed ?
middle tier makes it possible to maintain control over access and the kinds of updates that can be made to corporate data. --In what
ways ?
Consider these roles:
Workers can add low level data but can't add other workers.
Managers can add/update low level data but can't see the high level stats.
Executives can't update low level data, can't add workers but can see the high level stats.
The same can be in the world of components: loggers are write-only, some components can't access data of the other components, etc.
simplifies the deployment of applications -- How does that simplify deployment ?
Each layer provides an interface to its clients. If you change the internal implementation of the layer not touching its interface, the update can be completed seamlessly for the clients.
three-tier architecture can provide performance advantages. -- You just added a layer between two tiered arch. Now, instead of direct
communication between code and DB there is a middle layer. So,
should'nt that reduce your performance/speed ?
There are two ways to improve performance: vertical and horizontal scalability (google it). Here we talk about the horizontal one, it's hardly possible with two layered architecture.
Consider few examples of "Middle Tier" in Java, Web Servers like Tomcat, Enterprise Servers like JBoss, BEA Weblogic, IBM Websphere. There could be many other examples as well which falls under middle tier category.
Most of the enterprise servers provide full management functionality for database. Which handles in broad-way following requirements:
Configuration (Connection pool, XA, JDBC specific properties, ReadOnly/WriteEnabled, etc)
Deployments
Maintenance tasks (backup etc)
Monitoring (Database performance stats, its machine performance stats, size stats etc)
As a specific example in Tomcat or a standalone Java application where you configure connection-pool will help in performance gain.
Deployment wise specific example could be, it would provide ways to configure new database, schema etc.
I think it would help you if you say pick one Middle Tier say Tomcat and configure/use it for typical standard database interactions using connection-pools etc. Then you would be able to comprehend comparisons between two-tier vs three-tier arch.

GAE/GWT server side data inconsistent / not persisting between instances

I'm writing a game app on GAE with GWT/Java and am having a issues with server-side persistent data.
Players are polling using RPC for active games and game states, all being stores on the server. Sometimes client polling fails to find game instances that I know should exist. This only happens when I deploy to google appspot, locally everything is fine.
I understand this could be to do with how appspot is a clouded service and that it can spawn and use a new instance of my servlet at any point, and the existing data is not persisting between instances.
Single games only last a minute or two and data will change rapidly, (multiple times a second) so what is the best way to ensure that RPC calls to different instances will use the same server-side data?
I have had a look at the DataStore API and it seems to be database like storage which i'm guessing will be way too slow for what I need. Also Memcache can be flushed at any point so that's not useful.
What am I missing here?
You have two issues here: persisting data between requests and polling data from clients.
When you have a distributed servlet environment (such as GAE) you can not make request to one instance, save data to memory and expect that data is available on other instances. This is true for GAE and any other servlet environment where you have multiple servers.
So to you need to save data to some shared storage: Datastore is costly, persistent, reliable and slow. Memcache is fast, free, but non-reliable. Usually we use a combination of both. Some libraries even transparently combine both: NDB, objectify.
On GAE there is also a third option to have semi-persisted shared data: backends. Those are always-on instances, where you control startup/shutdown.
Data polling: if you have multiple clients waiting for updates, it's best not to use polling. Polling will make a lot of unnecessary requests (data did not change on server) and there will still be a minimum delay (since you poll at some interval). Instead of polling you use push via Channel API. There are even GWT libs for it: gwt-gae-channel, gwt-channel-api.
Short answer: You did not design your game to run on App Engine.
You sound like you've already answered your own question. You understand that data is not persisted across instances. The two mechanisms for persisting data on the server side are memcache and the datastore, but you also understand the limitations of these. You need to architect your game around this.
If you're not using memcache or the datastore, how are you persisting your data (my best guess is that you aren't actually persisting it). From the vague details, you have not architected your game to be able to run across multiple instances, which is essential for any app running on App Engine. It's a basic design principle that you don't know which instance any HTTP request will hit. You have to rearchitect to use the datastore + memcache.
If you want to use a single server, you can use backends, which behave like single servers that stick around (if you limit it to one instance). Frankly though, because of the cost, you're better off with Amazon or Rackspace if you go this route. You will also have to deal with scaling on your own - ie if a game is running on a particular server instance, you need to build a way such that playing the game consistently hits that instance.
Remember you can deploy GWT applications without GAE, see this explanation:
https://developers.google.com/web-toolkit/doc/latest/DevGuideServerCommunication#DevGuideRPCDeployment
You may want to ask yourself: Will your application ever NEED multiple server instances or GAE-specific features?
If so, then I agree with Peter Knego's reply regarding memcache etc.
If not, then you might be able to work around your problem by choosing a different hosting option (other than GAE). Particularly one that lets you work with just a single instance. You could then indeed simply manage all your game data in server memory, like I understand you have been doing so far.
If this solution suits your purpose, then all you need to do is find a suitable hosting provider. This may well be a cloud-based PaaS offer, provided that they let you put a hard limit (unlike with GAE) on the number of server instances, and that it goes as low as one. For example, Heroku (currently) lets you do that, as far as I understand, and apparently it's suitable for GWT applications, according to this thread:
https://stackoverflow.com/a/8583493/2237986
Note that the above solution involves a bit of fiddling and I don't know your needs well enough to make a strong recommendation. There may be easier and better solutions for what you're trying to do. In particular, have a look at non-cloud-based hosting options and server architectures that are optimized for highly time-critical, real-time multiplayer gaming.
Hope this helps! Keep us posted on your progress.

Loading facebook's big text file to memory (39MB) for autocompletion

I'm trying to implement part of the facebook ads api, the auto complete function ads.getAutoCompleteData
Basically, Facebook supplies this 39MB file which updated weekly, and which contains targeting ads data including colleges, college majors, workplaces, locales, countries, regions and cities.
Our application needs to access all of those objects and supply auto completion using this file's data.
I'm thinking of preferred ways to solved this. I was thinking about one of the following options:
Loading it to memory using Trie (Patricia-trie), the disadvantage of course that it will take too much memory on the server.
Using a dedicated search platform such as Solr on a different machine, the disadvantage is perhaps over-engineering (Though the file size will probably increase largely in the future).
(Fill here cool, easy and speed of light option) ?
Well, what do you think?
I would stick with a service oriented architecture (especially if the product is supposed to handle high volumes) and go with Solr. That being said, 39 MB is not a lot of hold in memory if it's going to be a singleton. With indexes and all this will get up to what? 400MB? This of course depends on what your product does and what kind of hardware you wish to run it on.
I would go with Solr or write your own service that reads the file into a fast DB like MySQL's MyISAM table (or even in-memory table) and use mysql's text search feature to serve up results. Barring that I would try to use Solr as a service.
The benefit of writing my own service is that I know what is going on, the down side is that it'll be no where as powerful as Solr. However I suspect writing my own service will take less time to implement.
Consider writing your own service that serves up request in a async manner (if your product is a website then using ajax). The trouble with Solr or Lucene is that if you get stuck, there is not a lot of help out there.
Just my 2 cents.

Categories

Resources