<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Char's Blogophone</title>
	
	<link>http://www.charlesaylward.net</link>
	<description>Break it until it's fixed</description>
	<pubDate>Tue, 10 Nov 2009 05:04:39 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/CharsBlogophone" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>MySQL-centric memcached warming</title>
		<link>http://feedproxy.google.com/~r/CharsBlogophone/~3/uFi5-zUeJw8/14</link>
		<comments>http://www.charlesaylward.net/archives/14#comments</comments>
		<pubDate>Sat, 08 Mar 2008 09:02:31 +0000</pubDate>
		<dc:creator>Charles Aylward</dc:creator>
		
		<category><![CDATA[Databases]]></category>

		<category><![CDATA[Performance]]></category>

		<category><![CDATA[cache warming]]></category>

		<category><![CDATA[libmemcached]]></category>

		<category><![CDATA[memcached]]></category>

		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.charlesaylward.net/blog/archives/14</guid>
		<description><![CDATA[Situation:
You&#8217;re using memcached to, among other things, cache information from a MySQL database.
Problem:
There are many clients who read and write to this database but only some of them use memcached. Therefore, not everyone can keep the cache sync&#8217;d when updating database values.  Those that do use memcached need a current view of certain data, [...]]]></description>
			<content:encoded><![CDATA[<h3>Situation:</h3>
<p>You&#8217;re using memcached to, among other things, cache information from a MySQL database.</p>
<h3>Problem:</h3>
<p>There are many clients who read and write to this database but only some of them use memcached. Therefore, not everyone can keep the cache sync&#8217;d when updating database values.  Those that do use memcached need a current view of certain data, that is, they will react poorly to stale cache.  Anndddd&#8230;. setting the cache record expirations low enough to solve the &#8220;staleness problem&#8221; defeats the benefit of caching in the first place (we&#8217;re back to lots of DB chatter).</p>
<h3>Solution:</h3>
<p>Install Patrick Galbraith and Brian Aker&#8217;s <a href="http://tangent.org/586/Memcached_Functions_for_MySQL.html">memcached UDFs</a> for MySQL and set up exploitive triggers to keep the cache both warm <em>and</em> current&#8230; downright hot hot hot!  *ksssss*</p>
<h3>Quick HOW-TO:</h3>
<p><span id="more-14"></span><br />
<strong>What you&#8217;ll need:</strong></p>
<ul>
<li>The latest <a href="http://tangent.org/552/libmemcached.html">libmemcached</a>.</li>
<li>The latest <a href="http://tangent.org/586/Memcached_Functions_for_MySQL.html">memcached functions for MySQL</a>.</li>
<li>Actually, that&#8217;s it since I&#8217;m assuming you already have <a href="http://www.mysql.com/">MySQL</a>, <a href="http://danga.com/memcached/">memcached</a>, some memcached clients, and the basic knowledge of how they work&#8230; otherwise you wouldn&#8217;t have my problem.</li>
</ul>
<p><strong>Build and install libmemcached:</strong></p>
<p>This is just standard operating procedure for installing a dynamically linked library.</p>
<p><strong>Build and install the memcached MySQL UDF:</strong></p>
<p>If you&#8217;ve never installed a <a href="http://dev.mysql.com/doc/refman/5.1/en/adding-functions.html">MySQL UDF</a> before, this could require some reading.  The README in the package is good but if you want an excerpt just to get it installed quickly as to get on with this how-to:</p>
<blockquote><p>To build:<code>
<pre>
./configure \
  --with-mysql=/usr/local/mysql/bin/mysql_config \
  --libdir=/usr/local/mysql/lib/mysql/
make
make install
</pre>
<p></code><br />
Please keep in mind that for your UDF to be loaded, it must be in the<br />
library path for your server (and yes, we should fix this). On Linux you can<br />
set this by exporting the correct path in LD_LIBRARY_PATH for your mysql<br />
server.
</p></blockquote>
<p><strong>Set up the basic UDFs memc_servers_set(), memc_set(), memc_get(), and memc_delete() in MySQL:</strong><br />
<code>
<pre>
CREATE FUNCTION memc_servers_set RETURNS INT SONAME "libmemcached_functions_mysql.so";
CREATE FUNCTION memc_set RETURNS INT SONAME "libmemcached_functions_mysql.so";
CREATE FUNCTION memc_get RETURNS STRING SONAME "libmemcached_functions_mysql.so";
CREATE FUNCTION memc_delete RETURNS INT SONAME "libmemcached_functions_mysql.so";
</pre>
<p></code><br />
These are the only functions you&#8217;ll need for this how-to but you might want to load them all (see the README).</p>
<p><strong>Create triggers to update your cache when particular tables are updated:</strong></p>
<p>So far we&#8217;ve only been doing prep. work.  Now for the fun part&#8230;  </p>
<p>For this example, I&#8217;ve set up five memcached servers on my local machine on TCP and UDP ports 11411 - 11415.  Now, let&#8217;s pretend that I want to access <em>important_data</em> for <em>username</em> in the <em>cache_test</em> table by the memcached key &#8220;imp:&lt;username&gt;&#8221;.  I want the cache to be refreshed any time a row is inserted or updated and I want the key removed when the related row is deleted from the database.</p>
<p>To create the table we&#8217;re going to play with:<code>
<pre>
CREATE TABLE cache_test (
  username VARCHAR( 32 ) NOT NULL,
  important_data VARCHAR( 255 ),
  PRIMARY KEY ( username )
) ENGINE=MyISAM;
</pre>
<p></code></p>
<p>To set the memcached servers we want to use (this only needs to be set once):<code>
<pre>
SELECT memc_servers_set( '127.0.0.1:11411,127.0.0.1:11412,127.0.0.1:11413,127.0.0.1:11414,127.0.0.1:11415' );
</pre>
<p></code></p>
<p>To create the related triggers, your user will need the TRIGGER and/or the SUPER privileges depending on the version of MySQL you&#8217;re running.  You can&#8217;t create a trigger that returns a result, but there&#8217;s nothing stopping you from just storing the result somewhere else.  Here are the statements to create the triggers:<br />
<code>
<pre>
DELIMITER |

CREATE TRIGGER cache_test_warmer_insert
  AFTER INSERT ON cache_test
  FOR EACH ROW BEGIN
    SET @memc_rc:= memc_set( CONCAT( "imp:", NEW.username ), NEW.important_data );
  END; |

CREATE TRIGGER cache_test_warmer_update
  AFTER UPDATE ON cache_test
  FOR EACH ROW BEGIN
    SET @memc_rc:= memc_set( CONCAT( "imp:", NEW.username ), NEW.important_data );
  END; |

CREATE TRIGGER cache_test_cooler
  AFTER DELETE ON cache_test
  FOR EACH ROW BEGIN
    SET @memc_rc:= memc_delete( CONCAT( "imp:", OLD.username ) );
  END; |

DELIMITER ;
</pre>
<p></code></p>
<p>That&#8217;s it.  Let&#8217;s test it out!  Let&#8217;s insert some records into the table:<code>
<pre>
mysql>
mysql> INSERT INTO cache_test ( username, important_data )
    -> VALUES
    -> ( 'zaphod', 'no ego' ),
    -> ( 'charles', 'hides money under his bed' ),
    -> ( 'zilton', 'drinks kool-aid with no sugar' );
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql>
</pre>
<p></code><br />
&#8230; and then check the cache:<code>
<pre>
(caylward@barghest):~/local/libmemcached/bin$ ./memcat imp:zilton
drinks kool-aid with no sugar
(caylward@barghest):~/local/libmemcached/bin$ ./memcat imp:charles
hides money under his bed
(caylward@barghest):~/local/libmemcached/bin$
</pre>
<p></code><br />
Now that hopefully you believe that this is actually working, the rest of the example will just use the MySQL client:<code>
<pre>
mysql> UPDATE cache_test SET important_data = "can't write for beans"
    -> WHERE username = 'charles';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>
mysql> SELECT memc_get( 'imp:charles' );
+---------------------------+
| memc_get( 'imp:charles' ) |
+---------------------------+
| can't write for beans     |
+---------------------------+
1 row in set (0.00 sec)

mysql>
mysql> DELETE FROM cache_test WHERE username = 'charles';
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> SELECT memc_get( 'imp:charles' );
+---------------------------+
| memc_get( 'imp:charles' ) |
+---------------------------+
| NULL                      |
+---------------------------+
1 row in set (0.00 sec)
</pre>
<p></code></p>
<p>There ya go.  Piping hot memcached.  :)</p>
<p>There are however a few caveats to all of this:</p>
<ul>
<li>This is all basically using alpha software so normal paranoia applies here.</li>
<li>The list of memcached servers to use needs to be set any time the database is restarted.</li>
<li>Trying to change the list of memcached servers more than once should be possible but does not behave correctly (possible bug I&#8217;m looking into).</li>
<li>
</ul>
<p>Good luck!</p>
<p>End of transmission.</p>
<img src="http://feeds.feedburner.com/~r/CharsBlogophone/~4/uFi5-zUeJw8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.charlesaylward.net/archives/14/feed</wfw:commentRss>
		<feedburner:origLink>http://www.charlesaylward.net/archives/14</feedburner:origLink></item>
		<item>
		<title>Error messages shouldn’t happen</title>
		<link>http://feedproxy.google.com/~r/CharsBlogophone/~3/FkhMBzr1dp8/4</link>
		<comments>http://www.charlesaylward.net/archives/4#comments</comments>
		<pubDate>Wed, 04 Jul 2007 03:10:46 +0000</pubDate>
		<dc:creator>Charles Aylward</dc:creator>
		
		<category><![CDATA[User Interfaces]]></category>

		<guid isPermaLink="false">http://www.charlesaylward.net/blog/archives/4</guid>
		<description><![CDATA[This applies to consumer electronics, shrink wrap software, and even web applications.  Apple gets it, Google usually gets it, but very few others do (or at least not consistently).  It&#8217;s a very easy mistake to make.
Basically, error messages are only to be seen by software developers.  Exceptions should be reserved for a [...]]]></description>
			<content:encoded><![CDATA[<p>This applies to consumer electronics, shrink wrap software, and even web applications.  Apple gets it, Google usually gets it, but very few others do (or at least not consistently).  It&#8217;s a very easy mistake to make.</p>
<p>Basically, error messages are only to be seen by software developers.  Exceptions should be reserved for a very small number of situations.  One is field (form) validation. Someone was supposed to enter a credit card number but didn&#8217;t. An email address was required but something that doesn&#8217;t resemble one was provided.  In other words, a key element in some transaction.  Another appropriate time is during absolute errors when you simply cannot complete a task like when the network is down (but even then there are graceful ways to handle that, like queuing up the operation&#8230; offline operating modes, etc).</p>
<p>It should never happen when the user is <em>navigating</em> your user interface &#8212; period(.)  Even when your user is trying to complete an action that requires more information on their part, it should not happen. When you are down in the crux of some code, it&#8217;s easy to get into the habit of thinking in terms of exceptions / errors when you don&#8217;t have enough information, but you should never throw the equivalent of these at your end users. If you are writing a user interface and you feel like it&#8217;s time for you to bring up an error message dialog box / widget / whatever, stop. Chances are it&#8217;s the wrong thing to do.  No, really, you need to take a step back.<br />
<span id="more-4"></span><br />
Ask yourself, is this message basically telling the user &#8220;you didn&#8217;t do it right, try again&#8221;? It doesn&#8217;t matter what the user was trying to do, telling them they aren&#8217;t doing it right is nothing short of infuriating.  (Has anyone here tried using Windows?)  More often than not, wherever the user is in your interface, there is enough contextual information for you to help the user do the right thing without them even knowing they are &#8220;doing something wrong&#8221;.</p>
<p>Example: If I am writing a text message on my cell phone and hit the button for &#8220;send&#8221;, and I haven&#8217;t entered a recipient, I should not get an error message telling me that I need to enter a recipient. It&#8217;s clear to every turnip using a cell phone that messages need at least one recipient. My intentions are clear. What should you do to help me send this message? Probably bring up my list of contacts.  Don&#8217;t tell me that the way I&#8217;m attempting to do something simple like send a text message is wrong.</p>
<p>It&#8217;s pretty clear in the example above which is the better solution.  If you analyze your interface in this way (what&#8217;s the user&#8217;s intention when I feel that I should be writing an error message? what do they still need to do to accomplish it?) and figure out how to help users instead of insult them, they will love you for it.  If you try this method and it seems that you&#8217;re getting lost in a never ending matrix of what input is still needed and what isn&#8217;t, then you probably need to redesign the whole interface.</p>
<p>Ok, that may be a bit harsh.  Perhaps forcefully move the user through a series of steps rather than giving them a whole bunch of ways to do something where some paths are wrong.  I would rather have fewer choices on an interface if it means the interface doesn&#8217;t need to yell at me.  If it still seems too complicated, it might mean that you have picked the wrong organizational units&#8230; your grouping the wrong items together&#8230; or your trees don&#8217;t have the right roots.</p>
<p>The example I gave above happens to be common on cell phones.  Instead of having a big swamp of text fields and check boxes for each outgoing / incoming message and then still have to code a text message folder navigation menu anyway, they could instead start out by binding text messages to contacts directly in say a thread format (or even just sequentially).  It&#8217;s a phone!  So most things are related to communicating with others, right?  So, why not bind all communiquÃ© to or from the contact in question&#8230; to the contact directly from the get go?</p>
<p>(I started writing this before the iPhone came out but didn&#8217;t post it until afterwards.  Again, because Apple gets this, it&#8217;s why people drool over an Apple iPhone but not over a Samsung SGH-AXYZ-123 or whatever)</p>
<p>Don&#8217;t tell your users that they are doing it wrong.  If you find yourself writing code that tells them so, take a step back and figure out what it is that <em>you</em> are doing wrong.</p>
<img src="http://feeds.feedburner.com/~r/CharsBlogophone/~4/FkhMBzr1dp8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.charlesaylward.net/archives/4/feed</wfw:commentRss>
		<feedburner:origLink>http://www.charlesaylward.net/archives/4</feedburner:origLink></item>
		<item>
		<title>Key considerations for network software</title>
		<link>http://feedproxy.google.com/~r/CharsBlogophone/~3/1b8PH1ZwVd4/6</link>
		<comments>http://www.charlesaylward.net/archives/6#comments</comments>
		<pubDate>Sat, 23 Jun 2007 03:12:58 +0000</pubDate>
		<dc:creator>Charles Aylward</dc:creator>
		
		<category><![CDATA[Networks]]></category>

		<guid isPermaLink="false">http://www.charlesaylward.net/blog/archives/6</guid>
		<description><![CDATA[Below are just a few of the things I remember to ask myself when either writing code, requirements, or specifications for network software.  The answers to these vary wildly depending on the project.  The answers are usually very simple and simple to implement as well.  Big problems almost always arise, however, when [...]]]></description>
			<content:encoded><![CDATA[<p>Below are just a few of the things I remember to ask myself when either writing code, requirements, or specifications for network software.  The answers to these vary wildly depending on the project.  The answers are usually very simple and simple to implement as well.  Big problems almost always arise, however, when the questions aren&#8217;t asked.  It&#8217;s easy to forget that networks by their very nature are not 100% reliable or that, at some point, services remote to you will flap or be cycled for maintenance reasons.  Failing to take these considerations into account usually leads to embarrassing questions and a headache&#8230; and a lot of extra work by you or someone else down the road in reimplementation or complicated and error-prone upgrade / maintenance procedures.<br />
<span id="more-6"></span><br />
<strong>What happens when initiating a connection fails?</strong><br />
Do you retry?  How many times?  With what delay?  Remember that if your software is actually successful (always plan for success), it might be deployed many times on one network.  You don&#8217;t want a network flap to trigger an internal DDoS of another possibly more central service.  Do you implement an exponential backoff?  If you are retrying, do you block other like jobs?  Do you stick the job in a queue, continue, and come back later?</p>
<p><strong>What happens when a connection dies?</strong><br />
This one is mostly the same as the one above except you might have been half way through an action.  So, are you using transactions?  If the datasource isn&#8217;t transactional, are you making sure to clean up and start over?  Continue where you left off?</p>
<p><strong>What happens if the network is simply very slow or has high latency?</strong><br />
This one can be tricky as it&#8217;s not an easily recognized error condition or might not be one at all, but one should think about it.</p>
<p><strong>How is redundancy / replication handled?</strong><br />
These ones are closer to things that would be put in the requirements in the first place.  I&#8217;d argue that these should always be in ones mind however.  Always plan for wild success, right?  ;)  Can it be redundant by adding more servers?  Simply, can multiple instances run on different machines?  Whereâ€™s state stored?  How is state shared?  Pretty easy questions to answer if you&#8217;re writing a web app on, say, Tomcat.</p>
<p><strong>How is load balanced?</strong><br />
This ties in with the one above.  Always assume that someone will actually want to use your software (right? hah!) and therefore scale their deployment of it.  Use round-robin DNS (generally weak)?  Use DNS and iterate over records yourself based on some criteria?  Implement DNS SRV records to do that?  Go big and buy load balancers?</p>
<p><strong>Is it easy to upgrade?</strong><br />
Usually, if you&#8217;ve answered the redundancy / replication questions, a rolling upgrade is easy to plan.</p>
<p><strong>How is the configuration stored?</strong><br />
Are they separate and centralized?  Separate meaning do different components have their own configs or share one big one?  Centralized meaning are they located in the same spot in the same manner?  When is it read?  Can it be gracefully reloaded without restarting the service?  Is it validated fully <i>before</i> being loaded or acted upon?  This doesn&#8217;t just mean that the formatting is correct or that each field has a value.  Input constraints apply here too&#8230; is that integer in the right range?  Does that string have an invalid character?  Is it stored securely?</p>
<p><strong>How do you log?</strong><br />
Ok&#8230; this doesn&#8217;t have to do with network software exactly but I&#8217;m throwing it on here too.  Files?  Syslog facilities?  Do you have well defined logging levels?  This one gets skipped a lot because we all feel that we have a pretty good idea about what&#8217;s a debug, fine, info, config, warning, or critical message.  The problem is that each person has a different versions of that list.  Make sure everyone on the project is using the same scheme.  It can be kept simple.  Are log entries meaningful to those not familiar with the code or the protocols used?  Developers are often not the people eventually running the software.  An operations group at another company or different department might be.  Even with effort, this one is hard to get right&#8230; just ask around if the messages make sense.  Maybe ask someone from HR or marketing&#8230;  :)</p>
<p><strong>Is input always validated for all methods?</strong><br />
Constraints!  Have them&#8230; and check them!  This one is also pretty general.  Did one of those pesky null pointers get passed over?  What happens if someone passes in a negative number and that doesn&#8217;t make sense?  Is there only a certain range that makes sense?  These checks sometimes don&#8217;t get done for fear of introducing &#8220;magic numbers&#8221; into your code.  Everyone hates magic numbers in code but sometimes they are necessary&#8230; just make sure they are used wisely and commented.  An example might be a method that creates a pool of connections.  The number of connections in the pool is passed in as an integer variable.  Someone might want to create a huge pool of connections later down the road for some weird reason&#8230; but it probably never makes sense to go completely unchecked and let the value 4,294,967,295 get passed in&#8230; or -1 for that matter.</p>
<img src="http://feeds.feedburner.com/~r/CharsBlogophone/~4/1b8PH1ZwVd4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.charlesaylward.net/archives/6/feed</wfw:commentRss>
		<feedburner:origLink>http://www.charlesaylward.net/archives/6</feedburner:origLink></item>
	</channel>
</rss>
