<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3426163161769571834</id><updated>2024-09-14T02:49:45.819-07:00</updated><category term="essay"/><category term="hacks"/><category term="announce"/><category term="devops"/><category term="vocanic"/><category term="reviews"/><category term="aws"/><category term="events"/><category term="php"/><category term="android"/><category term="mysql"/><category term="redis"/><category term="Kindle"/><category term="PDF"/><category term="big-data"/><category term="ci"/><category term="compress"/><category term="computers"/><category term="hack"/><category term="hudson"/><category term="logging"/><category term="performance"/><category term="phing"/><category term="queues"/><category term="scripts"/><category term="sns"/><category term="sqs"/><category term="testing"/><category term="tribute"/><category term="ubuntu"/><title type='text'>Shreeni&#39;s Tech Log</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tech.shreeni.info/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default?start-index=26&amp;max-results=25'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>78</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-8064124283768842690</id><published>2016-02-09T23:53:00.000-08:00</published><updated>2016-02-09T23:53:11.043-08:00</updated><title type='text'>Too much security</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;tr_bq&quot;&gt;
This happened today and this email was sent to Sharekhan. There are still engineers whose reaction to security threats is to make the product unusable.&lt;/div&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;Hi,&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;I keep receiving &quot;Digital Transaction Cum DP Billing Statement&quot; statements every now and then. These are in the form of PDF attachments with a password protection. I cannot Print them, I cannot Export them to a password less PDF. What is the point of this statement? How does any of your users use it?&amp;nbsp;&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;I understand the need for having a read-password protection because email is unsafe. But why restrict the files from being printed AFTER they have been opened with a password? Or why not let me export them to non-password PDF AFTER I have applied the passwords?&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;I have not seen a more singularly useless statement in my life.&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;Please forward this to your tech team and tell them that their paranoia is leading to completely useless reports. They might as well not send these reports to anybody, because hey, that would be even more safe!!&amp;nbsp;&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;Yours Sarcastically,&lt;br /&gt;Shreeniwas&lt;/i&gt;&lt;/blockquote&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/8064124283768842690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2016/02/too-much-security.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/8064124283768842690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/8064124283768842690'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2016/02/too-much-security.html' title='Too much security'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-3427643813934218755</id><published>2016-02-03T06:02:00.002-08:00</published><updated>2016-02-03T06:05:00.064-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Code as a bottleneck</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
When we talk about software performance, or performance bottlenecks, the general culprit is assumed to be big characters in the setup - the OS, the programming language, the storage (SQL/NoSQL) or then the web/app server.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.int13.net/france/samsung/06/03_java_slow.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.int13.net/france/samsung/06/03_java_slow.jpg&quot; height=&quot;150&quot; style=&quot;-webkit-user-select: none;&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;When I used to build systems in Java, first and foremost comment I used to hear from non-Java developers was that Java is slow.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I am sure people of certain age (30 and above, I believe) were also caught up in arguments over Windows vs Unix vs Linux. Thankfully, much of that died off, what with Linux becoming the overwhelming OS favourite for servers.&lt;br /&gt;
&lt;br /&gt;
Almost every programmer who hears about us (still) using SQL sneers at the fact that I am from the dinosaur era, heading for a well deserved extinction.&lt;br /&gt;
&lt;br /&gt;
And yet, few people realise that the biggest culprit in most practical software setups is hardly either one of the above, it is generally the code (or the engineer) itself that can make or break performance.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://cerinman.github.io/images/nosqlfunny.png&quot; style=&quot;-webkit-user-select: none;&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Let me put that in perspective. If you are engineering a new feature for Amazon, then thinking about the choice of performant stack from day one makes absolute sense. Their engineers are so well versed with high performance patterns, tools and tricks that the choice of an OS or language or storage will make a real difference.&lt;br /&gt;
&lt;br /&gt;
But if you are working anywhere else, most code will not hit the level of scale (read audience of 10s of millions operations per day). You probably work for a company that aspires to get there, but isn&#39;t yet there. Or you are happy working for a company that does work under that scale, simply because of the nature of audience or business or the software in question.&lt;br /&gt;
&lt;br /&gt;
In such cases, performance issues still crop up, more often than you imagine, and that&#39;s all attributable to well meaning engineers, and well meaning code.&lt;br /&gt;
&lt;br /&gt;
I will give you an example I say today at work.&lt;br /&gt;
&lt;br /&gt;
We have a module that does something like this:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Scan an S3 folder for new files.&lt;/li&gt;
&lt;li&gt;For each new file:&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;Read the contents&lt;/li&gt;
&lt;li&gt;JSON-decode it&lt;/li&gt;
&lt;li&gt;Read every record, and either write or update the data store (NoSQL)&lt;/li&gt;
&lt;li&gt;Move the file after processing&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;ol&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;
Now, this script was processing about 20 files a minute, and due to unrelated issues, built up a backlog of 90,000 files. If nothing was done, this would have taken 3 days to get done, and that would have been unacceptable.&lt;br /&gt;
&lt;br /&gt;
So, I sat down with the engineer and started poring over the code to see what we could. I spotted three issues and gave 3 recommendations:&lt;br /&gt;
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;http://www.changeandachieve.com/wp-content/uploads/2015/12/Backlogs.gif&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.changeandachieve.com/wp-content/uploads/2015/12/Backlogs.gif&quot; style=&quot;-webkit-user-select: none;&quot; /&gt;&lt;/a&gt;
&lt;li&gt;In step 2, for each file, we were spawning a PHP process to process the file. From experience I know that spawning processes is very heavy, so I just brought the code that processed the file into that loop and did away with the spawning.&lt;/li&gt;
&lt;li&gt;In step 2.1, we were moving the S3 file to a local temporary file and then opening to read them. I modified that code to read directly from S3.&lt;/li&gt;
&lt;li&gt;In step 2.3, we were reading 10 records from the store and updating them in a batch of 10. I changed the batch size of 100.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
These changes alone got us to processing about 2000 files a minute. 100x improvement for 3 relatively minor changes to a script.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
No OS, language, store or server had to change.&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/3427643813934218755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2016/02/code-as-bottleneck.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/3427643813934218755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/3427643813934218755'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2016/02/code-as-bottleneck.html' title='Code as a bottleneck'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-2555434503468275327</id><published>2016-02-02T06:06:00.000-08:00</published><updated>2016-02-02T06:06:34.763-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Micro Releases</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/proxy/AVvXsEgh65-YJcXbAo-czHCCIAFiGVzNbMH7ee2EoU3FnQb8n6NiSU3fLq9XmoBlr3_3GeKPZhZiXYBriKA_OcvgzdvuqIQ_X804PgooINRsz9pOH27d44RPeSXEdgEid8I3iydX07UDImXDGnYyMaAErujBojsgOZ0iSvTxHnEg4_um7ZQ3sRYRjM0FJ2LWeXDyevlkhw&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.visualstudiogeeks.com/assets/img/blog/tarun/post08_DevOpsFunnyImage.jpg&quot; height=&quot;149&quot; style=&quot;-webkit-user-select: none;&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Releases are painful. You are worried about everything you coded working out correctly. The whole idea of Sprints, and Continuous Integration, is to make sure that you release reasonably small updates, where the gap between design and accident is somewhat minimal. Obviously, the more you lump into a release, the more there are moving parts, the more you could get something wrong during integration or release.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/proxy/AVvXsEh0KS4BfccqnN1ZLhRVGLm7ITs0w1BC9iPtbaGDNW7YPPvcsI0X4BHZMwE2_czlWN-LygBx0zLkufIlszQ5fDgEKNBdpJgtOH39phF61SaFPUZBDkTeMtnGRFbgwMJYhS122x-EAJqgAUIWPKUsOlw6ugwdYnBHnaKCkpKONbA5DwjD1F-sHIxbQi1zRbcSV9hi-0DIsaTPcHy_tFQ8Xw&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/proxy/AVvXsEh0KS4BfccqnN1ZLhRVGLm7ITs0w1BC9iPtbaGDNW7YPPvcsI0X4BHZMwE2_czlWN-LygBx0zLkufIlszQ5fDgEKNBdpJgtOH39phF61SaFPUZBDkTeMtnGRFbgwMJYhS122x-EAJqgAUIWPKUsOlw6ugwdYnBHnaKCkpKONbA5DwjD1F-sHIxbQi1zRbcSV9hi-0DIsaTPcHy_tFQ8Xw&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;At Vocanic, we were doing 2 week releases for our primary product VSocial. Which seemed to be going along just fine. I came back to writing code for that product a few weeks back, and I realised, to my horror, that even with a small, nimble team, end-of-sprint releases were still taking too much time and too many integration issues were sprouting up. In a typical 2 weeks cycle, you would end up touching a bit of frontend, a bit of backend, a bit of config and a bit of your storage structure, and all put together was ending up becoming too much.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/proxy/AVvXsEh0KS4BfccqnN1ZLhRVGLm7ITs0w1BC9iPtbaGDNW7YPPvcsI0X4BHZMwE2_czlWN-LygBx0zLkufIlszQ5fDgEKNBdpJgtOH39phF61SaFPUZBDkTeMtnGRFbgwMJYhS122x-EAJqgAUIWPKUsOlw6ugwdYnBHnaKCkpKONbA5DwjD1F-sHIxbQi1zRbcSV9hi-0DIsaTPcHy_tFQ8Xw&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://25.media.tumblr.com/c9bae030a8999588d1f57d70103816d7/tumblr_n22z4mJvrj1tq4of6o1_500.gif&quot; height=&quot;110&quot; style=&quot;-webkit-user-select: none;&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
So, we just decided to take continuous integration to the next level. We decided to release stuff as soon as a cogent, related task was ready to be released. We needed to do a few changes to our setup to enable us to do this. Most important, we needed a live beta environment, one where we could run the new version of our software on live data, on live set up, on live config, without affecting the stable version.&lt;br /&gt;
&lt;br /&gt;
With a little bit of domain restructuring, we now have something similar to&amp;nbsp;https://beta.facebook.com/ - a live version of Facebook&#39;s upcoming version, for our product.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://sd.keepcalm-o-matic.co.uk/i/keep-calm-and-love-beta-13.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;http://sd.keepcalm-o-matic.co.uk/i/keep-calm-and-love-beta-13.png&quot; style=&quot;-webkit-user-select: none;&quot; width=&quot;171&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
And that was just enough. We are now able to release as soon as we want, sometimes as&amp;nbsp;many as 4 dot-releases per day. On slow moving weeks, it could be one release in 2 days. Since we have started this, we have gone through 21 micro-releases**.&lt;br /&gt;
&lt;br /&gt;
And it has been strangely liberating. Everyone knows that if they can code, test and make sure everything is working, they can get it out to live users before EOD. Partly it is hugely satisfying to complete the task the same day. And of course, needless to say, &lt;a href=&quot;https://en.wikipedia.org/wiki/Release_early,_release_often&quot; target=&quot;_blank&quot;&gt;release early and release often&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span id=&quot;note&quot;&gt;
[**I am led to believe that what we are doing is called &#39;&lt;a href=&quot;https://en.wikipedia.org/wiki/Extreme_programming&quot; target=&quot;_blank&quot;&gt;Extreme Programming&lt;/a&gt;&#39;. Since I have heard multiple interpretations of XP, if what we are doing fits your interpretation of XP, suit yourself. I will stick to calling them micro-releases.]
&lt;/span&gt;
&lt;/div&gt;




&lt;!-- Blogger automated replacement: &quot;https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F25.media.tumblr.com%2Fc9bae030a8999588d1f57d70103816d7%2Ftumblr_n22z4mJvrj1tq4of6o1_500.gif&amp;amp;container=blogger&amp;amp;gadget=a&amp;amp;rewriteMime=image%2F*&quot; with &quot;https://blogger.googleusercontent.com/img/proxy/AVvXsEh0KS4BfccqnN1ZLhRVGLm7ITs0w1BC9iPtbaGDNW7YPPvcsI0X4BHZMwE2_czlWN-LygBx0zLkufIlszQ5fDgEKNBdpJgtOH39phF61SaFPUZBDkTeMtnGRFbgwMJYhS122x-EAJqgAUIWPKUsOlw6ugwdYnBHnaKCkpKONbA5DwjD1F-sHIxbQi1zRbcSV9hi-0DIsaTPcHy_tFQ8Xw&quot; --&gt;&lt;!-- Blogger automated replacement: &quot;https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2Fwww.visualstudiogeeks.com%2Fassets%2Fimg%2Fblog%2Ftarun%2Fpost08_DevOpsFunnyImage.jpg&amp;amp;container=blogger&amp;amp;gadget=a&amp;amp;rewriteMime=image%2F*&quot; with &quot;https://blogger.googleusercontent.com/img/proxy/AVvXsEgh65-YJcXbAo-czHCCIAFiGVzNbMH7ee2EoU3FnQb8n6NiSU3fLq9XmoBlr3_3GeKPZhZiXYBriKA_OcvgzdvuqIQ_X804PgooINRsz9pOH27d44RPeSXEdgEid8I3iydX07UDImXDGnYyMaAErujBojsgOZ0iSvTxHnEg4_um7ZQ3sRYRjM0FJ2LWeXDyevlkhw&quot; --&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/2555434503468275327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2016/02/micro-releases.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/2555434503468275327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/2555434503468275327'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2016/02/micro-releases.html' title='Micro Releases'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-5626932650103260731</id><published>2014-04-14T19:58:00.004-07:00</published><updated>2014-04-14T19:58:55.308-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="mysql"/><category scheme="http://www.blogger.com/atom/ns#" term="php"/><category scheme="http://www.blogger.com/atom/ns#" term="redis"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Redis as a Session Store</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;(Cross posting from&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: Helvetica Neue Light, HelveticaNeue-Light, Helvetica Neue, Helvetica, Arial, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;&lt;a href=&quot;http://tech.vocanic.com/2014/04/switch-your-sessions-to-redis-without.html&quot;&gt;http://tech.vocanic.com/2014/04/switch-your-sessions-to-redis-without.html&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;By default&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://www.php.net/manual/en/intro.session.php&quot; style=&quot;-webkit-transition: color 0.3s; background-color: white; color: #009eb8; display: inline; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;PHP&#39;s session management&lt;/a&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;&amp;nbsp;is to store them in temporary files on the file system. This doesn&#39;t scale up if you are developing a web application to run on multiple machines. You could set up your load balancer to have&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/US_StickySessions.html&quot; style=&quot;-webkit-transition: color 0.3s; background-color: white; color: #009eb8; display: inline; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;sticky sessions&lt;/a&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;- where a session is associated to a machine - but the major drawback here is to have sessions become &quot;bad&quot; when that machine is out of rotation - primarily due to an error.&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;The typical solution, then, is to&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/sprain/PHP-MySQL-Session-Handler/blob/master/SessionHandler.php&quot; style=&quot;-webkit-transition: color 0.3s; background-color: white; color: #009eb8; display: inline; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;store the PHP sessions in Database&lt;/a&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;, or some such store. We, at Vocanic, started off by storing the sessions in MySQL, but then as our traffic went up, scaling that instance of MySQL became a headache and so we replaced it with a MySQL+Memcache solution, which was good enough for quite a while.&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;Recently, we saw a bigger problem - MySQL tends to be blocking if you are doing edits, and if the MySQL instance is shared between Sessions and any other data, then any major edit operation on the other databases also slows down the Sessions code and eventually blocks all the users out - since Sessions is the first module that needs to be loaded up for all of this to work.&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;So, we wanted to a non-blocking, fast, scalable store for our session management. These days, I am personally going through a Redis-Admiration phase and hence I decided to migrate this code to use Redis.&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; margin-left: auto; margin-right: auto; padding: 4px; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://rethinkdb.com/assets/images/antirez-redis.jpg&quot; imageanchor=&quot;1&quot; style=&quot;-webkit-transition: color 0.3s; color: #009eb8; display: inline; margin-bottom: 0px !important; margin-left: auto; margin-right: auto; margin-top: 0px !important; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;257&quot; src=&quot;http://rethinkdb.com/assets/images/antirez-redis.jpg&quot; style=&quot;-webkit-border-image: url(data:image/png; border-image-repeat: stretch; border-image-slice: 9; border-image-source: url(data:image/png; border-image-width: 9px; border: 9px none; box-sizing: border-box; display: inline-block; height: auto; margin: 10px auto; max-width: 100%; padding: 8px; position: relative;&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 11px;&quot;&gt;(Src:&amp;nbsp;http://rethinkdb.com/blog/thanks-redis/)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;The pseudo code for this is something like this:&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;class RedisSessionHandler implements SessionHandlerInterface {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;public function open($save_path, $name) {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;// Set up your Redis Connection&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;public function close() {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;&amp;nbsp;/* */&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;return true;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;public function read($id) {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;// GET &#39;$id&#39; &amp;nbsp;// unserialize and return&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;public function write($id, $data) {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;$wrapper = new stdClass();&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;$wrapper-&amp;gt;id = $id;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;$wrapper-&amp;gt;access = time();&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;$wrapper-&amp;gt;data = $data;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;// SET &#39;$id&#39; serialize($wrapper);&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;// ZADD &#39;ALL_SESSIONS&#39; $wrapper-&amp;gt;access, $id&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;public function destroy($id) {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;// DEL &#39;$id&#39;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;// ZREM &#39;ALL_SESSIONS&#39; $id&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;public function gc($maxlifetime) {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;$old = time() - $maxlifetime;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;// $keys = ZRANGEBYSCORE &#39;ALL_SESSIONS&#39;, 0, &#39;($old&#39;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;foreach($keys as $id) {&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;   &lt;/span&gt;$this-&amp;gt;destroy($id);&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;}&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;$sessionDataHandler = new RedisSessionHandler();&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;session_set_save_handler($sessionDataHandler, true);&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;// Send any headers you want to&amp;nbsp;&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;// Rest of the code&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;While this will just work for a new application, we wanted to ensure that your current sessions are migrated - so we wrote a compound session handler that wrote to both old session handler and the new session handler and compared the read results to ensure that we weren&#39;t seeing anything inconsistent.&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;Once we ran it for a few cycles of &quot;$maxlifetime&quot; - ours was set at 1440 seconds, we were sure that the new handler was working as expected. Once that happened, we replaced it with code that was just the Redis Handler and we had the entire system shift to Redis.&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.600000381469727px;&quot;&gt;At the moment, my nascent profiling is showing me that we are saving somewhere close to about 30ms savings in page views that uses Sessions.&lt;/span&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/5626932650103260731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2014/04/redis-as-session-store.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/5626932650103260731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/5626932650103260731'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2014/04/redis-as-session-store.html' title='Redis as a Session Store'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-1217781469356451054</id><published>2014-04-08T03:10:00.001-07:00</published><updated>2014-04-08T03:10:35.620-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="hacks"/><title type='text'>Clean up crapware on Android devices</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Android is in pretty bad shape - simply because the OEMs are loading it with crapware apps that are never used by you and I, but will be consuming the phone&#39;s resources. After struggling with battery drain issues recently, I sat down to see if there are any alternatives. I found &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.cleanmaster.mguard&quot; target=&quot;_blank&quot;&gt;cleanup master&lt;/a&gt;&amp;nbsp;app that helped me identify some of the crapware and helped me improve the battery performance significantly. Here are the steps:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Download the app&lt;/li&gt;
&lt;li&gt;Turn off auto-updating of Apps in Play Store (read below for the reasons)&lt;/li&gt;
&lt;li&gt;Use the App Manager tab in Cleanup Master to find all the pre-loaded apps. There is a good chance you don&#39;t use any of them, but go through the ones that you don&#39;t seem to be using and disable them. Some of them can&#39;t be disabled since they have been updated since your factory settings - so you might have to uninstall the updates before disabling them. (The reason for turning off auto-updating is that if you kept it on, then these pre-installed apps will be auto-updated and enabled - which is where you started off.)&lt;/li&gt;
&lt;li&gt;Remove any non-pre-loaded (apps that you installed) apps that you don&#39;t use anymore.&lt;/li&gt;
&lt;li&gt;Go to junk files tab in Cleanup Master to see if there are any files that you can delete.&lt;/li&gt;
&lt;li&gt;Update apps every now and then manually - only those that you seem to be using.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
When you are done, reboot your phone and confirm that everything you disabled is still disabled. If you are paranoid about what Cleanup Master app might do, then now is a good time to uninstall that too.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
You should see a significant performance improvement.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/1217781469356451054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2014/04/clean-up-crapware-on-android-devices.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/1217781469356451054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/1217781469356451054'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2014/04/clean-up-crapware-on-android-devices.html' title='Clean up crapware on Android devices'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-3210956294376966205</id><published>2014-04-02T21:38:00.001-07:00</published><updated>2014-04-02T21:38:46.320-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="queues"/><category scheme="http://www.blogger.com/atom/ns#" term="redis"/><category scheme="http://www.blogger.com/atom/ns#" term="sns"/><category scheme="http://www.blogger.com/atom/ns#" term="sqs"/><title type='text'>Redis as a replacement for SNS/SQS</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;i&gt;(Cross posting from&amp;nbsp;http://tech.vocanic.com/2014/04/redis-as-replacement-for-snssqs.html)&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We recently launched VSocial-API, a REST based API for our Social-CRM module. We also mandated all our internal uses to be shifted to use this API instead of going through the libraries that we had earlier provisioned for. This API, codenamed internally as Mantle, brought along a set of new architectures, each of which should perhaps be talked about in a separate blog entry, but I would like to talk about one specific feature and how we just sped it up.&lt;br /&gt;
&lt;br /&gt;
For each call to the API, we wanted to split the operations into two parts - one that needs to be done synchronously - like say storing data to Source-of-truth store like MySQL, and those that can be done asynchronously - like caching, or updating analytics etc.&lt;br /&gt;
&lt;br /&gt;
For this break up to work, we would either need multi-threading (such that the asynchronously processing can be forked into a separate thread) or we would need message passing. Since PHP doesn&#39;t support multi-threading our first release of this API achieved this using a combination of SNS-SQS.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://wacomdpsstorage.blob.core.windows.net/articlesmedia/content-ppe.windowsazure.com/en-us/documentation/articles/cloud-services-dotnet-multi-tier-app-using-service-bus-queues/20140207015810/getting-started-multi-tier-101.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;206&quot; src=&quot;https://wacomdpsstorage.blob.core.windows.net/articlesmedia/content-ppe.windowsazure.com/en-us/documentation/articles/cloud-services-dotnet-multi-tier-app-using-service-bus-queues/20140207015810/getting-started-multi-tier-101.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 13px;&quot;&gt;(Src:&amp;nbsp;https://wacomdpsstorage.blob.core.windows.net/articlesmedia/content-ppe.windowsazure.com/en-us/documentation/articles/cloud-services-dotnet-multi-tier-app-using-service-bus-queues/20140207015810/getting-started-multi-tier-101.png,&lt;br /&gt;
Our Architecture can be loosely illustrated like this.)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of synchronous processing, a message would be sent to SNS, which would be connected to a SQS. This SQS would then be scanned regularly by a background process, the asynchronous steps would be assigned and finally deleted from the SQS. SQS comes with mutex-visibility etc and automatic re-insertion if the current process died etc. All in all it was a great functional arrangement.&lt;br /&gt;
&lt;br /&gt;
But this was slow. Very slow. Our profiling indicated that we were spending about 40ms (out of an average of 150ms response time) just sending data to SNS. This was pretty much unacceptable in the long run.&lt;br /&gt;
&lt;br /&gt;
We have been toying with Redis internally for a few different things and this seemed to be a good fit to solve this problem. It is easy to use Redis as a Queue implementation using RPUSH and LPOP or BRPOPLPUSH commands as suggested&amp;nbsp;&lt;a href=&quot;https://programmers.stackexchange.com/questions/204623/how-to-implement-a-message-queue-over-redis&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;// Producer&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;RPUSH message&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;// Consumer&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;LPOP message&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, the problem is of mutex. The suggested solution there was to move the message from the primary queue to a processing queue and then if the process dies, then you regularly scan the processing queue and re-insert it back to the primary queue. This sounds a bit complex.&lt;br /&gt;
&lt;br /&gt;
Redis can also be used as a Mutex - SADD for instance won&#39;t be successful if run for the second time with the same value. And we can easily expire the key after some time - so the mutex will be automatcially released. The Mutex can also be extended if need be.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;// First process&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;SADD Mutex_message1 message1 &amp;nbsp;// Succeeds&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;EXPIRE Mutex_message1 10 &amp;nbsp; &amp;nbsp; &amp;nbsp;// Held for 10 seconds&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;// Second process&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;SADD Mutex_message1 message1 // Fails - mutex not obtained&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;// First Process extends the mutex for another 10 seconds&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;EXPIRE Mutex_message1 10 &amp;nbsp; &amp;nbsp; &amp;nbsp;// Held for 10 more seconds&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;// First process releases the Mutex&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;DEL Mutex_message1&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;So, we combined the two solutions to get a replacement for SNS-SQS. It hasn&#39;t deprecated SNS-SQS yet, since the background process is still pushing it to SNS for distribution to other consumers, but going forward we should be deprecating SNS-SQS completely.&lt;br /&gt;
&lt;br /&gt;
True to the word, after our push earlier today, our response time has dropped from an average of about 150ms to about 90ms.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif90U_AYc1c3TkZniquX7d5H0G1zoEzQwNAvRTjVOawaJPp66_l7GOvCbl7epexHxnhd7FxDcGiOC47zhRUFcrdlUQX0XvxifKuuc6vdMeCBbM7sb0kHcXMUrrZcfQs1ftnEkv-uwLZf8/s1600/Screen+Shot+2014-04-03+at+12.30.25+pm.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif90U_AYc1c3TkZniquX7d5H0G1zoEzQwNAvRTjVOawaJPp66_l7GOvCbl7epexHxnhd7FxDcGiOC47zhRUFcrdlUQX0XvxifKuuc6vdMeCBbM7sb0kHcXMUrrZcfQs1ftnEkv-uwLZf8/s1600/Screen+Shot+2014-04-03+at+12.30.25+pm.png&quot; height=&quot;169&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/3210956294376966205/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2014/04/redis-as-replacement-for-snssqs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/3210956294376966205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/3210956294376966205'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2014/04/redis-as-replacement-for-snssqs.html' title='Redis as a replacement for SNS/SQS'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif90U_AYc1c3TkZniquX7d5H0G1zoEzQwNAvRTjVOawaJPp66_l7GOvCbl7epexHxnhd7FxDcGiOC47zhRUFcrdlUQX0XvxifKuuc6vdMeCBbM7sb0kHcXMUrrZcfQs1ftnEkv-uwLZf8/s72-c/Screen+Shot+2014-04-03+at+12.30.25+pm.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-6157016670344576877</id><published>2014-01-29T19:27:00.006-08:00</published><updated>2014-01-29T19:28:29.626-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="hack"/><category scheme="http://www.blogger.com/atom/ns#" term="php"/><title type='text'>Using PHP Namespaces</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Let&#39;s suppose:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;include(&quot;/usr/lib/facebook/facebook.php&quot;); &amp;nbsp;// Defines \Facebook\User&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;include(&quot;/usr/lib/facebook/twitter.php&quot;); // Defines \Twitter\User&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// And you need to construct both User objects&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;// Option1:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;use \Facebook\User;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;$u1 = new User(); // Constructs \Facebook\User&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;$u2 = new \Twitter\User();&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: #741b47; font-family: Courier New, Courier, monospace;&quot;&gt;// Option2&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #741b47; font-family: Courier New, Courier, monospace;&quot;&gt;use \Facebook\User as FbUser;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #741b47; font-family: Courier New, Courier, monospace;&quot;&gt;use \Twitter\User as TwUser;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #741b47; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: #741b47; font-family: Courier New, Courier, monospace;&quot;&gt;$u1 = new FbUser();&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #741b47; font-family: Courier New, Courier, monospace;&quot;&gt;$u2 = new TwUser();&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/6157016670344576877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2014/01/using-php-namespaces.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6157016670344576877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6157016670344576877'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2014/01/using-php-namespaces.html' title='Using PHP Namespaces'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-7431198266211627107</id><published>2013-10-30T23:32:00.001-07:00</published><updated>2013-10-30T23:32:09.845-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ci"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="hudson"/><category scheme="http://www.blogger.com/atom/ns#" term="phing"/><category scheme="http://www.blogger.com/atom/ns#" term="php"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Continuous Integration with Phing and Hudson</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I presented at the PHP User Group (Singapore) this week on how to get Continuous Integration working in a PHP development environment using Phing and Hudson.&lt;br /&gt;
&lt;br /&gt;
Check out the talk:&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/wNy5N9wjyWg&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
and the slides:&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;356&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; scrolling=&quot;no&quot; src=&quot;http://www.slideshare.net/slideshow/embed_code/27765725&quot; style=&quot;border-width: 1px 1px 0; border: 1px solid #CCC; margin-bottom: 5px;&quot; width=&quot;427&quot;&gt; &lt;/iframe&gt; &lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5px;&quot;&gt;
&lt;strong&gt; &lt;a href=&quot;https://www.slideshare.net/shreeniwasiyer/2013-1028-php-ug-presentation-ci-using-phing-and-hudson&quot; target=&quot;_blank&quot; title=&quot;2013 10-28 php ug presentation - ci using phing and hudson&quot;&gt;2013 10-28 php ug presentation - ci using phing and hudson&lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a href=&quot;http://www.slideshare.net/shreeniwasiyer&quot; target=&quot;_blank&quot;&gt;Shreeniwas Iyer&lt;/a&gt;&lt;/strong&gt; &lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/7431198266211627107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2013/10/continuous-integration-with-phing-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/7431198266211627107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/7431198266211627107'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2013/10/continuous-integration-with-phing-and.html' title='Continuous Integration with Phing and Hudson'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-3212399843270830493</id><published>2013-10-04T03:05:00.002-07:00</published><updated>2013-10-04T03:05:22.617-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><title type='text'>Improving our Central Deployment Architecture</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;span style=&quot;background-color: white; font-size: 14px; line-height: 19px;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: Helvetica Neue Light, HelveticaNeue-Light, Helvetica Neue, Helvetica, Arial, sans-serif;&quot;&gt;(Cross posting from: &lt;a href=&quot;http://tech.vocanic.com/2013/10/improving-our-central-deployment.html&quot;&gt;http://tech.vocanic.com/2013/10/improving-our-central-deployment.html&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot;&gt;We have written in the past about how we use a&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://tech.vocanic.com/2013/02/central-deployment-server-vocanic.html&quot; style=&quot;-webkit-transition: color 0.3s; background-color: white; color: #009eb8; display: inline; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;central deployment server&lt;/a&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot;&gt;&amp;nbsp;to push all our code to our servers. We have three two general category of servers - serving pages to users; web-workers that fetch data from various external API and put them into our content stores.&lt;/span&gt;&lt;br /&gt;
&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot;&gt;The second category, web workers, has seen an increase in number proportionate to our on-boarding of clients and eventually hit about 50 servers. Now, the big problem is that if you have about 50 servers hitting our deploy server every minutes, our deploy server is just bombarded with too much and the CPU&amp;nbsp;utilisation&amp;nbsp;maxed out too many times for our comfort.&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot; /&gt;&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; margin-left: auto; margin-right: auto; padding: 4px; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://yankeegunnerblog.files.wordpress.com/2011/08/lions-hippo_1536335i.jpg&quot; imageanchor=&quot;1&quot; style=&quot;-webkit-transition: color 0.3s; color: #009eb8; display: inline; margin-bottom: 0px !important; margin-left: auto; margin-right: auto; margin-top: 0px !important; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;http://yankeegunnerblog.files.wordpress.com/2011/08/lions-hippo_1536335i.jpg&quot; style=&quot;-webkit-border-image: url(data:image/png; border-image-repeat: stretch; border-image-slice: 9; border-image-source: url(data:image/png; border-image-width: 9px; border: 9px none; box-sizing: border-box; display: inline-block; height: auto; margin: 10px auto; max-width: 100%; padding: 8px; position: relative;&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 11px;&quot;&gt;(Src:&amp;nbsp;http://yankeegunnerblog.files.wordpress.com/2011/08/lions-hippo_1536335i.jpg)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot; /&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot; /&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot;&gt;This week, after sitting over enough CPU-Utilisation&amp;nbsp;alarms (over the past 10 days or so), we decided to fix it once and for all. Here is the broad outline of the change we did to improve things:&lt;/span&gt;&lt;br style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px;&quot; /&gt;&lt;br /&gt;
&lt;ul style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; outline: none; padding: 0px 0px 0px 2em;&quot;&gt;
&lt;li style=&quot;margin: 0px; outline: none; padding: 0px;&quot;&gt;The deploy server checks the last updated time of our code directories every minute and publishes them over a webserver.&lt;/li&gt;
&lt;li style=&quot;margin: 0px; outline: none; padding: 0px;&quot;&gt;The web workers (and even the page serving servers) have a cron running every minutes that gets this timestamp and compares with a cached copy - if the timestamp is different, then it goes and rsyncs the code over to itself.&lt;/li&gt;
&lt;li style=&quot;margin: 0px; outline: none; padding: 0px;&quot;&gt;To avoid the&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Thundering_herd_problem&quot; style=&quot;-webkit-transition: color 0.3s; color: #009eb8; display: inline; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;thundering herd problem&lt;/a&gt;, each client will sleep for a time period that it choses randomly (within a fixed limit) so that the clients come to deploy server in a staggered manner.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; margin: 0px; outline: none; padding: 0px;&quot;&gt;
And that was all it took for us to improve the CPU utilisation on the deploy server. (The hike towards the right is because of certain changes that developers were pushing which caused actual file transfers.)&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; margin: 0px; outline: none; padding: 0px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;background-color: white; clear: both; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; margin: 0px; outline: none; padding: 0px; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTIPtiqVR4BAhBPKivV4L2VRxlbBJumh5fGvF9B4sLrk4Txu8e8E46R3GG1ICrMi7HEgiWb_spL8MkmmUyySdCNrH1obDqOv4PXPRTR7hx1rYKf-18DU9gryYEsSQhvhSwmfR3Nu-FTXk/s1600/Screen+Shot+2013-10-04+at+5.35.12+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;-webkit-transition: color 0.3s; color: #009eb8; display: inline; margin-bottom: 0px !important; margin-left: 1em; margin-right: 1em; margin-top: 0px !important; outline: none; text-decoration: none; transition: color 0.3s;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;339&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTIPtiqVR4BAhBPKivV4L2VRxlbBJumh5fGvF9B4sLrk4Txu8e8E46R3GG1ICrMi7HEgiWb_spL8MkmmUyySdCNrH1obDqOv4PXPRTR7hx1rYKf-18DU9gryYEsSQhvhSwmfR3Nu-FTXk/s640/Screen+Shot+2013-10-04+at+5.35.12+PM.png&quot; style=&quot;-webkit-border-image: url(data:image/png; border-image-repeat: stretch; border-image-slice: 9; border-image-source: url(data:image/png; border-image-width: 9px; border: 9px none; box-sizing: border-box; display: inline-block; height: auto; margin: 10px auto; max-width: 100%; padding: 8px; position: relative;&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; margin: 0px; outline: none; padding: 0px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #333333; font-family: &#39;Helvetica Neue Light&#39;, HelveticaNeue-Light, &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19px; margin: 0px; outline: none; padding: 0px;&quot;&gt;
In fact, the CPU utilisation on the web workers have also gone down enough that we think that we can use them more efficiently. That&#39;s for another day though! Have a good weekend.&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/3212399843270830493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2013/10/improving-our-central-deployment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/3212399843270830493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/3212399843270830493'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2013/10/improving-our-central-deployment.html' title='Improving our Central Deployment Architecture'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTIPtiqVR4BAhBPKivV4L2VRxlbBJumh5fGvF9B4sLrk4Txu8e8E46R3GG1ICrMi7HEgiWb_spL8MkmmUyySdCNrH1obDqOv4PXPRTR7hx1rYKf-18DU9gryYEsSQhvhSwmfR3Nu-FTXk/s72-c/Screen+Shot+2013-10-04+at+5.35.12+PM.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-6657187583631361052</id><published>2013-07-27T17:46:00.000-07:00</published><updated>2017-09-02T17:38:09.887-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="compress"/><category scheme="http://www.blogger.com/atom/ns#" term="hacks"/><category scheme="http://www.blogger.com/atom/ns#" term="PDF"/><category scheme="http://www.blogger.com/atom/ns#" term="scripts"/><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu"/><title type='text'>Compressing all PDF files in a directory</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
[UPDATE (2017/09/03): This code is now available at&amp;nbsp;&lt;a href=&quot;https://github.com/ShreeniwasIyer/PDFCompressor&quot;&gt;https://github.com/ShreeniwasIyer/PDFCompressor&lt;/a&gt;&amp;nbsp;ready to be forked and readily available to run at&amp;nbsp;&lt;a href=&quot;https://hub.docker.com/r/shreeniwasiyer/pdfcompressor/&quot;&gt;https://hub.docker.com/r/shreeniwasiyer/pdfcompressor/&lt;/a&gt;]&lt;br /&gt;
&lt;br /&gt;
If you are like me, you would have probably accumulated a bunch of PDFs related to travels, bills, receipts, statements, financial stuff etc. These PDFs are generated through a variety of sources - using &quot;Save As&quot; functionality on your browser or elsewhere, downloaded from an attachment in an email, downloaded from a website using the Browser or you probably just scanned them in.&lt;br /&gt;
&lt;br /&gt;
The big trouble with this collection of PDFs is that their sizes could hugely vary - starting at about 30Kb per page for an invoice generated by a well optimized program to upto 500Kb per page for a scanned document. If you want to store these files over the long run, you want to compress them so that you are consuming less space. &amp;nbsp;So, I wanted to compress all of them to an extent that the visible quality doesn&#39;t worsen.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://synapse.files.wordpress.com/2011/06/compress-files1.jpg?w=630&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://synapse.files.wordpress.com/2011/06/compress-files1.jpg?w=630&quot; height=&quot;288&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;(src:&amp;nbsp;http://synapse.files.wordpress.com/2011/06/compress-files1.jpg?w=630)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
In Ubuntu, compressing a single PDF is fairly easy (from &lt;a href=&quot;http://askubuntu.com/a/256449&quot;&gt;http://askubuntu.com/a/256449&lt;/a&gt;):&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 0px; color: #333333; font-family: &#39;Ubuntu Mono&#39;, &#39;Ubuntu Beta Mono A&#39;, Consolas, &#39;Bitstream Vera Sans Mono&#39;, &#39;Courier New&#39;, Courier, monospace; font-size: 14px; line-height: 18px; margin-bottom: 10px; max-height: 600px; overflow: auto; padding: 5px; vertical-align: baseline; width: auto;&quot;&gt;&lt;code style=&quot;border: 0px; color: #222222; font-family: &#39;Ubuntu Mono&#39;, &#39;Ubuntu Beta Mono A&#39;, Consolas, &#39;Bitstream Vera Sans Mono&#39;, &#39;Courier New&#39;, Courier, monospace; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dNOPAUSE -dQUIET -dBATCH -sOutputFile=output.pdf input.pdf
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Depending on the size of the original document, the improvement varied anywhere between 5% to 90%, on a sample test of a few files. So, then I decided to build in a bash script to run it over a folder with subfolders in it.&lt;br /&gt;
&lt;br /&gt;
Firstly, one strange case I encountered was that if the file was small enough (about 100kb in size or smaller), then the above script would create a file sometimes bigger, and most often perceptably worse off than the original. So, it meant that it was best to compress only those files that were bigger than 100Kb in size.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 0px; margin-bottom: 10px; max-height: 600px; overflow: auto; padding: 5px; vertical-align: baseline; width: auto;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;code style=&quot;border: 0px; color: #222222; font-family: &#39;Ubuntu Mono&#39;, &#39;Ubuntu Beta Mono A&#39;, Consolas, &#39;Bitstream Vera Sans Mono&#39;, &#39;Courier New&#39;, Courier, monospace; font-size: 14px; line-height: 18px; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;# Get the file size&lt;/code&gt;&lt;span style=&quot;color: #003300; font-family: &amp;quot;ubuntu mono&amp;quot; , &amp;quot;ubuntu beta mono a&amp;quot; , &amp;quot;consolas&amp;quot; , &amp;quot;bitstream vera sans mono&amp;quot; , &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;span style=&quot;font-size: 14px; line-height: 18px;&quot;&gt;s=`stat -c%s &quot;$f&quot;`
if [ $s -gt $thresh ]; then
  # Process
else
  echo &quot;Too-Small File $f&quot;
fi&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;code style=&quot;border: 0px; color: #222222; font-family: &#39;Ubuntu Mono&#39;, &#39;Ubuntu Beta Mono A&#39;, Consolas, &#39;Bitstream Vera Sans Mono&#39;, &#39;Courier New&#39;, Courier, monospace; font-size: 14px; line-height: 18px; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Secondly, if you tried applying this on a password protected file, you will encounter a bunch of errors and hence you don&#39;t want to try it on such files. It was best to detect it upfront and not attempt any further operations on password protected files.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 0px; margin-bottom: 10px; max-height: 600px; overflow: auto; padding: 5px; vertical-align: baseline; width: auto;&quot;&gt;&lt;code style=&quot;border: 0px; font-size: 14px; line-height: 18px; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: #222222; font-family: &amp;quot;ubuntu mono&amp;quot; , &amp;quot;ubuntu beta mono a&amp;quot; , &amp;quot;consolas&amp;quot; , &amp;quot;bitstream vera sans mono&amp;quot; , &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;#Check if PDF file is encrypted&lt;/span&gt;&lt;/code&gt;

&lt;code style=&quot;border: 0px; font-size: 14px; line-height: 18px; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: #222222; font-family: &amp;quot;ubuntu mono&amp;quot; , &amp;quot;ubuntu beta mono a&amp;quot; , &amp;quot;consolas&amp;quot; , &amp;quot;bitstream vera sans mono&amp;quot; , &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;output=`gs -dBATCH -sNODISPLAY &quot;$f&quot; 2&amp;gt;&amp;amp;1`
gsexit=$?

if [ &quot;$gsexit&quot; == &quot;0&quot; ]; then
  # Normal File
else 
  echo &quot;Encrypted File $f&quot;
fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Thirdly, if the file was once compressed, I didn&#39;t want to compress them again - in case the quality deteriorated too much.&lt;br /&gt;
&lt;br /&gt;
Finally, I wanted this entire script to be idempotent - which meant that I could run this operation on the same directory twice and the second one should retain state from the first run, and I wanted it to be incremental - which meant that if I had a big directory - 10GB for instance, I should run it for a few minutes, let it process a quarter of the files, stop it and restart it later and it should continue from where it left off.&lt;br /&gt;
&lt;br /&gt;
To counter these above requirements, you can always build a stateful script (using files/DB to store state) - but I wanted it quick and dirty, and it should run on bash. I didn&#39;t want another programming language to be involved. So, I decided to save the state of files in the file-names itself. I used prefixes like &quot;passprotected-&quot;, &quot;compressed-&quot; and &quot;toosmall-&quot; to know I can skip them in following rounds.&lt;br /&gt;
&lt;br /&gt;
Putting it all together, here is what I got:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 0px; margin-bottom: 10px; max-height: 600px; overflow: auto; padding: 5px; vertical-align: baseline; width: auto;&quot;&gt;&lt;span style=&quot;color: #222222; font-family: &amp;quot;ubuntu mono&amp;quot; , &amp;quot;ubuntu beta mono a&amp;quot; , &amp;quot;consolas&amp;quot; , &amp;quot;bitstream vera sans mono&amp;quot; , &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;span style=&quot;font-size: 14px; line-height: 18px;&quot;&gt;#!/bin/bash

if [ &quot;$1&quot; == &#39;&#39; ]; then
 echo &quot;Usage &amp;lt;script-name&amp;gt; &amp;lt;directory&amp;gt; &amp;lt;threshhold&amp;gt;&quot;;
 exit 0;
fi

if [ &quot;$2&quot; == &#39;&#39; ]; then
 echo &quot;Usage &amp;lt;script-name&amp;gt; &amp;lt;directory&amp;gt; &amp;lt;threshhold&amp;gt;&quot;;
 exit 0;
fi

directory=$1;
thresh=$2;

echo &quot;Running the Compressor on $directory and $thresh&quot;;

find $directory -iname *.pdf | grep -v -i compressed | grep -v passprotected | grep -v toosmall | while read f
do
    # Looping on all files in the directory which have not been tagged in the past.

 # Get Directory where the file is located
 subdir=`dirname &quot;$f&quot;`
 # Get The filename in that directory. Prefixes can be added to this.
 filename=`basename &quot;$f&quot;`
 # Get size of the file.
 s=`stat -c%s &quot;$f&quot;`
 
 if [ $s -gt $thresh ]; then
  # File is big enough to be considered for Compressing
  
  # Check if the file is password protected
  output=`gs -dBATCH -sNODISPLAY &quot;$f&quot; 2&amp;gt;&amp;amp;1`
  gsexit=$?
  
  # CAUTION:
  # There is a chance that gsexit is non-zero for other reasons too - like format error etc.
  # This script will still mark it as Password Protected.
  
  if [ &quot;$gsexit&quot; == &quot;0&quot; ]; then
   # Normal File
   newfilename=&quot;$subdir/compressed-$filename&quot;;
   
   # The following command will create a compressed file, then delete the original if the first operation succeeded
   # And echos the fact that both commands were successful.
   
   gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dNOPAUSE -dQUIET -dBATCH -sOutputFile=&quot;$newfilename&quot; &quot;$f&quot; &amp;amp;&amp;amp; rm &quot;$f&quot; &amp;amp;&amp;amp; echo &quot;Compressed into $newfilename&quot;;
  else 
   # Tag the password protected file so we can ignore it in future.
   echo &quot;Renaming Encrypted File $f&quot;
   newfilename=&quot;$subdir/passprotected-$filename&quot;;
   mv &quot;$f&quot; &quot;$newfilename&quot;
  fi
 else
  # Tag files too small so we can ignore it in future
  
  echo &quot;Renaming Too-Small File $f&quot;
  newfilename=&quot;$subdir/toosmall-$filename&quot;;
  mv &quot;$f&quot; &quot;$newfilename&quot;
 fi
done&lt;/span&gt;&lt;/span&gt;

&lt;div&gt;
&lt;code style=&quot;border: 0px; font-size: 14px; line-height: 18px; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: #222222; font-family: &amp;quot;ubuntu mono&amp;quot; , &amp;quot;ubuntu beta mono a&amp;quot; , &amp;quot;consolas&amp;quot; , &amp;quot;bitstream vera sans mono&amp;quot; , &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;/pre&gt;
&lt;br /&gt;
There are bunch of noteworthy points:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;b&gt;This is an in-place script which means that the originals will be over-riden. Make a copy and run it there.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;The gsexit check isn&#39;t the best way to detect password protected files. The gs command could return an error for other reasons - but to keep it simple, I am bundling all errors into one tag.&lt;/li&gt;
&lt;li&gt;The command to compress has been chained to the deleting of original using &quot;&amp;amp;&amp;amp;&quot;, which, in bash, will happen only if first command succeeds and this could potentially mean that whatever errors, or interruptions, that happen at first command, will ensure that the original is unaffected. This is a simple, but elegant want to ensuring data integrity.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
On a run of 307Mb of PDF files, this script brought down the contents down to 130Mb. Totally worth the effort!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If you have an Ubuntu, or an X-OS, give this a shot.&lt;br /&gt;
&lt;br /&gt;
[UPDATE (2017/09/03): This code is now available at&amp;nbsp;&lt;a href=&quot;https://github.com/ShreeniwasIyer/PDFCompressor&quot;&gt;https://github.com/ShreeniwasIyer/PDFCompressor&lt;/a&gt;&amp;nbsp;ready to be forked and readily available to run at &lt;a href=&quot;https://hub.docker.com/r/shreeniwasiyer/pdfcompressor/&quot;&gt;https://hub.docker.com/r/shreeniwasiyer/pdfcompressor/&lt;/a&gt;]&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/6657187583631361052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2013/07/compressing-all-pdf-files-in-directory.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6657187583631361052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6657187583631361052'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2013/07/compressing-all-pdf-files-in-directory.html' title='Compressing all PDF files in a directory'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-4330380580326334001</id><published>2013-07-19T00:07:00.001-07:00</published><updated>2013-07-19T00:07:28.883-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="essay"/><title type='text'>AWS as a monopoly threat</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
How many of you have heard of IBM SmartCloud? or RedHat Open Shift? or AppHarbour? or Engine Yard? or SoftLayer? or Joyent? Apparently, these are all &lt;a href=&quot;http://www.networkcomputing.com/cloud-computing-comparisons/iaas-providers/&quot; target=&quot;_blank&quot;&gt;Platform-as-a-Service&lt;/a&gt; (PaaS) or &amp;nbsp;Infrastructure-as-a-Service (IaaS)&amp;nbsp;&lt;a href=&quot;http://www.informationweek.com/cloud-computing-comparisons/paas-providers/&quot; target=&quot;_blank&quot;&gt;providers&lt;/a&gt;. These are all supposed to be competing with AWS.&lt;br /&gt;
&lt;br /&gt;
As I was sitting at the &lt;a href=&quot;https://aws.amazon.com/aws-summit-2013/singapore/&quot; target=&quot;_blank&quot;&gt;AWS Summit 2013&lt;/a&gt; yesterday at the MBS, and hearing of one success story after another, which includes my experience at Vocanic, I was left wondering on whether we are seeing the case of monopoly being constructed one service, one quarter, one page view at a time.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/82/files/2009/07/slide1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/82/files/2009/07/slide1.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;(src:&amp;nbsp;&lt;a href=&quot;http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/82/files/2009/07/slide1.jpg&quot;&gt;http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/82/files/2009/07/slide1.jpg&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
I have heard of famous monopolistic market captures in the past - Windows in the Desktop market (which continues to today), Google (countered by Yahoo and Bing), iPhone (countered by Android) and so on, but I have only been fortunate to see one right in front of my eyes - and that has been the ever rising tide of AWS.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://venturebeat.files.wordpress.com/2010/12/wintel.jpg?w=558&amp;amp;h=9999&amp;amp;crop=0&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;307&quot; src=&quot;http://venturebeat.files.wordpress.com/2010/12/wintel.jpg?w=558&amp;amp;h=9999&amp;amp;crop=0&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;(Src:&amp;nbsp;&lt;a href=&quot;http://venturebeat.files.wordpress.com/2010/12/wintel.jpg?w=558&amp;amp;h=9999&amp;amp;crop=0&quot;&gt;http://venturebeat.files.wordpress.com/2010/12/wintel.jpg?w=558&amp;amp;h=9999&amp;amp;crop=0&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
In the above instances, the case of Google, iPhone, and if I may add the other case of Facebook whose case is still open, are all cases where their contemporaries fought back hard and created either an equal or at least a significant second. In Google&#39;s case, Yahoo and Bing continued to corner at least a third of the market. In case of iPhone, the split is almost even now. In case of Facebook, while the numbers favor Facebook at the moment, significant competitors like Twitter, WhatsApp, Instagram etc are keeping Facebook busy either at competing for market share or at acquiring the market share.&lt;br /&gt;
&lt;br /&gt;
But the instance of Microsoft is somewhat unique. While they were gaining traction in the 1990s, there doesn&#39;t seem to be documented evidence of major efforts to counter that in the market. Apple, their competitor on consumer facing compute market, had carved a niche that they seem to be unwilling to expand. Linux, Unix and such, which built compelling operating systems, were building it either as hobby or for the server markets, leaving the consumer market wide open for Windows to capture. Once the takeover of the market was complete, Microsoft could engage in questionable practices leading to multiple anti-trust cases.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://insiderlouisville.com/wp-content/uploads/2012/10/MonopolyMan.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://insiderlouisville.com/wp-content/uploads/2012/10/MonopolyMan.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;(Src:&amp;nbsp;&lt;a href=&quot;http://insiderlouisville.com/wp-content/uploads/2012/10/MonopolyMan.jpg&quot;&gt;http://insiderlouisville.com/wp-content/uploads/2012/10/MonopolyMan.jpg&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
The brief history on popular case of tech competition is important to understand to study what might happen to AWS. Amazon&#39;s top brass, Jeff Bezos and Dr. Werner Vogels, are clearly pushing for a vision that isn&#39;t shared by others in the market. None of the competitors listed in the first line are fighting out for the big market of cloud infrastructure services. IBM may capture some enterprise market, but AWS is &lt;a href=&quot;http://www.forbes.com/sites/timworstall/2013/05/31/amazons-aws-cloud-is-a-serious-threat-to-traditional-enterprise-computing-companies/&quot; target=&quot;_blank&quot;&gt;gunning for that too&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
There are competitors - Google App Engine, Heroku, Azure and Rackspace that are perhaps worth mentioning (along with similar cases like Linode.) In case of Google App Engine, which I had briefly toyed with, doesn&#39;t allow a dev to write code as they like, but to write it in the &lt;a href=&quot;https://developers.google.com/appengine/&quot; target=&quot;_blank&quot;&gt;paradigm chosen by GAE&lt;/a&gt;. &lt;a href=&quot;https://devcenter.heroku.com/articles/cedar&quot; target=&quot;_blank&quot;&gt;Same&lt;/a&gt; is the case with Heroku, which unfortunately, also &lt;a href=&quot;http://stackoverflow.com/questions/9802259/why-do-people-use-heroku-when-aws-is-present-whats-distinguishing-about-heroku&quot; target=&quot;_blank&quot;&gt;runs on AWS&lt;/a&gt; making it not much of a real competitor anyway.&lt;br /&gt;
&lt;br /&gt;
Rackspace is too busy just lending standard compute instance and left too far behind in the space of providing &lt;a href=&quot;http://www.rackspace.com/cloud/managed_cloud/&quot; target=&quot;_blank&quot;&gt;managed services&lt;/a&gt; to be considered on equal footing. Windows Azure is stuck with a world where people have to use &lt;a href=&quot;http://www.windowsazure.com/en-us/documentation/services/sql-database/&quot; target=&quot;_blank&quot;&gt;Windows Tech&lt;/a&gt; to be developing on their cloud.&lt;br /&gt;
&lt;br /&gt;
Put it all together and you get a case where Amazon Web Services is being &lt;a href=&quot;http://pro.gigaom.com/blog/new-morgan-stanley-reports-cites-the-dominance-of-aws/&quot; target=&quot;_blank&quot;&gt;let loose&lt;/a&gt; to capture the large market for providing tech-agnostic platform and &lt;a href=&quot;http://blog.backupify.com/2013/05/09/the-future-of-the-cloud-will-aws-continue-to-dominate/&quot; target=&quot;_blank&quot;&gt;infrastructure services&lt;/a&gt;. What happens once their &lt;a href=&quot;http://www.businessinsider.com/morgan-stanley-predicts-more-aws-dominance-2013-5&quot; target=&quot;_blank&quot;&gt;capturing&lt;/a&gt; of the market is &lt;a href=&quot;http://www.businessinsider.com/cia-600-million-deal-for-amazons-cloud-2013-3&quot; target=&quot;_blank&quot;&gt;complete&lt;/a&gt;? A monopoly.&lt;br /&gt;
&lt;br /&gt;
As a consumer of AWS, I continued to be amazed by their services and how they continue to be &lt;a href=&quot;http://aws.amazon.com/about-aws/whats-new/2013/07/01/amazon-rds-mysql-5-6/&quot; target=&quot;_blank&quot;&gt;innovating&lt;/a&gt; and &lt;a href=&quot;http://aws.amazon.com/about-aws/whats-new/2013/07/09/price-reductions-on-amazon-ec2-dedicated-instances/&quot; target=&quot;_blank&quot;&gt;dropping their prices&lt;/a&gt; as they go along. While some experts out there are&lt;a href=&quot;http://www.zdnet.com/is-amazon-becoming-the-microsoft-of-cloud-hold-that-thought-7000016157/&quot; target=&quot;_blank&quot;&gt; holding on to the thought&lt;/a&gt; of an AWS Monopoly, I feel threatened by the fact that there aren&#39;t any real competitors. The consequences of such a scenario are just too frightening to imagine.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/4330380580326334001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2013/07/aws-as-monopoly-threat.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4330380580326334001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4330380580326334001'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2013/07/aws-as-monopoly-threat.html' title='AWS as a monopoly threat'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-5582992058774787059</id><published>2013-06-04T23:27:00.000-07:00</published><updated>2013-06-04T23:29:09.197-07:00</updated><title type='text'>Our (selective) approach to Caching</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
(Cross posting from&amp;nbsp;&lt;a href=&quot;http://tech.vocanic.com/2013/06/our-selective-approach-to-caching.html&quot;&gt;http://tech.vocanic.com/2013/06/our-selective-approach-to-caching.html&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
At Vocanic, for a long time, we were shirking away from the idea of Caching. It is not that we didn&#39;t feel the need, but it was always considered too much of an effort to put in, specially since, any one campaign or module wasn&#39;t running at a scale where the cache would have been beneficial.&lt;br /&gt;
&lt;br /&gt;
To me caching involves the following cost:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;The actual cache server (this is becoming insignificant since AWS provides one ready made)&lt;/li&gt;
&lt;li&gt;Adopting the code for caching the data and cache invalidation across all the pertinent data flows.&lt;/li&gt;
&lt;li&gt;All operational work (like going in and changing a data row that is wrong) need to deal with the cache invalidation.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.testically.org/wp-content/uploads/2012/03/caching.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://www.testically.org/wp-content/uploads/2012/03/caching.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;(Image Src:&lt;a href=&quot;http://www.testically.org/wp-content/uploads/2012/03/caching.jpg&quot;&gt;http://www.testically.org/wp-content/uploads/2012/03/caching.jpg&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
For most of our campaigns, the scale of data isn&#39;t big enough for the above efforts to pay off. &amp;nbsp;Over 2012, that slowly started to change. We were adding on RDS Slaves and adopting our data layers to address the growing amount of traffic.&lt;br /&gt;
&lt;br /&gt;
More importantly, we were also working on a few products that were stretching our data requirements. It seemed that if we can get the caching going, then at the very least, the effort to build the caching and maintaining it would be paid off by the benefits to these products. So, as of late 2012, we started working on introducing caching into a few important modules/products.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Infrastructure Level Caching&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
The first layer that we attacked was the DB layer. We were using &lt;a href=&quot;http://adodb.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;AdoDB&lt;/a&gt; as our ORM for PHP. We were quite happy with it and had been maintaining it and adding features to it. For more than 2 years now, more than 95% of our data requirements was going through AdoDB. If we could get AdoDB to be cache aware, then that would ease our implementation efforts considerably. Thankfully, since a lot of our calls were something like:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;$user-&amp;gt;Load(&quot;id = ?&quot;, ($id));&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;$conversation-&amp;gt;Load(&quot;userId = ?&quot;, ($userId));&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In such case, it made perfect sense to cache the results against the $id and the $userId params. So, we decided to extend AdoDB_Active_Record (the primary class that maps to a table in DB) and added the logic to cache the results.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The next problem we encountered was that while at one place facebookId could be used to Load the $user object, at other places it could be other primary keys like $id. So, we wanted to make sure that we can cache it first and have the object be returned even in the second case.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here is how we solved the problem:&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Find the primary key of the Class/Table.&lt;/li&gt;
&lt;li&gt;When an object is cached, cache is against it&#39;s primary key only.&lt;/li&gt;
&lt;li&gt;Map the query string (like &quot;facebookId = ?&quot; and $facebookId) into this primary key.&lt;/li&gt;
&lt;li&gt;So, when &quot;id = ?&quot; is queried for, we already have the object in cache and we retrieve it.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
We excluded caching against queries which were returning multiple objects, like Find queries, in which case we don&#39;t know if the same query will result in the same set of objects with confidence. &amp;nbsp;Obviously, we invalidated the cache on every Insert, Update, Save or Delete operations.&lt;br /&gt;
&lt;br /&gt;
Once this extended class was created, we rolled it out to a few modules and made it work. Then we moved on to Application Layer Caching.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Application Layer Caching&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
The trouble with Infrastructure Level Caching is that it has no clue to the intentions of the calling application/module. Only the module knows the business logic of what makes sense to be cached and what not. Trying to do everything at Infrastructure Level is dangerous - you will end up caching too many objects that may not be looked up before expiry, while you will end up not caching the ones that are important.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So, we started at looking at some of our modules - specially the user warehouse that spans across all campaigns of a client - to add application layer caching. This module had clean entry points (based on the PHP api allowed to the developers) and hence cache invalidation could be carefully controlled. Moreover, this module is called multiple times for the same user while he is interacting with a campaign and the locality of reference (by time) is quite strong.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Moreover, this module was thoroughly tested using automated tests - so we could test the caching easily. So we extended our existing UserManager and added cached implementation of all interfaces - tested them and rolled out the new version slowly to one client after another.&lt;/div&gt;
&lt;div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Results&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLpaAf5XKbVmAe5JmVdWRjHMCS8NFEkk5NnAIOmChsPvqnxawoIsZA1Ok18Uxq_P-TMvsaW85Uc_0zGzkac4yMXs59JXsGG1zN6LcqqcIwvzI-EFVjQCkbQ3P-zZ02upr5yZJFFc9welM/s1600/Screenshot+from+2013-06-04+18:06:06.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLpaAf5XKbVmAe5JmVdWRjHMCS8NFEkk5NnAIOmChsPvqnxawoIsZA1Ok18Uxq_P-TMvsaW85Uc_0zGzkac4yMXs59JXsGG1zN6LcqqcIwvzI-EFVjQCkbQ3P-zZ02upr5yZJFFc9welM/s1600/Screenshot+from+2013-06-04+18:06:06.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Despite our limitations of not adding caching to vast majority of our code, just attacking the infrastructure layer and one module at the application layer has got us quite a bit of Cache Hit successes. Let&#39;s look at the second peak in the red line (at 150,000 mark) and compare the various lines:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Traffic on Loadbalancer 1: ~6,000&lt;/li&gt;
&lt;li&gt;Traffic on Loadbalancer 3: ~25,000&lt;/li&gt;
&lt;li&gt;Total Traffic: ~31,000&lt;/li&gt;
&lt;li&gt;DB Connections: ~12,000&lt;/li&gt;
&lt;li&gt;Cache Hits: ~150,000&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Since we use s3 for serving out static content, it is safe to assume that much of the traffic through the Loadbalancers are application service requests (ajax + page loads put together.)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Essentially, we were having 5 cache hits per request, while we are at 1 DB connection per 4 requests.&amp;nbsp;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The big dipping in cache hit results mostly happen in night time SGT, when Load balancer 1 also sees a significant dip in traffic. So, our caching is tracking our data requirements quite well. The key lesson for us is that we managed to get a significant caching mechanism going with very little coding practices changes and developer effort.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/5582992058774787059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2013/06/our-selective-approach-to-caching.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/5582992058774787059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/5582992058774787059'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2013/06/our-selective-approach-to-caching.html' title='Our (selective) approach to Caching'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLpaAf5XKbVmAe5JmVdWRjHMCS8NFEkk5NnAIOmChsPvqnxawoIsZA1Ok18Uxq_P-TMvsaW85Uc_0zGzkac4yMXs59JXsGG1zN6LcqqcIwvzI-EFVjQCkbQ3P-zZ02upr5yZJFFc9welM/s72-c/Screenshot+from+2013-06-04+18:06:06.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-4406791913718966310</id><published>2013-03-30T01:20:00.004-07:00</published><updated>2013-03-30T01:21:52.078-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="big-data"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="mysql"/><category scheme="http://www.blogger.com/atom/ns#" term="php"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Medium Size Data Set Processing with PHP + MySQL</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div&gt;
&lt;i&gt;(Cross Post from Vocanic&#39;s official blog -&amp;nbsp;&lt;a href=&quot;http://tech.vocanic.com/2013/03/medium-size-data-set-processing-with.html&quot;&gt;http://tech.vocanic.com/2013/03/medium-size-data-set-processing-with.html&lt;/a&gt;)&amp;nbsp;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
This blog is a bit long, but for engineers trying to solve data processing of non-trivial sets across a MySQL+PHP setup, this is perhaps a read worth the time they spend.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.dreamwizardz.com/images/php_mysql_logo.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;115&quot; src=&quot;http://www.dreamwizardz.com/images/php_mysql_logo.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;(Img Source:&amp;nbsp;http://www.dreamwizardz.com/images/php_mysql_logo.png)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
At Vocanic, we selected to go with PHP + MySQL for a set of reasons that hold true as much as it did when we took the decision 30 months back and we are still quite happy with that choice.&lt;br /&gt;
&lt;br /&gt;
One thorny problem, however, is trying to process reports or other such data processing activities. Let me define the problem first and then explain how we went about solving it:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Processing reasonably small sets of data (at least by current big-data standards): 50k-500k objects/rows at a time.&lt;/li&gt;
&lt;li&gt;All objects have primary source of truth in MySQL.&lt;/li&gt;
&lt;li&gt;Each object will have secondary linked objects (or joined tables in MySQL terminology) taking the total input size to anywhere between 200k-3million objects/rows.&lt;/li&gt;
&lt;li&gt;Synchronous results are not necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
MySQL queries, with a bunch of &lt;i&gt;join&lt;/i&gt;s and &lt;i&gt;group by&lt;/i&gt;s just don&#39;t cut it. They are too slow and hog up too much resources that live queries, which are very important to be serviced aren&#39;t serviced in time. You can go along a few paths of adding indexes and optimizing the queries, but at some point it breaks down.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.brainstuck.com/wp-content/uploads/2009/02/mysql-or-my-sql.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;201&quot; src=&quot;http://www.brainstuck.com/wp-content/uploads/2009/02/mysql-or-my-sql.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;(Img Src:&amp;nbsp;http://www.brainstuck.com/wp-content/uploads/2009/02/mysql-or-my-sql.jpg)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;
The next alternative is to go distributed, as in Map Reduce to solve such a problem. Having been at Yahoo when we were building a Hadoop based solution for exactly this category of problems, it was a natural choice for me to consider. With Amazon offering Elastic Map Reduce, it seemed we wouldn&#39;t have to worry about setting up and maintaining our own Hadoop cluster, which was too much for us to handle.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The trouble is - if you source of truth is in MySQL, you have to pump all of that data into S3, which is Amazon&#39;s choice of replacement for HDFS and then you started a cluster linked to S3. For me, moving the data from MySQL to S3 was more than half the trouble anyway. In addition to that, whether we went traditional Hadoop or Hive, we would have had to maintain a parallel code base in a different language, just to handle reports and data processing. There is yet no port of PHP based Map Reduce in sight.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://3.asset.soup.io/asset/3776/2147_ecdd_500.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.asset.soup.io/asset/3776/2147_ecdd_500.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;(Img Src:&amp;nbsp;http://3.asset.soup.io/asset/3776/2147_ecdd_500.png)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
The reason for PHP based distributed systems not being there, seems natural, since PHP doesn&#39;t support threads, and while it is easy to imagine building a distributed data processing system with Inter Process Communication, I am gathering that it might be too heavy to make sense. I haven&#39;t done enough thinking or researching, but the evidence shows that PHP based distributed data processing is a non-starter in the tech community.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://cdn.smartphowned.com/2012/11/5/54897fd852dfd829a5fc3535fb7e05d2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;204&quot; src=&quot;http://cdn.smartphowned.com/2012/11/5/54897fd852dfd829a5fc3535fb7e05d2.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;(Img Src:&amp;nbsp;http://cdn.smartphowned.com/2012/11/5/54897fd852dfd829a5fc3535fb7e05d2.jpg)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So, back to Vocanic&#39;s problem. We had a perfectly functioning PHP+MySQL setup for all our synchronous processing that seemed to be useless for heavy data processing for asynchronous needs. We already had the architecture to scale up and down a bunch of web worker machines. So, we decided to experiment with building a bridge between the two worlds&amp;nbsp;our self.&amp;nbsp;We started building a PHP solution that would work with all our existing PHP code and still be able to achieve the above requirements.&lt;/div&gt;
&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Data Export&lt;/h4&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://d36cz9buwru1tt.cloudfront.net/solutions/backup-storage/Manyways.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;http://d36cz9buwru1tt.cloudfront.net/solutions/backup-storage/Manyways.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;(Img Src:&amp;nbsp;http://d36cz9buwru1tt.cloudfront.net/solutions/backup-storage/Manyways.png)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
As a first cut, we adopted the AWS route of storing intermediate data in S3. So, we built a rudimentary data export from MySQL to S3. Turns out that if you have an auto-incrementing id on a table, then incremental exports are super fast - just export the latest objects. But moving a single object from MySQL and into S3, after serializing into JSON was proving to be too slow, when attempted across a&amp;nbsp;sizable&amp;nbsp;table. Moreover, in the first cut, we were first storing it on the local file system and doing a batch copy and I was worried that having one file per row, in the file system would make it too slow, and I was fairly right on that (with hat-tip to &lt;a href=&quot;https://www.facebook.com/hyerba&quot;&gt;Yasin&lt;/a&gt; for cracking the exact reason). So, we moved to using batches of 5000 objects each, and we decided to write it straight to S3, since with batches, the call overhead wasn&#39;t too much. Also, we switched to PHP serialized data and not JSON due to encoding issues with UTF-8 characters. (I am sure it is solvable, but the fact that PHP serialization works perfectly well cuts down our motivation to fix it. )&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
Imagine that we had 50000 User objects, on which you are generating a Gender Count report, the S3 location would have looked like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;jobid&amp;gt;/input/1-5000.php&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;jobid&amp;gt;/input/5001-10000.php&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;....&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;jobid&amp;gt;/input/49001-50000.php&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Map &amp;amp; Reduce&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
We decided to adopt the concept of Map Reduce itself. The simple reason is that we were foreseeing that we will parallelize the maps and the reduces, using PHP processes instead of Java threads. Even if that didn&#39;t work, adopting a well known distribution computing paradigm would have helped us if we decided that this whole arrangement was a mess and we moved to Hadoop or something similar.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Essentially, the map and the reduce are no different in this world than what you can see in the Hadoop world. Every object is passed to a Map function, that is allowed to return a group for the object and all objects of the same group are passed to the reduce function for it&#39;s processing.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Since we had neatly cut down our objects into slices of 5000 each, we read a batch, kept it in memory, passed each of them to map function and write back n number of files (with n being the distinct groups generated for this batch of 5000 objects) to the groups section of the job in S3 itself.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So, in the example above, it would become:&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;jobid&amp;gt;/groups/male/1-5000.php (may not contain all 5000 objects, but contains every object from the batch of 1-5000 which are grouped as males)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;jobid&amp;gt;/groups/male/5001-10000.php&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;jobid&amp;gt;/groups/female/1-5000.php&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;....&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;font-family: inherit;&quot;&gt;
And finally, in the reduce phase, each of the files in &amp;lt;jobid&amp;gt;/groups/&amp;lt;group&amp;gt; can be passed to the reduce function for it to do whatever it does - export, summary count or something else if need be.&lt;/div&gt;
&lt;div style=&quot;font-family: inherit;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: inherit;&quot;&gt;
A summarize function is also called to allow the developers to close out anything that they wish to do after the heavy lifting is all over.&lt;/div&gt;
&lt;div style=&quot;font-family: inherit;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Putting Together as a service&lt;/h4&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
We put together all these ideas into a PHP based framework and we are calling it VocanicMapReduceLite or VMRL in short. It runs as a daemon service on a few select servers. Every time a report is needed, developers call a helper function providing the table, the secondary object mappings and their implementation class with the map and reduce functions and the framework does the rest.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;The helper function first puts the request into a SQS Queue.&lt;/li&gt;
&lt;li&gt;Then a bunch of VMRL workers keep scanning the queue and pick one when they find it.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Each worker, at the moment, goes through the entire process of data-generation, map, reduce and summarize &lt;i&gt;in sequence&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;We have implemented a S3 based locking to make sure that the same dataset (same table, same implementation class, same DB) is not attacked by more than one process leading to race conditions.&lt;/li&gt;
&lt;li&gt;The framework provides the option of developer giving a callback location, where callbacks are sent to ensure that the calling module is kept aware or progress or when the job is complete.&lt;/li&gt;
&lt;li&gt;While many jobs of non-competing data sets can run in parallel, we haven&#39;t implemented intra-job parallelization yet.&lt;/li&gt;
&lt;li&gt;Expected functionality like CSV exports, CSV summary tables (equivalent to group by queries) and similar SQLite3 outputs are pre-built into the framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
It took about 2 weeks for us to develop and about 2 more weeks to troubleshoot the first implementations, but as of now, the entire set up can be considered advanced beta. We have already rolled it out into our flagship product VSocial and it seems to be working fine, on production data sets.&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Summary &amp;amp; Road Ahead&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
Has this worked? Fortunately yes. At least for us.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This solution is allowing us to process a lot of insights reports over the data we contain in a parallel, asynchronous manner. The first lot always takes time, since it has to export all the data till then, but incremental runs are super fast.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In addition to this, it allows us to process the data in PHP during this flow, that wouldn&#39;t have been possible with MySQL queries, like geo-tagging, or expanding a JSON text field to extract deeper attributes.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This is also a lot cheaper than the Elastic Map Reduce, since AWS doesn&#39;t allow you to run EMR on anything less than medium EC2 node, whereas VMRL works and works perfectly fine on a EC2-micro instance.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
We are working on closing out a few kinks in operational issues with VMRL and then we shall be attacking Intra-Job parallelization. I believe that this framework has promise for medium data set processing (of sizes of about a few million objects) for those who have adopted PHP+SQL as the combination for other engineering considerations. We are hoping for a 18-24 month run of this framework before we will have to reconsider it based on the state of the art of both our and our provider&#39;s setups at that point of time.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
We are also considering whether such a framework would be interesting enough for a wider audience and if so, should we open source it. If you think this is the kind of solution you are looking for, drop a comment here please.&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/4406791913718966310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2013/03/medium-size-data-set-processing-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4406791913718966310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4406791913718966310'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2013/03/medium-size-data-set-processing-with.html' title='Medium Size Data Set Processing with PHP + MySQL'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-9197598393416698005</id><published>2013-03-04T19:42:00.002-08:00</published><updated>2013-03-04T19:52:00.673-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>State of Vocanic Infrastructure 2013</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Many months ago, I wrote about why we decided to use &lt;a href=&quot;http://tech.shreeni.info/2010/10/google-app-engine-vs-amazon-our.html&quot;&gt;Amazon EC2 as our primary Web Hostin&lt;/a&gt;g mechanism. Here is a quick update on how things are going with us.&lt;br /&gt;
&lt;br /&gt;
From my &lt;a href=&quot;http://tech.shreeni.info/2012/12/central-logging-server-using-syslog-ng.html&quot;&gt;previous&lt;/a&gt; &lt;a href=&quot;http://tech.shreeni.info/2012/11/central-deployment-server-vocanic.html&quot;&gt;posts&lt;/a&gt; on this &lt;a href=&quot;http://tech.shreeni.info/2012/11/scaling-up-infrastructure-vocanic.html&quot;&gt;blog&lt;/a&gt;, it is apparent that we are still very much on Amazon EC2. In fact, our being on Amazon EC2 is one of the reasons that we are well ahead of some of our competitors in this space and we can do things that we ourselves would have deemed daunting.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Team:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
We continue to be a team without a specialized server admin or DevOps engineers. Between Myself, &lt;a href=&quot;http://www.linkedin.com/in/chrisdrum&quot;&gt;Chris&lt;/a&gt; and &lt;a href=&quot;https://www.facebook.com/hyerba?fref=ts&quot;&gt;Yasin&lt;/a&gt;, we share the biggest load of our DevOps work. That has worked out fine till about now, when we finally started looking for a full time person. We have found the right candidates (one full time and one trainee engineer on rotation) and they should be coming on board pretty soon. So, what I am writing below has been achieved without having a full time engineering effort.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.companyweb.com.br/site/wp-content/uploads/2011/10/Imagem1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;280&quot; src=&quot;http://www.companyweb.com.br/site/wp-content/uploads/2011/10/Imagem1.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;(Image Source:&amp;nbsp;&lt;a href=&quot;http://www.companyweb.com.br/site/wp-content/uploads/2011/10/Imagem1.jpg&quot;&gt;http://www.companyweb.com.br/site/wp-content/uploads/2011/10/Imagem1.jpg&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Key AWS Advantages:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The natural advantage of AWS is to spin up new &lt;a href=&quot;http://aws.amazon.com/products/&quot;&gt;infrastructure elements&lt;/a&gt; at the click of a button. Want a new Database server? click a few buttons. Want a slave for that server? Click a few more buttons. Want a new caching server? some more buttons. Want a new Queue? Just a few more buttons.&lt;br /&gt;
&lt;br /&gt;
Just the DevOps convenience isn&#39;t enough. SQS is a classic instance of how the availability of easily administered technology infrastructure spurred us to queue up all background tasks and handle it in a structured manner. If we were to build our own queuing system, like the ones I had seen at Yahoo, we would have been too intimidated to even try, given the size of our team and trade-off on such an effort.&lt;br /&gt;
&lt;br /&gt;
Just having the ability to spin up new RDS servers, at multiple scales, have instilled demarcation of what data goes into what farms and hence made the setup a little easier to understand, a bit cleaner and easier to administer. If we were on hard servers, the cost of having to set them up from scratch (and pay extra just for demarcating data) would have made it too costly.&lt;br /&gt;
&lt;br /&gt;
Caching servers are among the easiest things to set up. Install memcached on a server with tons of memory and you are done. Right? Wrong. The rest of the hardware on those machines either go waste when left unused, or tend to interfere with the functioning of the cache if used for other purposes (a restart for a security patch involving an imagemagick library for instance, would have made it mandatory to lose the cache too.) ElastiCache takes the headache away from you.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Summary:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.lasvegasadco.com/draft_lens1996638module9907943photo_1213026232cartoon_geek.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://www.lasvegasadco.com/draft_lens1996638module9907943photo_1213026232cartoon_geek.png&quot; width=&quot;273&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;(Image Source:&amp;nbsp;&lt;a href=&quot;http://www.lasvegasadco.com/draft_lens1996638module9907943photo_1213026232cartoon_geek.png&quot;&gt;http://www.lasvegasadco.com/draft_lens1996638module9907943photo_1213026232cartoon_geek.png&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
The state of our 2013 systems architecture is that we use a lot of Amazon Web Services - EC2, RDS, ELB, ElastiCache, SQS, SNS, CloudWatch, S3 and SES, at last count. And we are very happy with it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/9197598393416698005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2013/03/state-of-vocanic-infrastructure-2013.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/9197598393416698005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/9197598393416698005'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2013/03/state-of-vocanic-infrastructure-2013.html' title='State of Vocanic Infrastructure 2013'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-2815297371586036782</id><published>2012-12-21T05:45:00.001-08:00</published><updated>2012-12-21T06:04:35.088-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="hacks"/><category scheme="http://www.blogger.com/atom/ns#" term="logging"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Central Logging Server Using Syslog-Ng @ Vocanic </title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
As blogged earlier, one of our DevOps goals at Vocanic is to have flexibility in &lt;a href=&quot;http://tech.shreeni.info/2012/11/scaling-up-infrastructure-vocanic.html&quot;&gt;scaling up and down&lt;/a&gt;&amp;nbsp;the app hosting environment using EC2 instances. I also blogged about how we set up a &lt;a href=&quot;http://tech.shreeni.info/2012/11/central-deployment-server-vocanic.html&quot;&gt;central deployment server&lt;/a&gt; to ensure that pushing code changes is as easy as possible for the developers.&lt;br /&gt;
&lt;br /&gt;
One of the nagging issues that we wanted to solve is that since we don&#39;t know the number of EC2 instances running, how do you troubleshoot issues where the primary way of investigation is log files?&lt;br /&gt;
&lt;br /&gt;
All our apps log a lot and all of them used to use either the PEAR Log class or the native PHP error_log and both these methods, by default, log into the local machine&#39;s file system. Both these systems can be configured to separate the logs of one app from another, by specifying the destination at the beginning of the execution of the script.&lt;br /&gt;
&lt;br /&gt;
The challenge then is to have one, well known, centralized logging server where all of these apps would log to, and where they would segregate logs files across app space and eventually end up. This has to have the following properties:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Update near real time: &lt;/i&gt;&lt;/b&gt;Having a one minute delay, perhaps using crons, is just way too slow for all practical purpose, since you can&#39;t tail the logs while trying to re-create the bug.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Automatically scale up&lt;/i&gt;&lt;/b&gt; when a new instances is spawned - having an arrangement which needs manual steps before the instance can be commissioned is just not acceptable.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Very &lt;b&gt;&lt;i&gt;easy for the developer to adopt&lt;/i&gt;&lt;/b&gt;, and not have them needing to change the 100s of log statements that they have already written through out the application/module.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Ability to write into the app specific log files&lt;/i&gt;&lt;/b&gt; so that developer don&#39;t step on each other&#39;s toes while troubleshooting stuff.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
With this mind, the easiest solution to produce is the following - just have a web listener on the central logging server and call it every time somebody calls error_log or PEAR Log.info. This will ensure that the above properties, but will make our code execution incredibly slow, because every time a log has to be written, it will wait for the process to initiate a TCP (or UDP) connection to the logging server. Having a persistent connection may help, but all said and done, logging to a third-party node while processing client&#39;s request is going to still be very slow.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The optimization to this, is to have the logs collected in memory during the script&#39;s execution and passing it to the central logging server, using perhaps &lt;a href=&quot;http://php.net/manual/en/function.register-shutdown-function.php&quot;&gt;register_shutdown_function&lt;/a&gt;. In practice, this is also very slow and it tends to hold up the serving process for a precious few milli seconds more than required and in effect, affects the overall capacity of the front end servers. (Every milli second extra spent per request slows down the freeing up of THAT process/thread to serve the next request.)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The perfect solution, then, is to have something where the logging works quite like it does with a regular error_log or PEAR log, but it in turn sends it off to the destination in it&#39;s process space and process time so that the front end processing is not much affected. Turns out, a smart combination of syslog-ng client and server should solve the problem. The genesis for this solution came from &lt;a href=&quot;http://stackoverflow.com/a/13564632/121052&quot;&gt;Michel Feldheim&#39;s answer&lt;/a&gt; on StackOverflow, which was then improved upon to achieve the desired result. So, here goes the detailed steps to achieving a central logging server for a PHP web serving environment.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;b&gt;Central Logging Server&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In the central logging server, install syslog-ng and configure it thus:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;sudo apt-get install syslog-ng&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
add the following to /etc/syslog-ng/syslog-ng.conf:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;destination d_php { file(&quot;$PROGRAM&quot; owner(www-data) group(www-data) perm(0644)); };&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;filter f_php { program(&quot;^\/var\/log\/&quot;); };&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;log { source(s_all); filter(f_php); destination(d_php); flags(final); };&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;source s_all {&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # ....&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # .... LET THE PREVIOUS CONTENT STAY - add the following line&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; tcp(port(5140) keep_alive(yes));&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;};&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
restart syslog service:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;sudo service syslog-ng restart&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;b&gt;On FE Servers&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
On each of the FE Servers, install syslog-ng and configure it thus:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;sudo apt-get install syslog-ng&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
add the following to /etc/syslog-ng/syslog-ng.conf on each of the FE servers:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;destination php { tcp(&quot;log.example.com&quot; port(5140)); };&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;log { source(s_all); filter(f_php); destination(php); };&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;filter f_php { facility(user); };&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
restart syslog servers:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;sudo service syslog-ng restart&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Application Code Changes:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now, the application code can be changed thus. Suppose each of the application have code like this writing to a separate file and you want the same structure to be reflected in the central log server:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;// PREVIOUS CODE: using PEAR Log&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;include &#39;/usr/share/php/Log.php&#39;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$log = Log::singleton(&#39;file&#39;, &#39;/var/log/nginx/xxx.log&#39;, &#39;&#39;, array(), PEAR_LOG_INFO);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;// PREVIOUS CODE: Using error_log&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;ini_set(&#39;error_log&#39; , &#39;/var/log/nginx/xxx.log&#39;);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The new code should look like:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;// NEW CODE: using PEAR Log&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;include &#39;/usr/share/php/Log.php&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$log = Log::singleton(&#39;syslog&#39;, LOG_USER, &#39;/var/log/nginx/xxx.log&#39;, array(), PEAR_LOG_INFO);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;// NEW CODE: Using error_log&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;ini_set(‘error_log’, ‘syslog’);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #d0e0e3;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;openlog(&#39;/var/log/nginx/xxx.log&#39;, LOG_NDELAY, LOG_USER);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If your FE servers and the Logging servers are all within the same EC2 security group, then there is no need to open the ports, since within the groups, all ports can be accessed freely, so long as a service is listening to it.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This allows your auto-scale environment to expand and contract without worries about your logs going astray.&lt;br /&gt;
&lt;br /&gt;
(ps: Credit for this solution goes to Michel Feldheim&#39;s answer and then fine-tuning by &lt;a href=&quot;https://www.facebook.com/hyerba?fref=ts&quot;&gt;Yasin&lt;/a&gt;, our de-facto Operation&#39;s Lead.)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/2815297371586036782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2012/12/central-logging-server-using-syslog-ng.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/2815297371586036782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/2815297371586036782'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2012/12/central-logging-server-using-syslog-ng.html' title='Central Logging Server Using Syslog-Ng @ Vocanic '/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-861872202805909667</id><published>2012-11-29T23:49:00.000-08:00</published><updated>2012-12-21T06:04:56.615-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="hacks"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Central Deployment Server @ Vocanic</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;br /&gt;
I &lt;a href=&quot;http://tech.shreeni.info/2012/11/scaling-up-infrastructure-vocanic.html&quot;&gt;blogged&lt;/a&gt; about how we solved the issue of scaling up our infrastructure through the use of EC2 instances, Elastic Load Balancers and a couple of RDS MySQL farms. In terms of hardware and compute power, this is good enough. There was one big problem that we had to solve, however.&lt;br /&gt;
&lt;br /&gt;
The way Vocanic&#39;s Engineering team is structured is that all our engineers work independently on their project-of-the-moment. The project of the moment may be a platform module, a feature in a product, or a social campaign (which in turn is most probably a Facebook App). Unlike a product company, this team doesn&#39;t work towards collective, synchronized schedules, but rather each engineer has their own deadline, to which they launch their work, after completing their due diligence (which could be automated testing, self testing or process testing involving multiple people). Because of this, it is too expensive for our team to have a fixed release process (check out code, compile, run tests, push to servers, restart servers etc). Doing that for each file change we small change we want to push will be too slow. The process had to be instant and scalable to individual file level plus it had to allow for anybody and everybody in the team to do so.&lt;br /&gt;
&lt;br /&gt;
So long as we had 2 Front End Servers, this problem is reasonably trivial to solve - ask the engineer to push the files to two of the servers and we are done. Despite the fact that pushing to just two servers is reasonably easy, engineers, being human, make mistakes and two servers end up being out of sync. So, we said, no problem - we will run a nightly script to diff the two servers in the important folders - the ones containing PHP code and PHP libraries and so long as we don&#39;t find anything amiss, we are good and if we find anything amiss, we shoot an email each night. Every morning, I would receive an email about an out-of-sync file and forward it to the engineer, and he will go fix it. This worked, at least for some time.&lt;br /&gt;
&lt;br /&gt;
Then we started talking about 3,4,5 servers. When I first brought up more servers in a team meeting, most engineers had this resigned look saying - &quot;f**k, we got to push now to half a dozen servers, and Shreeni will be forwarding diff mails about how I missed pushing it to server 4&quot;. Turns out, we needed a better solution.&lt;br /&gt;
&lt;br /&gt;
EC2 allows you to store files either in the machine&#39;s own virtual space, or you could load up an &lt;a href=&quot;http://aws.amazon.com/ebs/&quot;&gt;Elastic Block Storage&lt;/a&gt; to hold your data. EBS allows you to scale your file storage requirement independent of your compute scale requirement and also allows you to detach EBS from one EC2 instance and attach it to another. And EBS attached to all our EC2 instances would solve our problem - just throw in your code there and you are good to go. Turns out AWS doesn&#39;t allow that arrangement.&lt;br /&gt;
&lt;br /&gt;
We thought about using Dropbox on our servers or some such tools - but DropBox on Linux servers have always been iffy - even the single Ubuntu server we have at our office for file sharing has issues.&lt;br /&gt;
&lt;br /&gt;
We then looked into the good old rsync to do the file updates from a single location. Turns out rsync is fast, efficient and works for the needs we have.&lt;br /&gt;
&lt;br /&gt;
So we have now deployed a single, central deployment server, unimaginatively called deploy, whose job is to receive the updated code from the developers and hold it till an FE server comes and syncs up the relevant folders. The FE servers themselves can easily be set up - using the SSH keys of the deploy server - to do an rsync over password less SSH. Using the deploy&#39;s keys means that once you have set it up, you can replicate the FE servers many times over and you won&#39;t have to do any keys setup along the way. And with the right combination of rsync flags you can ensure that you pull only what you need and the deletes are also synchronized. The only throuble with this approach is that symlinks are not preserved, but end up becoming hard files on the FE servers, but it doesn&#39;t seem a big enough worry for us.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-3Zl4qmAx1C8G_GIWrlJq8FvgDm86AvviPJbnSE16RdihR94d4otxEHxZ_MIBsZAF7RoVWidx1ynXCD9HLBhYhSE6Ae3GJ2s9qSWHFImq3xMBnYWN7oK6KQRgF-xXXLcmagoin0NmJFc/s1600/Deploy+Architecture+2012.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-3Zl4qmAx1C8G_GIWrlJq8FvgDm86AvviPJbnSE16RdihR94d4otxEHxZ_MIBsZAF7RoVWidx1ynXCD9HLBhYhSE6Ae3GJ2s9qSWHFImq3xMBnYWN7oK6KQRgF-xXXLcmagoin0NmJFc/s1600/Deploy+Architecture+2012.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Since all our code is Plain Old PHP, we don&#39;t have to worry about restarting or reloading servers to pick up the updates. Our nginx+apc combination works fine in picking them and up and executing them in the best possible manner.&lt;br /&gt;
&lt;br /&gt;
All transfers within EC2 instances is free from a bandwidth charge perspective - which means that as you scale up the number of servers, this arrangement brings down the cost of your operation, since your file updates are going only to one server, though one could always argue that updated code only constitutes a negligible component of our overall bandwidth bill.&lt;br /&gt;
&lt;br /&gt;
This still doesn&#39;t answer the following questions, some of which we haven&#39;t sorted out yet, but we are working towards them:&lt;br /&gt;
&amp;nbsp;- What about pushing library or config changes to FE servers, still got to be done one by one?&lt;br /&gt;
&amp;nbsp;- &lt;a href=&quot;http://stackoverflow.com/questions/13563078/how-do-i-set-up-php-logging-to-go-to-a-remote-server&quot;&gt;What about the logs being generated at the servers, can we centralize log collection so that the developers don&#39;t have to log into a bunch of machines to troubleshoot?&lt;/a&gt;&lt;br /&gt;
&amp;nbsp;- What happens if the deploy server itself goes down? What specifically happens to the keys that have been set up already?&lt;br /&gt;
&lt;br /&gt;
I will write more about these aspects in further posts.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/861872202805909667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2012/11/central-deployment-server-vocanic.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/861872202805909667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/861872202805909667'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2012/11/central-deployment-server-vocanic.html' title='Central Deployment Server @ Vocanic'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-3Zl4qmAx1C8G_GIWrlJq8FvgDm86AvviPJbnSE16RdihR94d4otxEHxZ_MIBsZAF7RoVWidx1ynXCD9HLBhYhSE6Ae3GJ2s9qSWHFImq3xMBnYWN7oK6KQRgF-xXXLcmagoin0NmJFc/s72-c/Deploy+Architecture+2012.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-6380377701177781549</id><published>2012-11-28T02:53:00.001-08:00</published><updated>2012-12-21T06:05:17.942-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="vocanic"/><title type='text'>Scaling Up Infrastructure @ Vocanic</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I have been meaning to document some of what we have been doing to scale up our infrastructure at &lt;a href=&quot;http://www.vocanic.com/&quot;&gt;Vocanic&lt;/a&gt;. When I joined more than 2 years back, Vocanic was running on very limited infrastructure, running off a managed hosting center somewhere in the US. I wanted to move the hosting to Singapore, simply because I wanted to keep the servers close to where our traffic was coming from- which was 99% from Singapore, Malaysia and Indonesia.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1ViB4pbnlpROfMqc3rj72htgccgcbd9AFHZqPlObDVuEAmkG9erGIoBR_q2fk7ESND5rhmLMoUWT7ePDuhyphenhyphen03aKi8LH5kzu_LW-cG724YU6s8HnLZcHUWjWsVQpSA4GvilxduJzyLfiZQ/s1600/Vocanic+Architecture+2010.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1ViB4pbnlpROfMqc3rj72htgccgcbd9AFHZqPlObDVuEAmkG9erGIoBR_q2fk7ESND5rhmLMoUWT7ePDuhyphenhyphen03aKi8LH5kzu_LW-cG724YU6s8HnLZcHUWjWsVQpSA4GvilxduJzyLfiZQ/s1600/Vocanic+Architecture+2010.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a href=&quot;http://aws.amazon.com/&quot;&gt;Amazon Web Services&lt;/a&gt;&amp;nbsp;had just set up a colo in Singapore and t1.micro&amp;nbsp;&lt;a href=&quot;http://aws.amazon.com/ec2/#instance&quot;&gt;instances&lt;/a&gt;&amp;nbsp;were just launched in EC2. It seemed like a perfect combination for us - host our services in Singapore, put up a bunch of EC2 instances behind an&amp;nbsp;&lt;a href=&quot;http://aws.amazon.com/elasticloadbalancing/&quot;&gt;Elastic Load Balancer&lt;/a&gt;&amp;nbsp;(ELB) and back it up with MySQL&amp;nbsp;&lt;a href=&quot;http://aws.amazon.com/rds/&quot;&gt;RDS&lt;/a&gt;. We plunged into it and the experience was overall satisfactory. Given the kind of campaigns we run, we don&#39;t experience regular high traffic, and in fact, traffic at any given time was never too much to bother us. The cost was still well under control and although we took a painful 12+ months to get off from our US hosting provider, we finally did it.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgalDDQxWpk5FI6UQle4_wxfZbki8i0WJ7vJAR_9mRO_3VGw2F_B7O2vYjAL7xAn3VeYV5lUsD_OXn1bAVRfqprdwVcNcx2xMEeP5p05AbIVBgttl_LbDl0HpTl7BHiHaPtT3_TaaZZyaSM/s1600/Vocanic+Architecture+2011.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;218&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgalDDQxWpk5FI6UQle4_wxfZbki8i0WJ7vJAR_9mRO_3VGw2F_B7O2vYjAL7xAn3VeYV5lUsD_OXn1bAVRfqprdwVcNcx2xMEeP5p05AbIVBgttl_LbDl0HpTl7BHiHaPtT3_TaaZZyaSM/s1600/Vocanic+Architecture+2011.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;span style=&quot;text-align: start;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;span style=&quot;text-align: left;&quot;&gt;We realized, recently, that our architecture isn&#39;t going to cut it too much into the future. One problem was that RDS was getting filled up fast and we were dependent too much on one RDS. We did two things at the same time, hived off our DB into two farms, each with a master and slave. The read traffic were being sent off to the slaves, while all writes to the master. This was enough to get us back to comfort zone, despite a significant increase in the amount of computing and read-write we were encountering. (Master Slave brought in a bunch of issues, but I am going to write about that in a separate blog post.)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;span style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;span style=&quot;text-align: left;&quot;&gt;Also, we were using one Elastic Load Balancer (ELB) to handle all our FE traffic, only to realize that one ELB can only be configured with only one SSL certificate, which meant that, as our SSL work increased (due to secure nature of recent campaigns), we were left with having to commission a bunch of ELBs. Thankfully, EC2 now allows you to attach a single EC2 instances to a bunch of ELBs, which means you don&#39;t have to spawn too many instances.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimTJCJOF-fXdwiy16IGQtxZHoBqyVKsOuQm_eFyjMvQxp81By2yN10Cn6fdqRVT-MRqhT51c04aOrTrFWDw_gAjcxUyheA5ljXAm84zzfWCv4os2WCY2XLiI8zbvkLQH29Yytcu9VC-jKn/s1600/Vocanic+Architecture+2012.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;261&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimTJCJOF-fXdwiy16IGQtxZHoBqyVKsOuQm_eFyjMvQxp81By2yN10Cn6fdqRVT-MRqhT51c04aOrTrFWDw_gAjcxUyheA5ljXAm84zzfWCv4os2WCY2XLiI8zbvkLQH29Yytcu9VC-jKn/s1600/Vocanic+Architecture+2012.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Recently, we have also realized that having a bunch of ELBs alone isn&#39;t enough. In some cases, the instances behind an ELB need to have fixed IPs (since they may be talking to services which are IP locked), while we have a lot of apps which don&#39;t have such a restriction, but need to scale up fast.&lt;br /&gt;
&lt;br /&gt;
So, we are now in the process of categorizing our ELBs into two sets - fixed ELBs and flexi ELBs. Fixed ELBs will always a fixed number of nodes which we promise to the developers, which can then be converted into IP locks. These ELBs can&#39;t be scaled up by adding more EC2 instances, but only by increasing the size of each instance (from t1.micro to small to medium to large and so on). The flexi ELBs can be scaled up across either dimension - number of nodes of the capacity of each node.&lt;br /&gt;
&lt;br /&gt;
When a new ELB is commissioned, the commissioning team (Dev+PM) needs to inform whether it is going to be flexi or fixed and we will accordingly set up the scripts.&lt;br /&gt;
&lt;br /&gt;
Along the line, we are also working on requesting DB connections on demand, to avoid opening unused connections to DBs; using memcache as default caching for all objects etc to allow us to scale our system across different attributes. We have also commissioned &lt;a href=&quot;http://aws.amazon.com/sns/&quot;&gt;Simple Notification Service&lt;/a&gt; (SNS) to improve the speed at which we process asynchronous tasks so that we don&#39;t have dependence on crons, which are already proving too slow for us since we can&#39;t kick it off before a minute is up. Each of these will need a separate post in itself and I hope to find time to write about all these developments.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/6380377701177781549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2012/11/scaling-up-infrastructure-vocanic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6380377701177781549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6380377701177781549'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2012/11/scaling-up-infrastructure-vocanic.html' title='Scaling Up Infrastructure @ Vocanic'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1ViB4pbnlpROfMqc3rj72htgccgcbd9AFHZqPlObDVuEAmkG9erGIoBR_q2fk7ESND5rhmLMoUWT7ePDuhyphenhyphen03aKi8LH5kzu_LW-cG724YU6s8HnLZcHUWjWsVQpSA4GvilxduJzyLfiZQ/s72-c/Vocanic+Architecture+2010.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-5645215642609688977</id><published>2012-11-22T04:09:00.000-08:00</published><updated>2012-11-22T04:09:44.102-08:00</updated><title type='text'>Kicking this blog back to life</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Its been a long time &lt;a href=&quot;http://tech.shreeni.info/2011/10/rip-dennis-m-ritchie.html&quot;&gt;since&lt;/a&gt; I posted on this forum (with my previous post being motivated by my boss wanting to showcase S3 to a client). The primary reason has been that I have been too busy (at work) and too lazy (at home) to make any meaningful contribution. I am now trying to make a conscious effort to post regularly here at some of the interesting things I have done in the last few months.&amp;nbsp;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/5645215642609688977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2012/11/its-been-long-time-since-i-posted-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/5645215642609688977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/5645215642609688977'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2012/11/its-been-long-time-since-i-posted-on.html' title='Kicking this blog back to life'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-4090767983050037223</id><published>2012-09-30T23:06:00.003-07:00</published><updated>2012-09-30T23:09:10.866-07:00</updated><title type='text'>Option to access S3 </title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
S3 is becoming the preferred choice of storage for a lot of companies now, and with its security features, auto scaling, and of course, easy access from EC2 instances make it the favored choice of storing files. What if the same had to be used and exposed (through secure credentials) to your clients or other third-parties?&lt;br /&gt;
&lt;br /&gt;
Here is a quick collection of possible options on how your client would access the same:&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
List of S3 Backup Tools (By Jeremy, the famous techie)&lt;/div&gt;
&lt;a href=&quot;http://jeremy.zawodny.com/blog/archives/007641.html&quot; style=&quot;color: #1155cc;&quot; target=&quot;_blank&quot;&gt;http://jeremy.zawodny.com/&lt;wbr&gt;&lt;/wbr&gt;blog/archives/007641.html&lt;/a&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;DragonDisk (for all OSes):&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://www.dragondisk.com/download-amazon-s3-client-google-cloud-storage-client.html&quot; style=&quot;color: #1155cc;&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;http://www.dragondisk.com/&lt;wbr&gt;&lt;/wbr&gt;download-amazon-s3-client-&lt;wbr&gt;&lt;/wbr&gt;google-cloud-storage-client.&lt;wbr&gt;&lt;/wbr&gt;html&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Amazon recommended or supported LIbraries for Android, iOS, Java, .NET, PHP &amp;amp; Ruby:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://aws.amazon.com/code?_encoding=UTF8&amp;amp;jiveRedirect=1&quot; style=&quot;color: #1155cc;&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;http://aws.amazon.com/code?_&lt;wbr&gt;&lt;/wbr&gt;encoding=UTF8&amp;amp;jiveRedirect=1&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br style=&quot;background-color: white; color: #222222;&quot; /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: white; color: #222222;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #222222;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Firefox Plugin:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #222222;&quot;&gt;
&lt;a href=&quot;http://www.s3fox.net/&quot; style=&quot;color: #1155cc;&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;http://www.s3fox.net&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #222222;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #222222;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;More links and guide to S3:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white; color: #222222;&quot;&gt;
&lt;a href=&quot;http://www.hongkiat.com/blog/amazon-s3-the-beginners-guide/&quot; style=&quot;color: #1155cc;&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;http://www.hongkiat.com/blog/&lt;wbr&gt;&lt;/wbr&gt;amazon-s3-the-beginners-guide/&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;But here is a quick code snippet to the same:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Download the PHP S3 Library from:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;a href=&quot;http://undesigned.org.za/2007/10/22/amazon-s3-php-class&quot;&gt;http://undesigned.org.za/2007/10/22/amazon-s3-php-class&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
Include it and integrate:&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;include_once (&quot;S3.php&quot;);&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;// To handle all the s3 media uploads/downloads&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Construct the object using:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$s3 = new S3($s3Key, $s3Secret);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Get the contents of your bucket using:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;// Full Signature:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;// public static function&amp;nbsp;getBucket(&quot;test-bucket&quot;, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null, $returnCommonPrefixes = false);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$files = $s3-&amp;gt;getBucket(&quot;test-bucket&quot;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Decide which file to download&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$file = $files[0];&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;//And finally download the contents using:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;// Full signature: public static function getObject($bucket, $uri, $saveTo = false);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$localfile = &quot;/tmp/abcd.txt&quot;;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$s-&amp;gt;getObject(&quot;text-bucket&quot;. $file-&amp;gt;name, $localfile);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// And you are done!&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/4090767983050037223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2012/09/option-to-access-s3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4090767983050037223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4090767983050037223'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2012/09/option-to-access-s3.html' title='Option to access S3 '/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-6280485526851898763</id><published>2011-10-12T20:27:00.000-07:00</published><updated>2011-10-12T20:27:44.338-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="computers"/><category scheme="http://www.blogger.com/atom/ns#" term="essay"/><category scheme="http://www.blogger.com/atom/ns#" term="tribute"/><title type='text'>RIP Dennis M Ritchie</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;Dear Dr. Dennis Ritchie,&lt;br /&gt;
&lt;br /&gt;
I just heard of your demise. My condolences to your family.&lt;br /&gt;
&lt;br /&gt;
You have been an inspiration to many engineers like me. I feel it is my honor &amp;amp; privilege to have read the book you co-authored with Dr. Brian Kernigham and set me on the path to becoming a programmer. I am also glad that all my co-students who thought that that book was &quot;difficult to read&quot; have either become managers or salespersons. The fact that I read it many years after I stopped actively programming in C, just so that I strengthen my basics, is a small tribute to that masterpiece.&lt;br /&gt;
&lt;br /&gt;
Your creations - both Unix &amp;amp; C, have had a phenomenal impact on the computer industry spawning dozens of thousands of innovative products and almost single handedly powering many many industries and helping the entire computer engineering manpower to make their livelihood.&amp;nbsp;I find it an honor that every language I programmed in has been either a direct or indirect descendant of C.&lt;br /&gt;
&lt;br /&gt;
I believe you have left a lasting impact on my life.&lt;br /&gt;
&lt;br /&gt;
Rest In Peace.&amp;nbsp;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/6280485526851898763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2011/10/rip-dennis-m-ritchie.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6280485526851898763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/6280485526851898763'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2011/10/rip-dennis-m-ritchie.html' title='RIP Dennis M Ritchie'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-8015670755333965191</id><published>2011-07-07T02:28:00.000-07:00</published><updated>2011-07-07T02:28:17.433-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kindle"/><category scheme="http://www.blogger.com/atom/ns#" term="reviews"/><title type='text'>Kindle - the review</title><content type='html'>Its been about 5-6 weeks since I have started using a Kindle and I believe it is long enough to write a review. My Kindle is a &lt;a href=&quot;http://www.amazon.com/dp/B004HFS6Z0/ref=kin3_ddp_alsoavail_kinw_kinwso&quot;&gt;3rd Generation Kindle (with the small screen) with special offers&lt;/a&gt; - worth USD 114. For the record, it was a gift from my lovely wife on my just-passed birthday. I picked a good partner.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;I will write more about Kindle in the following lines, but it is a device meant only for reading. Don&#39;t buy it to do anything else. This is for bibliophiles - not geeks. If you are a geek - buy an iPad or something like that - where you can read books and read emails and browse internet and listen to music and watch movies and video chat and so on. The Kindle is not a general purpose electronic device, and I repeat, it is meant only for reading. Did I tell you, it is only for book lovers?&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Right, now that I have put the reason d&#39;etre of Kindle in clear perspective, let&#39;s proceed.&amp;nbsp;Here are my quick notes:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Best device to read. With a nice black and white display and fluid options for page navigation, it is easy enough to read and addictive enough to keep you hooked.&lt;/li&gt;
&lt;li&gt;Form factor is good - fits nice into your palms, easy to hold with a single hand too and still navigate pages with ease. The only complaint I have is that it too thin and too light that it can easily slip out of your hands or hold (I have dropped it a few times already - unfortunately.)&lt;/li&gt;
&lt;li&gt;The hardware seems rigid - and as I said I have dropped it a few times and no major damage done. It also doesn&#39;t heat up - so you can hold it in your hands for many hours.&lt;/li&gt;
&lt;li&gt;The battery life is just about brilliant. I don&#39;t bother with charging. Seriously, I don&#39;t. Once in a while, when I plug it into my laptop for copying books, it gets enough charge to last me till the next such&amp;nbsp;occasion. For the record, the Kindle can go 3 weeks without a charge if you don&#39;t use Wifi and 2 weeks if you turn your Wifi on.&lt;/li&gt;
&lt;li&gt;In terms of supported formats - the primary support is for AZW, amazon&#39;s own format and generally available only from amazon, and mobi. In general, this is good enough since &lt;a href=&quot;http://calibre-ebook.com/&quot;&gt;calibre&lt;/a&gt; can easy convert almost any format into mobi and the experience is promising. PDF reading is a bit of an issue though, because reading it directly means that the screen is too small and if you adjust your zoom level, then you are left with too much&amp;nbsp;scrolling&amp;nbsp;for the experience to be good. Converting PDFs into mobi is ok for PDFs with primarily text content - but if you have PDFs with lots of images and such, skip it.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Getting content for the Kindle is reasonably straight forward - &lt;a href=&quot;http://www.amazon.com/Kindle-eBooks/b/ref=sv_kinh_1?ie=UTF8&amp;amp;node=1286228011&quot;&gt;amazon&lt;/a&gt; itself is the best source - it has free and paid books. Prices are costly if you compare to Indian retail prices, but not if you compare to Singapore retail prices. There is of course a decent supply of free content around the internet - both legal and illegal - so chose your pick.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;The e-Ink technology is just about brilliant - no glare, very easy on the eyes - and the comparable technologies - iPad (too much glare), Computer (again, glare and not easy on the eyes) don&#39;t even come close.&lt;/li&gt;
&lt;li&gt;No distractions - all you are doing is reading a book - and not getting a popup here and there for an email or a text message or a call. That makes the experience well rounded.&lt;/li&gt;
&lt;li&gt;The special offers that comes with this price is totally non-intrusive and not detrimental to the reading experience.&lt;/li&gt;
&lt;li&gt;Lastly, it is the price. US$114 (plus shipping to Singapore made it SGD 157) is attractive enough that you should consider buying it. It is cheaper that your mobile (and cheaper than say even 3 months of mobile bills), TV, Computer, A bicycle, a dinner at a costly restaurant with drinks or two dinners at a not-so-costly-restaurant. It is great pricing.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;If you are a book lover, who reads at least 10 books a year, Kindle is the device for you.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/8015670755333965191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2011/07/kindle-review.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/8015670755333965191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/8015670755333965191'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2011/07/kindle-review.html' title='Kindle - the review'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-4308689094072897420</id><published>2011-04-23T22:05:00.000-07:00</published><updated>2011-04-23T22:05:26.617-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="reviews"/><title type='text'>Buying my second Android Phone</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;A few months back, I blogged&lt;a href=&quot;http://tech.shreeni.info/2010/09/my-humble-take-on-android-vs-iphone.html&quot;&gt;&amp;nbsp;when I bought my first Android phone &lt;/a&gt;- Samsung Galaxy S. I had my fair share of disappointments and had written that the idea that I cannot upgrade to the latest versions of AndroidOS when the updates had been launched was too disappointing to bear. When finally I did get 2.2 on the phone, it was a massive improvement and suddenly the phone started looking a lot more closer to the iPhone experience.&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;Subsequently, when my iPhone 3G (the one that I had passed to my wife when I got the Galaxy S) contract ended, I decided to continue with the AndroidOS. These are the reasons:&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;/div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;I don&#39;t use too many apps - I have a minimal set of apps that are mandatory, then everything else doesn&#39;t matter much. To that extent, Apple &amp;amp; Android are about the same - the minimal apps are good in both OSes - Twitter, Browsers, Skype, Email, LinkedIn, FB and the likes.&lt;/li&gt;
&lt;li&gt;Google experience - Gmail, Chat, Picassa etc is a lot better on Android than on iPhone.&lt;/li&gt;
&lt;li&gt;For people like me who like to read a lot on the screen, the screen size and quality of some Android phones (like the Galaxy S) is a big plus.&lt;/li&gt;
&lt;li&gt;Battery life is normally good, and you can replace the batteries.&lt;/li&gt;
&lt;li&gt;WiFi hotspot - I can&#39;t count the number of times this has been a life saver for both me and my friends/colleagues.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;So, I am now the proud owner of a Samsung Nexus S - the Android 2.3 phone (and my wife has moved on to Galaxy S). The biggest plus is that it is a pure Android phone - which means updating stuff should be pretty easy. On the other hand, Samsung had done a good job of creating an OS version with more utilities (video player, file browser and such) than the standard OS and I had to spend some time to get up to speed with that. All in all, I am yet to have any major complaints and am generally quite impressed with the product.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;To address the concerns of the &lt;a href=&quot;http://tech.shreeni.info/2010/09/my-humble-take-on-android-vs-iphone.html&quot;&gt;previous blog post&lt;/a&gt;:&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Touch screen becoming unusable while charging - you get used to not using the phone when it is charging. Doesn&#39;t seem much of a bummer now.&lt;/li&gt;
&lt;li&gt;GMail App gripes: I had a few of those - but as I have been using the app, I feel the flow of usage is a lot more suited to my usage and works better than the Apple Native Email option.&lt;/li&gt;
&lt;li&gt;Browser: Both on 2.2 and 2.3, Android&#39;s browser is a lot faster and has a better feel to using it. I still have the problem of closing a browser which I have been using for a bit, but then, I am now used to using the task manager to killing the browser. I still feel Google can do something about this.&lt;/li&gt;
&lt;li&gt;Multiple calendar works and works precisely as expected in both 2.2 and 2.3 of Android OS.&lt;/li&gt;
&lt;li&gt;Contacts usability: Once you get used to searching instead of browsing for contacts, life is back to being good on Android - and so is the case with me.&lt;/li&gt;
&lt;li&gt;3g/2g switching - still as bad as it was in 2.1, but with better battery lives, I have stopped worrying about switching to 2g altogether.&lt;/li&gt;
&lt;li&gt;Skype VoIP: Skype is still a rather poor experience on Android as compared to iPhone. Call quality is very poor and the phones freeze when trying to use skype. Can&#39;t help but hope for a better version of skype on Android - stable &amp;amp; fast.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/4308689094072897420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2011/04/buying-my-second-android-phone.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4308689094072897420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/4308689094072897420'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2011/04/buying-my-second-android-phone.html' title='Buying my second Android Phone'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-7800399318981436830</id><published>2010-10-22T02:11:00.000-07:00</published><updated>2010-10-22T02:11:33.211-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="essay"/><title type='text'>Google App Engine vs Amazon: Our decision at Vocanic</title><content type='html'>When I joined &lt;a href=&quot;http://www.vocanic.com/&quot;&gt;Vocanic&lt;/a&gt; about 10 weeks back, one of the key mandates for me was to move our applications to a better infrastructure. We were running a old style hosting environment based out of a colo in the US and it just didn&#39;t seem like a scalable solution. There was already an instance where one of the apps brought in heavy traffic and brought down the site - so we wanted something that can be scaled at a short notice.&lt;br /&gt;
&lt;br /&gt;
To just complete the context, we are a social media marketing agency - so we run a lot of social media applications for our clients - facebook apps, apps that interact with Foursquare, Twitter and the likes.&lt;br /&gt;
&lt;br /&gt;
As a fan of the &lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;Google App Engine (GAE)&lt;/a&gt;, I was quick to point out that option. As soon as I joined, I showed the engineers &lt;a href=&quot;http://tech.shreeni.info/2009/06/tinyurl-clone-in-java-in-40-lines.html&quot;&gt;some&lt;/a&gt; of the &lt;a href=&quot;http://tech.shreeni.info/2009/07/hack-rahu-kalam-calculator.html&quot;&gt;apps&lt;/a&gt; I had built on the GAE and spoke passionately about moving into that direction.&lt;br /&gt;
&lt;br /&gt;
Then I started evaluating Amazon&#39;s EC2 - specially because Amazon had set shop in Singapore recently and we were hoping to ride the &lt;a href=&quot;http://www.ida.gov.sg/Infrastructure/20090717105113.aspx&quot;&gt;Next Gen NBN&lt;/a&gt; wave in Singapore (most of our user base is from the region and if we could avoid sending their traffic across the pacific, it would be a boon for us) and I quickly saw why GAE was so much more a restricted environment in comparison to Amazon&#39;s EC2.&lt;br /&gt;
&lt;br /&gt;
We decided to go with &lt;a href=&quot;http://aws.amazon.com/&quot;&gt;Amazon EC2&lt;/a&gt; and having been on it for about 6 weeks now and&amp;nbsp;though&amp;nbsp;we were a skeptical bunch&amp;nbsp;in the beginning, I have to admit that it proved to be a good choice. The specific reasons include:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;GAE psupports two domain landings per app - one from appspot.com and one custom domain (say shreeni.info) of your choice. We often ran apps on multiple custom domains - if the client so wishes. In EC2, we could just hack up the apache vhosts file, but there is no such option in GAE.&lt;/li&gt;
&lt;li&gt;GAE&#39;s data storage engine while being quite well designed for scaling up, is rather a pain to deal with - specially since any single app of ours never scales to a million rows for us, but taken together, they add up to that order. We did not want a store where we could not do arbitrary DB operations - you can&#39;t do count(*) operation on GAE, for instance - and we didn&#39;t find the trade-off of retraining all our engineers to be GAE-storage-restrictions-aware when we were not going to get any benefits in return. Amazon&#39;s RDS storage, running a MySQL InnoDB engine was good enough - and it is fairly trivial to upgrade the storage on that while still retaining all our MySQL-training intact.&lt;/li&gt;
&lt;li&gt;We did not want to tie ourselves down to Java or Python - the two programming environments supported on GAE - specifically since we are veering towards using PHP as our default programming language (more on that in a separate post).&lt;/li&gt;
&lt;li&gt;We found some of the restrictions a little too er.. restrictive - timing out page requests after a few seconds, for instance. So, if we wanted to run a cron job that took more than a few seconds, we would have to go and redo the whole thing to fit into the GAE restrictions. Considering that we often launch entire apps within a few days and sometime in few hours, having to deal with altering our thought process just because GAE has that restriction seemed too time-consuming and detracting to me.&lt;/li&gt;
&lt;li&gt;Of course, serving the traffic from Singapore (one of EC2 colos) was going to make our pages faster than from GAE, which doesn&#39;t specify a region from where it will serve traffic. It might as well be doing it from Singapore, but unless it spells it out, we assumed it was from across the oceans.&lt;/li&gt;
&lt;li&gt;Amazon is showing a lot more innovation - &lt;a href=&quot;http://aws.amazon.com/sns/&quot;&gt;SNS&lt;/a&gt; and &lt;a href=&quot;http://aws.amazon.com/rds/#Read_Replica&quot;&gt;RDS Read Replicas&lt;/a&gt; being launched within the last month, while GAE hasn&#39;t shown enough new development in the last year and half I have been following them.&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;Starting up, one of the considerations we had was the cost of EC2 - almost ~$100 per instance per month for the lowest instance. But just in time for us, Amazon launched &lt;a href=&quot;http://aws.amazon.com/ec2/&quot;&gt;Micro Instances &lt;/a&gt;- and at ~$25 per instance per month, that was a perfect deal - our traffic, thankfully, fits perfectly on to the micro-instance-plus-RDS architecture. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;We already have a EC2 setup where we have launched a few client applications with higher availability and reliability than in our previous setup and it has so far been a good experience. This is not to say we won&#39;t be building GAE apps at all - I still see a role for that kind of environment in our setup, but it didn&#39;t fit into what we wanted to be our primary infrastructure base.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;In conclusion, GAE takes upon a lot of responsibility vis-a-vis Amazon EC2, but cuts down on a lot of a developer&#39;s authority. We chose to have a higher authority in exchange of accepting a higher responsibility.</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/7800399318981436830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2010/10/google-app-engine-vs-amazon-our.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/7800399318981436830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/7800399318981436830'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2010/10/google-app-engine-vs-amazon-our.html' title='Google App Engine vs Amazon: Our decision at Vocanic'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-7007666981372511604</id><published>2010-10-03T05:58:00.000-07:00</published><updated>2010-10-03T05:58:14.931-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="essay"/><title type='text'>Musings on Android</title><content type='html'>I am hardly alone in the thoughts that Android is spreading &lt;a href=&quot;http://twitter.com/#!/getanis/statuses/26066285043&quot;&gt;itself too thin&lt;/a&gt;&amp;nbsp;(thanks to &lt;a href=&quot;http://twitter.com/#!/getanis/&quot;&gt;@getanis&lt;/a&gt; who reached the same thought as I did). It seems that between Google, the manufacturers and the telecom operators, there are way too many parties involved, each of whom have the ability to &lt;a href=&quot;http://tech.shreeni.info/2010/09/my-humble-take-on-android-vs-iphone.html&quot;&gt;screw up the final product&lt;/a&gt;. In the good old iPhone world, Apple took most of the responsibility - they designed, manufactured it (through FoxConn of course, but the specifications were Apple&#39;s), tested it, ran the apps, sold it and even did a significant share of customer service. And to me, that seems like a working model.&lt;br /&gt;
&lt;br /&gt;
When the flash issue came up a few months back, some thought of it as a &lt;a href=&quot;http://techcrunch.com/2010/04/09/is-steve-jobs-ignoring-history-or-trying-to-rewrite-it/&quot;&gt;repeat of the Mac vs PC battle&lt;/a&gt; that was clearly won by PC in terms of market share. Yet, I believe this round of the battle is different - it is more like Windows vs Linux with Apple taking on the monopoly part and Android taking on the Linux part. Linux was fundamentally sound - open, and with lots of technical merits and yet, it fought a hard and mostly losing battle to win over desktop users. I always felt that Linux had way too many versions of the products flying around with little or no hand holding for the vast majority of the desktop users who needed a consistent experience across machines and over a reasonable period of time.&amp;nbsp;Something similar might happen to Android with every body from Google to &lt;a href=&quot;http://techcrunch.com/2010/09/21/verizon-v-cast-apps/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed:+Techcrunch+(TechCrunch)&amp;amp;utm_content=Google+Reader&quot;&gt;Verizon&lt;/a&gt; to &lt;a href=&quot;http://techcrunch.com/2010/09/27/amazon-android-app-store/&quot;&gt;Amazon&lt;/a&gt; wanting to run market places, and somewhere along the line, the experience might get diluted.&amp;nbsp;Some feel Android is&amp;nbsp;&lt;a href=&quot;http://techcrunch.com/2010/09/09/android-open/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed:+Techcrunch+(TechCrunch)&amp;amp;utm_content=Google+Reader&quot;&gt;too open&lt;/a&gt;&amp;nbsp;(to the detriment of end-users) and probably&amp;nbsp;&lt;a href=&quot;http://techcrunch.com/2010/09/10/google-nexus-one/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed:+Techcrunch+(TechCrunch)&amp;amp;utm_content=Google+Reader&quot;&gt;too supportive of operators&lt;/a&gt;&amp;nbsp;- the parties who have killed innovation for too long.&lt;br /&gt;
&lt;br /&gt;
The more pertinent thought for me, however, is that the economics don&#39;t seem to add up in favor of Android. When Apple alone is working on one product that can sell as much as a dozen Android phone, the the number of $s it can invest in making that model perfect is always going to be more and hence the product management, engineering and testing resources will always be more available for an Apple team to build a better product vis-a-vis Android products - which will be split between Google (who isn&#39;t going to be making much money per activation), manufacturers (like Samsung or HTC who will never boast of the best product/software-engineering teams) or the operators (let&#39;s just forget them as being the gatekeepers of phone quality - the best they can do is to provide good network coverage.)&lt;br /&gt;
&lt;br /&gt;
(Observers of news on Yahoo will be wise to remember the &lt;a href=&quot;http://techcrunch.com/2006/11/18/yahoos-brad-garlinghouse-makes-his-power-move/&quot;&gt;peanut butter manifesto&lt;/a&gt; which covered the same issue - spreading yourself too thin.)&lt;br /&gt;
&lt;br /&gt;
This is not to say that Apple won&#39;t mess things up - we have already seen &lt;a href=&quot;http://techcrunch.com/2010/09/10/iphone-4-antenna-case-2/&quot;&gt;Antennagate&lt;/a&gt; - but it seems that the dice is loaded in their favor of producing one good smartphone a year that can sell more profitably and can satisfy consumers a lot more than all the Android models put together in the same year.&lt;br /&gt;
&lt;br /&gt;
What do you think?</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/7007666981372511604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2010/10/musings-on-android.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/7007666981372511604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/7007666981372511604'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2010/10/musings-on-android.html' title='Musings on Android'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3426163161769571834.post-2071935087158369674</id><published>2010-09-05T19:24:00.000-07:00</published><updated>2011-04-23T22:07:21.000-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="reviews"/><title type='text'>My Humble Take on Android vs iPhone</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;[Update: Read&amp;nbsp;&lt;a href=&quot;http://tech.shreeni.info/2011/04/buying-my-second-android-phone.html&quot;&gt;follow up post&lt;/a&gt;&amp;nbsp;written after buying a second Android phone]&lt;br /&gt;
&lt;br /&gt;
I recently shifted from an iPhone 3G to Samsung Galaxy S. Sort of, because I actually gave away the Nokia E63 that my wife held in exchange for the Galaxy S, while my old iPhone 3G was taken up by her. I have used it for about 10 days now and done about same kind of things I used to do with my iPhone - so I believe this review is well-placed.&lt;br /&gt;
&lt;br /&gt;
To start off with, one of the primary motivations to buy the Galaxy S was because of the Android appeal. Android is one of the most talked about OSes out there and purported to be the real competitor to iPhone OS4. Secondly Android was often whispered to solve some of the thorny issues in iPhone - push Gmail, support for multiple exchange accounts, ability to run widgets and stuff, radio and in general openness (Oh, the tyranny of iPhone app store!).&lt;br /&gt;
&lt;br /&gt;
The secondary motivation was that it was cheaper. After trading in my Nokia E63 and signing up a new contract for 2 years, the Galaxy S was delivered without me paying a cent. To compare, the iPhone 4 would have costed me $110 on top of that. Nothing much, but still the allure of moving to a more open OS coupled with it being cheap was too much to let pass. So, the Galaxy S.&lt;br /&gt;
&lt;br /&gt;
Now the actual review. (Green means positive, red means negative, if you did not guess it already):&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Hardware:&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;[Compared is a brand new Samsung Galaxy S with 18 month old iPhone 3G.]&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #38761d;&quot;&gt;The screen size is bigger and it doesn&#39;t lose out of clarity w.r.t iPhone 3G. For that bigger screen, it doesn&#39;t become any difficult to handle or keep in your pocket. In general, a plus.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #38761d;&quot;&gt;It is so much lighter than the iPhone 3G. After handling it for a few days, when I pick up the iPhone 3G, it feels like lifting a brick.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #38761d;&quot;&gt;The batteries can be replaced. One of my big gripes is that smart phones in general are a drain on batteries - they must be since they run so many radios and a powerful display - and hence the ability to change batteries is a must - for two reasons, one so that you can keep a spare battery fully charged up if you are a power user, and two to replace the battery a year later so that you can prolong the life of the phone itself (most phones degrade mostly on the battery front).&lt;/span&gt; &lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;On the other hand, the display on this phone consumes so much battery that it goes from 100%-4% within 12 hours with about 2 hours of actual usage. Turning off 3G doesn&#39;t help, as it did on iPhone, because the display is the real culprit here. More so, charging the phone from say 5% to 100% takes nothing less than 3-4 hours. iPhone 3G would do that in just over an hour.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #38761d;&quot;&gt;Galaxy S is so slim that I am often afraid that it will drop it or it will slip from my hands.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;For some strange reason (I am guessing that the electronics majors would throw some light here), the touch-screen becomes completely unusable when charging. The sensitivity is all thrown off and it assumes taps all the time, even when I didn&#39;t actually tap. In general, I disconnect it from the charger before using it.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Software:&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;[Compared is Android OS 2.1 to iOS 3.1.3. I don&#39;t care if Android fans respond to these arguments with Android 2.2 features because iOS 4.0 also has its own set of rather impressive victories.]&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #38761d; font-weight: normal;&quot;&gt;Swype. It is the way forward on inputting words on a phone. Typing just feels so 2000ish after using swype.&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-weight: normal;&quot;&gt;Gmail App is OK. I know, everybody seems to love the app, but I will give it passing marks at best. In general, it is good to have full web functionality, but iPhone always had that support through the browser while the native client covered 90% of my use cases. &lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;My main gripe is that the new mail alert disappears once I open the app, but not actually read the unread messages. On a busy day, I often open the app, see that the mail is not important and come back later, but with the alert gone, I am often deceived into believing I have nothing to read. The iPhone native mail client got it right - keep the number of unread messages always consistent with the actual unread messages inside, neatly updated every time you read something through the web browser (if you used IMAP/Exchange). On a minor note, usability hasn&#39;t been thought through - if you have a back button and you are in the inbox of one account, with other accounts also configured, what do you expect to happen when you click on back button? On iPhone it goes to the page listing all your accounts so you can go to one of the other accounts - intuitive, very intuitive. On Galaxy S, it exits the app itself. To go to one of the other accounts, click menu, then accounts and then you get list of accounts.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;Usability of browser. Imagine you have been clicking around links and now you want to close the browser. How do you do it? On the iPhone you clicked home and you are done. On Android, you click back (which closes other apps) and you go to the previous page. So, you need to track back your entire browsing history to close it. Or you click home, leaving the browser running in the background, then go to app manager and then mark it closed. This was a big bummer.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;Mutiple Calendar fail. One of the reasons I wanted Android was because of the full exchange support for multiple exchange accounts. Turns out they can&#39;t handle multiple calendar accounts, even if those calendars are all hosted on Gmail. This was again, a rather big bummer.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;Widget/Calendar usability. You would imagine that a widget holding weather and stock information which comes default packaged with the phone would show you the current weather and stock information, right? Wrong. The widget sits right there with the information from the day you last refreshed it. If you want to update it, you have to click refresh. Now, who the hell was smoking cheap pot when designing this feature? Also, what is it with Calendar not notifying me when a meeting or appointment is due? iPhone did it neatly with an alert, but Android seems to do nothing of the sort. There is a tiny little message on the top, but if you didn&#39;t open the phone, you wouldn&#39;t get to know.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;Contacts usability. I was using the iPhone to sync my contacts to Gmail. And on the web interface, I had filtered the contacts using groups such that only the most important and relevant would come on the phone (using &quot;My Contacts&quot;). In fact, in anticipation of buying an Android, I had spent hours organizing the groups to my best convenience - and guess what? The OS built by Google doesn&#39;t support the groups running on Google&#39;s gmail interface. In fact, the entire concept of groups is thrown off on Android&#39;s contacts app. If that wasn&#39;t bad enough, try updating an existing contact with a number from which you just received a call. On that interface alone, &quot;search&quot; is disabled. So, Android expects me to browse from 1000s (which is actually only 100s if the phone respected the groups that I created on Gmail) of contacts to update the contact. Absolute FAIL. It is so bad (and error prone) that I have stopped updating contacts using the phone and instead do it through the laptop when I get the chance.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;3G/2G switching. You would think that you, as a techie, knowing that 3G meant &quot;faster internet but more battery consuming&quot; and 2G, aliased as GPRS, meant &quot;slower internet but less battery consumption&quot;, were learned enough to switch between the two on the Android, right? Wrong. You also need to know that 2G is &quot;GSM only&quot; and 3G is &quot;WCDMA&quot; and that &quot;GSM/WCDMA (auto)&quot; means auto switching between the two. Unfortunately, I did not. So, I couldn&#39;t figure out how to switch off my 3G to save battery. And after clicking on the GSM only mode (because I thought my phone was GSM and not a CDMA one), I couldn&#39;t figure out why my phone wouldn&#39;t run 3G. It took some wikipediaing to figure out that &lt;a href=&quot;http://en.wikipedia.org/wiki/W-CDMA_(UMTS)&quot;&gt;WCDMA meant 3G&lt;/a&gt;. Big big FAIL.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;VoIP. For some strange reason, Skype is listed on Android market place, but only for phones sold on Verizon network in the US. Tried it on my phone&#39;s market app. Nothing turns up. Tried a few other methods. Then eventually tried installing it through back door entry (download APK, put it on dropbox and then install, as suggested by &lt;a href=&quot;http://twitter.com/jasonong/status/22329652204&quot;&gt;@jasonong&lt;/a&gt;), but it was a skype lite feature which wants me to pay for receiving calls on the phone while my Skype app is running. It is rather sad to read articles which talk about the &lt;a href=&quot;http://www.zdnet.com/blog/btl/the-dirty-little-secret-about-google-android/38260&quot;&gt;dirty little secret of Android&lt;/a&gt; and realizing that it could all be true (and that I am contributing to it) and in the name of openness, we might be handing the power back to the very same companies who couldn&#39;t innovate a proper smart phone.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #38761d;&quot;&gt;Background Apps. It is good to have the feature.&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt; At least half the world has been singing a positive song about it - except that I can&#39;t seem to figure out why to use it? I was really happy with my iPhone usage and never felt the need to have background apps except for VoIP. Now that VoIP support isn&#39;t state-of-the-art (without skype), background apps looks like a superfluous feature. I am yet to use it. (In the meanwhile, I am seething that iPhone 4 has both background apps and state-of-the-art VoIP.)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #990000;&quot;&gt;The whole marketplace tyranny issue. If Apple has been criticized from running a tightly controlled App Store, then Google should also be criticized for running a haphazard app store. There are apps for one provider but not for others (i.e. skype). There are also apps whose reviews will tell you how it works on one device and not other. The democrat in me (wanting an open marketplace) is losing left right and center to the user in me (one who wants the apps to just be available and work).&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;In summary, Galaxy S is reasonably good hardware, but with Android&#39;s usability, and the phone&#39;s usability in general, being average at best, specially if you are coming from the iPhone experience (even an old iPhone OS experience) you might feel disappointed. The &quot;open&quot; Android isn&#39;t as usable as the &quot;closed&quot; iPhone. And in general, the $110 you are bound to save is just not worth the money.&lt;br /&gt;
&lt;br /&gt;
[Update: Read &lt;a href=&quot;http://tech.shreeni.info/2011/04/buying-my-second-android-phone.html&quot;&gt;follow up post&lt;/a&gt; written after buying a second Android phone]&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech.shreeni.info/feeds/2071935087158369674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tech.shreeni.info/2010/09/my-humble-take-on-android-vs-iphone.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/2071935087158369674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3426163161769571834/posts/default/2071935087158369674'/><link rel='alternate' type='text/html' href='http://tech.shreeni.info/2010/09/my-humble-take-on-android-vs-iphone.html' title='My Humble Take on Android vs iPhone'/><author><name>Shreeni</name><uri>http://www.blogger.com/profile/08742144807675237049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WMWZHKDQC2DAfc31_j_EAoSyNbc6VZGjwbhCjqGGD25iE9F7DzoM0TY3Kbbi7u7QS0NzADqN7n6F_m_YsIQQiknuaXx2rO6qF430ArK4N-IHSmK5tl0RZ5nR-S8v9u2k5kYcxQgcgtnILIxcLdQ0KpUkH-72GYaUdJDu8DXK8Vw/s220/2021-12%20Semi%20Formal%20with%20Tie%20and%20Jacket.jpeg'/></author><thr:total>4</thr:total></entry></feed>