<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title> &#187; Databases</title>
	<atom:link href="http://googolflex.com/?feed=rss2&#038;cat=14" rel="self" type="application/rss+xml" />
	<link>http://googolflex.com</link>
	<description></description>
	<lastBuildDate>Fri, 06 Aug 2010 18:46:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>MySQL Master-Master Replication</title>
		<link>http://googolflex.com/?p=542</link>
		<comments>http://googolflex.com/?p=542#comments</comments>
		<pubDate>Tue, 09 Feb 2010 16:34:16 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[master-master]]></category>
		<category><![CDATA[replication]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=542</guid>
		<description><![CDATA[In my opinion, having dual-writable master MySQL databases (in a replication configuration) is not worth the hassle.  There are a host of problems, enough that you should seriously consider what you&#8217;re trying to gain when attempting it.  However, the master-master replication scheme still has some very good uses when used in an active-passive [...]]]></description>
			<content:encoded><![CDATA[<p>In my opinion, having dual-writable master MySQL databases (in a replication configuration) is not worth the hassle.  There are a host of problems, enough that you should seriously consider what you&#8217;re trying to gain when attempting it.  However, the master-master replication scheme still has some very good uses when used in an active-passive way.  The two most compelling reasons for me are:</p>
<p>1. Keeping a &#8220;hot spare&#8221;.  You have an additional database already configured as a master.  This might not seem like much, since you &#8220;almost&#8221; gain the same thing in a master-slave setup.  However, if your master-master includes slave servers, this topology provides a very high degree of fault tolerance.  Especially when each master-server pair is geographically separated.</p>
<p>2. Making changes to the database.  Certain changes made to the database may require a long time to complete, particularly if you have a very large database.  In the master-master setup, you can take one of the servers &#8220;offline&#8221; (by telling the other master not to replicate its changes), and make the changes necessary.  Then bring it back online, after the changes have been made, make it the active master, and let the other master perform the changes.</p>
<p>This could be seen as an added benefit of keeping a &#8220;hot spare&#8221;.</p>
<p>The good news is that setting this up is identical to setting up master-slave replication, you simply do it twice.  Each master is essentially the master of and a slave to the other database.  To keep it active-passive, one of the databases will need to be made read-only.  Here are the changes you will need to the my.cnf configuration file:</p>
<p><strong>Active Master my.cnf</strong></p>
<pre class="brush: bash;">
log_bin = mysql-bin
server_id = 1001
relay_log = mysql-relay-bin
log_slave_updates = 1
</pre>
<p><strong>Passive Master my.cnf</strong></p>
<pre class="brush: bash;">
log_bin = mysql-bin
server_id = 1002
relay_log = mysql-relay-bin
log_slave_updates = 1
read_only = 1  # Notice this line
</pre>
<p>Then set up the replication user accounts, as described in this post: <a href="http://googolflex.com/?p=518">Simple MySQL Master-Slave Replication</a></p>
<p>Finally you issue the slave directives, and start the slave process:</p>
<p><strong>Active Master &#8216;change master&#8217;</strong></p>
<pre class="brush: bash;">
# Active master is slave to passive host
CHANGE MASTER TO MASTER_HOST='passive.mysql.host',
MASTER_USER='rep_user',
MASTER_PASSWORD='reppassword',
MASTER_LOG_FILE='mysql-bin-000001',
MASTER_LOG_POS=0;

start slave;
</pre>
<p><strong>Passive Master &#8216;change master&#8217;</strong></p>
<pre class="brush: bash;">
# Passive master is slave to active host
CHANGE MASTER TO MASTER_HOST='active.mysql.host',
MASTER_USER='rep_user',
MASTER_PASSWORD='reppassword',
MASTER_LOG_FILE='mysql-bin-000001',
MASTER_LOG_POS=0;

start slave;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=542</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple MySQL Master-Slave Replication</title>
		<link>http://googolflex.com/?p=518</link>
		<comments>http://googolflex.com/?p=518#comments</comments>
		<pubDate>Sat, 06 Feb 2010 21:33:03 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[master-slave]]></category>
		<category><![CDATA[replication]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=518</guid>
		<description><![CDATA[I&#8217;ve been doing a lot of research (not cutting edge type stuff) into MySQL scalability, and the first exercise I went through was configuring a simple master-slave replication setup.  It was much simpler than I thought it would be.  Here are the steps.

Editing the my.cnf Files
Because of the way replication works in MySQL, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been doing a lot of research (not cutting edge type stuff) into MySQL scalability, and the first exercise I went through was configuring a simple master-slave replication setup.  It was much simpler than I thought it would be.  Here are the steps.</p>
<hr />
<strong><u>Editing the my.cnf Files</u></strong></p>
<p>Because of the way replication works in MySQL, you will need to turn on binary logging.  Essentially, the slave is going to connect to the master and request the log.  After it gets the log (or the parts that it needs) it will replay it, executing the queries to bring it up to date.  You also need to give the server an ID.  So add these lines to the my.cnf (usually /etc/my.cnf) on the master database:</p>
<pre class="brush: bash;">
&amp;lt;mysqld&amp;gt;
log_bin = mysql-bin
server_id = 1001
</pre>
<p>You can give it any ID you want, you just want it to have a different ID than the slave.  In the slave we will add a few additional lines, as well:</p>
<pre class="brush: bash;">
&amp;lt;mysqld&amp;gt;
log_bin = mysql-bin
server_id = 1002
relay_log = mysql-relay-bin
log_slave_updates = 1
read_only = 1
</pre>
<p>Note: Replace the angle brackets above with square brackets.  I haven&#8217;t figured out how to make my code plugin not treat [mysqld] as another code block definition.</p>
<p>According to Schwartz, et al. in <em>High Performance MySQL</em> (review forthcoming), the only parameter required on a slave is the server_id.  The other parameters make it easy to switch the server between being a master or a slave.  They also mention the read_only parameter is a good safety precaution but might not be applicable in all cases.</p>
<hr />
<strong><u>User Account Setup</u></strong></p>
<p>Replication privileges need to be granted to the replication user on the master.  If you want to be able to easily switch your server between master or slave, you can grant these privileges on both servers.</p>
<pre class="brush: sql;">
GRANT REPLICATION SLAVE
ON *.*
TO 'rep_user'@'10.0.0.%'
IDENTIFIED BY 'reppassword';
</pre>
<p>There are certain features that are accessible by granting the <code>REPLICATION CLIENT</code> privilege.  You can also limit the replication privileges to only certain databases or tables if so desired.  Though it is not recommended, you could also grant access to all hosts, just as you might in any other GRANT statement.</p>
<hr />
<strong><u>Starting the Replication Procedure</u></strong></p>
<p>Now that both the master and slave are configured, and correct permissions are granted to the replication user, the slave needs to be &#8220;started&#8221;.  This is done by declaring the master host, and indicating necessary credentials and log file information, and then issuing the &#8217;start slave&#8217; command.</p>
<p>The host and credential information can be declared in the my.cnf file.  However there are some advantages to making the declarations as MySQL commands.  Specifically you will be able to make changes to these without having to restart the daemon.  Here is the command you should issue to configure the slave:</p>
<pre class="brush: sql;">
CHANGE MASTER TO MASTER_HOST='master.mysql.host',
MASTER_USER='rep_user',
MASTER_PASSWORD='reppassword',
MASTER_LOG_FILE='mysql-bin-000001',
MASTER_LOG_POS=0;
</pre>
<p>And then you issue the command to start the slave:</p>
<pre class="brush: sql;">start slave</pre>
<p>If you were previously using binary logs on the master, and then cloned the server to create the slave, you might have trouble getting replication started without first deleting the binary log from the slave.</p>
<p><strong><u>Sources</u></strong><br />
<a href="http://dev.mysql.com/doc/refman/5.1/en/replication-howto.html">The MySQL documentation</a><br />
<em>High Performance MySQL</em>, by Baron Schwartz et al.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=518</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache mod_proxy_balancer Self Registration : Part 3</title>
		<link>http://googolflex.com/?p=507</link>
		<comments>http://googolflex.com/?p=507#comments</comments>
		<pubDate>Thu, 04 Feb 2010 22:25:51 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Shell Scripting]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[load balancing]]></category>
		<category><![CDATA[mod_proxy_balancer]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[self registration]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=507</guid>
		<description><![CDATA[I&#8217;ll start off by going over the basic high level architecture for my self registration procedure:
There is a register.php script residing on the load balancer, accessible via HTTP.
There is a deregister.php script residing on the load balancer, accessible via HTTP.
There is a register_with_lb.pl script residing on the web server, in /usr/local/bin/.
There is a deregister_with_lb.pl script [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ll start off by going over the basic high level architecture for my self registration procedure:</p>
<p>There is a register.php script residing on the load balancer, accessible via HTTP.<br />
There is a deregister.php script residing on the load balancer, accessible via HTTP.<br />
There is a register_with_lb.pl script residing on the web server, in /usr/local/bin/.<br />
There is a deregister_with_lb.pl script residing on the web server, in /usr/local/bin/.<br />
There is a MySQL database that stores the current configuration state, on it are two stored procedures register_lb and deregister_lb.</p>
<hr/>
<strong>register.php</strong></p>
<p>No changes were made to register.php as described in this <a href="http://googolflex.com/?p=494">post </a>, though I&#8217;m considering some alterations to increase its security.</p>
<hr/>
<strong>deregister.php</strong></p>
<p>The biggest difference between register.php and deregister.php (aside from their purpose) is where the insert/delete database code is called from and why.  When register.php is called by the web server, it will have already inserted information about itself into the database, including its hash.  I made the decision that I did not want the load balancer responsible for inserting servers into the database.  It would merely check that the requesting server inserted itself, and then regenerate the balancer_members.conf.</p>
<p>In the case of deregister.php I decided I wanted the server making the call to still be in the database so the script could verify the identity before removing it and regeneration the balancer_members.  And since the deregistration SQL is contained within a stored procedure, I needed to make some changes to the script (as compared to register.php) regarding the database.</p>
<p>Specifically, the standard mysql library cannot call stored procedures.  So I had to convert it to using mysqli, which is a similar, though more OO approach.  The portion of the code that regenerates the balancer_members.conf is similar enough that I won&#8217;t re-list it here, but I will show how to connect using mysqli, and how to call a stored procedure.</p>
<pre class="brush: php;">
$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
if (mysqli_connect_errno()) {
  printf(&quot;Connect failed: %s\n&quot;, mysqli_connect_error());
}

$query = &quot;SELECT count(*) as count FROM &quot; . $dbtable . &quot; WHERE ip='&quot; . $_SERVER['REMOTE_ADDR'] . &quot;';&quot;;
$result = $mysqli-&gt;query($query);
$row = $result-&gt;fetch_row();
echo $row[0];

if ($row[0] &gt;= 1) {
  $del_query = &quot;call deregister_lb('&quot; . $_SERVER['REMOTE_ADDR'] . &quot;');&quot;;
  $del_result = $mysqli-&gt;query($del_query);

  //&lt;code for regenerating the conf file removed here&gt;

  echo exec('echo &quot;' . $file . '&quot; &gt; /etc/httpd/conf.d/balancer_members.conf');
  echo exec(&quot;sudo /usr/local/bin/reload_httpd&quot;);
}
</pre>
<p>As you can see, I&#8217;m using the actual REMOTE_ADDR to determine the validity of the request.</p>
<hr/>
<strong>(de)register_lb.sql Stored Procedure</strong></p>
<p>Here is the code for the deregister_lb stored procedure:</p>
<pre class="brush: sql;">
DROP PROCEDURE IF EXISTS deregister_lb $$

CREATE PROCEDURE deregister_lb ( ip VARCHAR(100) )
  BEGIN
    DELETE FROM lb2_members
	WHERE ip=_ip;
  END $$
</pre>
<p>and also for the register_lb stored procedure:</p>
<pre class="brush: sql;">
DROP PROCEDURE IF EXISTS register_lb $$
CREATE PROCEDURE register_lb (
  _hostname VARCHAR(100),
  _ip VARCHAR(40),
  _loadfactor INT,
  _hash VARCHAR(100)
  )

  BEGIN
    DECLARE already_exists INT DEFAULT 0;
    SELECT count(*) INTO already_exists FROM lb2_members WHERE hash=_hash;

    IF already_exists=1 THEN
	  UPDATE lb2_members
	  SET hostname=_hostname, ip=_ip, loadfactor=_loadfactor
	  WHERE hash=_hash;
    ELSE
      INSERT INTO lb2_members (ip, hostname, loadfactor, hash)
	  VALUES (_ip, _hostname, _loadfactor, _hash);
    END IF;
  END $$
</pre>
<p>Note that I&#8217;ve omitted the code that changes the delimiter to $$ instead of a semicolon.</p>
<hr />
<strong>register_with_lb.pl</strong></p>
<p>This perl script uses perl DBI for accessing the database.  I had to get that installed on my web server since it wasn&#8217;t already.  Normally you can install perl packages using the cpan command.  In which case you would issue the following commands to install DBI and a MySQL driver for it:</p>
<pre class="brush: bash;">
cpan DBI
cpan DBD::mysql
</pre>
<p>If it&#8217;s the first time you&#8217;ve run cpan, you will need to go through some configuration.  It&#8217;s pretty much self explanatory, and I just accepted all of the defaults.  Everything installed correctly except for the MySQL driver, which I ended up having to install from source.  If I had executed the command:</p>
<pre class="brush: bash;">yum install mysql-devel.i386</pre>
<p>first, then my cpan install of DBD::mysql might have worked, but I didn&#8217;t realize that until installing from source.  In case you ever need to install a perl module from source, particularly the DBD::mysql driver, enter these commands (which I think is basically what cpan does):</p>
<pre class="brush: bash;">
yum install mysql-devel.i386 #(only requred in this particular instance)
wget http://www.cpan.org/modules/by-module/DBD/DBD-mysql-4.011.tar.gz
gzip -cd DBD-mysql-4.011.tar.gz | tar xf -
cd DBD-mysql-4.011 #(or whatever version you downloaded)
perl Makefile.PL
make
</pre>
<p>Here is how you connect to the database and call a stored procedure:</p>
<pre class="brush: perl;">
my $dsn = &quot;DBI:mysql:host=mysql.host;database=lb_register&quot;;
my $dbh = DBI-&gt;connect ($dsn, &quot;lbuser&quot;, &quot;lbpasswd&quot;)
  or die &quot;Cannot connect to MySQL server\n&quot;;

my $sql = &quot;call register_lb('&quot; . $localhost . &quot;', '&quot; . $localip . &quot;', &quot; . $loadfactor . &quot;, '&quot; .  $hash . &quot;')&quot;;
$dbh-&gt;do($sql);

$dbh-&gt;disconnect();
</pre>
<p>After that, register_with_lb.pl opens a socket to the load balancer and makes an HTTP request over the socket.  There are probably easier ways to do this, I just happened to have the socket code lying around and was glad to be able to reuse it.  Here&#8217;s the gist of it, in case you&#8217;re interested:</p>
<pre class="brush: perl;">
# Parse the URI.
my $url = URI-&gt;new(&quot;http://load.balancer.com/register/register.php?hash=&quot; . $hash);

# Parse these in from the command line
$host = $url-&gt;host;
$port = $url-&gt;port;
$resource = $url-&gt;path;
$query = $url-&gt;query;

# Initialize the socket
$socket = IO::Socket::INET-&gt;new ( Proto =&gt; &quot;tcp&quot;, PeerAddr =&gt; $host, PeerPort =&gt; $port,);
unless ($socket) { die &quot;Error connecting to $host&quot; }
$socket-&gt;autoflush(1);

# Format the request
my $request = &quot;GET &quot; . $resource . (($query)?&quot;?&quot; . $query : &quot;&quot;) . &quot; HTTP/1.1&quot; . $EOL . &quot;Host: &quot; . $host . $EOL . &quot;User-agent: register_script&quot; . $EOR;

# Use send() to make the request, and output the response.
# Not necessary in this example, but informational.
if ( $socket-&gt;send($request) ) {
  while ( &lt;$socket&gt; ) { print }
}

# Close the socket
close $socket;
</pre>
<p>The above code pretty much sums up deregister_from_lb.pl, since no database calls are made, a call is simply made to the deregister script.  The line you would change is as follows:</p>
<pre class="brush: perl;">my $url = URI-&gt;new(&quot;http://my.balancer.com/register/deregister.php&quot;);</pre>
<p>Then make the files executable, and copy them to be used by the startup script described in the previous <a href="http://googolflex.com/?p=499">post</a>:</p>
<pre class="brush: bash;">
chmod a+x register_with_lb.pl
chmod a+x deregister_with_lb.pl
cp register_with_lb.pl /usr/local/bin/
cp deregister_with_lb.pl /usr/local/bin
</pre>
<p>I don&#8217;t show it here, but right now my IP addresses are hard coded.  There are a number of ways you can find out your actual IP address from within perl, I&#8217;m just not doing that right now.</p>
<hr/>
<strong>Securing the register scripts</strong></p>
<p>As an additional security measure, I&#8217;ve restricted access to the /register/ location on the load balancer to the IP address range I expect my web servers to be from, like this:</p>
<pre class="brush: bash;">
&lt;Location /register&gt;
  Order Deny,Allow
  Deny from all
  Allow from 10.0.0.
&lt;/Location&gt;
</pre>
<p>And now you have a web server that can register automatically (if you&#8217;ve gone through the previous two posts as well) with a mod_proxy_balancer load balancer.</p>
<hr/>
<strong>Update</strong></p>
<p>I did some searching around to find a way to determine your IP address from inside the perl script.  This is a simple way if your server has a public IP address and reverse DNS set up correctly for that IP address:</p>
<pre class="brush: perl;">
use Socket;
use Sys::Hostname;
my $host = hostname();
my $addr = inet_ntoa(scalar(gethostbyname($host)) || 'localhost');
</pre>
<p>If your slave web servers are on a private network, the above command will return the loopback IP address (127.0.0.1) which isn&#8217;t useful for the load balancer (I wonder if it would start an infinite loop and crash the load balancer?).  I found a function that prints out the IP address by parsing it out from the results of the ifconfig command.</p>
<p>It seemed a little long to just rip off and copy verbatim.  So here&#8217;s a link to that code (which is what I&#8217;m using now) in case you&#8217;d like to use it.    <a href="http://ubuntuforums.org/showthread.php?t=273433">Perl script to get IP address</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=507</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache mod_proxy_balancer Self Registration : Part 1</title>
		<link>http://googolflex.com/?p=494</link>
		<comments>http://googolflex.com/?p=494#comments</comments>
		<pubDate>Wed, 03 Feb 2010 20:39:12 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[load balancing]]></category>
		<category><![CDATA[mod_proxy_balancer]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[self registration]]></category>
		<category><![CDATA[Shell Scripting]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=494</guid>
		<description><![CDATA[Load balancers are great, but they become even more powerful when servers have the ability to self-register when they come online, and deregister when they go offline.  This is especially true with services such as EC2, when the size of the server group might grow or shrink in response to need.  This is [...]]]></description>
			<content:encoded><![CDATA[<p>Load balancers are great, but they become even more powerful when servers have the ability to self-register when they come online, and deregister when they go offline.  This is especially true with services such as EC2, when the size of the server group might grow or shrink in response to need.  This is a tutorial describing my particular (partially insecure at the moment) solution for allowing self-registration with Apache&#8217;s mod_proxy_balancer.  Specifically this covers the load balancer side of the equation.  Tomorrow I hope to get a post out describing the server side.</p>
<p>Here is my flowchart for how self registration will work:<br />
1. Server comes online.<br />
2. A startup script will register itself with the MySQL database (including hostname, ip, loadfactor, and a hash that it will generate in some way).<br />
3. The server will then call a PHP script on the load balancer: &#8220;register/register.php&#8221;.<br />
4. The PHP script will verify that a server sent the request.<br />
5. The PHP script will query the database to get the current list of balancer members, and regenerate the balancer_members.conf file.<br />
6. The PHP script will then issue a command to reload Apache&#8217;s configuration files.</p>
<p>Deregistration, which my PHP script as presented doesn&#8217;t display, will work as follows:<br />
1. Server sends its hash to the PHP script, and shuts down.<br />
2. The PHP script will check the hash against the database.<br />
3. The PHP script will remove the server from the database.<br />
4. The PHP script will repeat steps 5 and 6 above.</p>
<p>First, set up the database and created a user with sufficient privileges.</p>
<pre class="brush: sql;">
CREATE DATABASE lb_register;
GRANT ALL ON lb_register.* TO 'lbuser'@'%' IDENTIFIED BY 'password';

CREATE TABLE lb2_members(
ip VARCHAR(20) NOT NULL PRIMARY KEY,
hostname VARCHAR(100) NOT NULL,
loadfactor INT NOT NULL DEFAULT 0,
hash VARCHAR(40) );
</pre>
<p>Second, create the PHP script.</p>
<pre class="brush: php;">
$dbhost = &quot;mysql.host.com&quot;;
$dbuser = &quot;lbuser&quot;;
$dbpass = &quot;password&quot;;
$dbname = &quot;lb_register&quot;;
$dbtable = &quot;lb2_members&quot;;

$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die (mysql_error());
mysql_select_db($dbname);

$query = &quot;SELECT count(*) as count FROM &quot; . $dbtable . &quot; WHERE hash='&quot; . $_GET['hash'] . &quot;';&quot;;
$result = mysql_query($query);

$row = mysql_fetch_assoc(mysql_query($query));
if ($row['count'] &gt;= 1) {

  $file = &quot;&lt;Proxy balancer://mycluster&gt;&quot; . &quot;\n&quot;;
  $member_query = &quot;SELECT hostname, loadfactor FROM &quot; . $dbtable . &quot;;&quot;;
  $member_result = mysql_query($member_query);

  while ($row = mysql_fetch_array($member_result, MYSQL_BOTH)) {
    $file .= &quot;   BalancerMember http://&quot; . $row['hostname'] . &quot; &quot;;
    $file .= ($row['loadfactor'] &gt; 1) ? (&quot;loadfactor=&quot; . $row['loadfactor'] . &quot;\n&quot;) : &quot;\n&quot;;
  }
  $file .= &quot;&lt;/Proxy&gt;&quot;;

  exec('echo &quot;' . $file . '&quot; &gt; /etc/httpd/conf.d/balancer_members.conf');
  exec(&quot;sudo /usr/local/bin/reload_httpd&quot;);
}

mysql_close($conn);
</pre>
<p>You can tell a few things about the server configuration by looking at the script:<br />
1. User apache will need to be able to write to the &#8220;/etc/httpd/conf.d/balancer_members.conf&#8221; file.<br />
2. User apache will need to be able to execute the script &#8220;/usr/local/bin/reload_httpd&#8221;.<br />
3. User apache will need sudoer rights.<br />
4. This script was used for debugging, and not by a server that is actually registering&#8230; tyou can see that deregistration is not handled yet.</p>
<p>To grant write privileges to apache, I changed the owner of the balancer_members.conf to apache.</p>
<pre class="brush: bash;"> chown apache /etc/httpd/conf.d/balancer_members.conf</pre>
<p>This is probably the least secure aspect of my solution, as if the apache user were compromised, then any directives could be written to this file.  I&#8217;m not sure how big a threat this is, but it&#8217;s something that concerns me at least enough to think about this some more (and invite suggestions).</p>
<p>Next is to grant apache privileges to execute &#8220;/usr/local/bin/reload_httpd&#8221;.  We could accomplish this the same as we did above, but then it wouldn&#8217;t allow apache to execute what&#8217;s inside of the script, which is this:</p>
<pre class="brush: bash;">
#!/bin/bash
service httpd reload
</pre>
<p>unless we give execution rights to apache on service, which we don&#8217;t want.  What we also don&#8217;t want is for apache to be able to write to the file reload_httpd.  So what I ended up doing was, as you see in the script, to make root the owner of reload_httpd and remove write privileges for all (so apache couldn&#8217;t change it) and then add apache to the sudoers file, granting rights to execute this script without a password.</p>
<pre class="brush: bash;">visudo</pre>
<p>is the generally accepted way to edit the sudoers file.  And I added this line:</p>
<pre class="brush: bash;">apache ALL=(ALL) NOPASSWD: /usr/local/bin/reload_httpd</pre>
<p>I&#8217;m open to more secure ways of implementing this aspect as well, as I don&#8217;t consider myself a sudo configuration expert.  I think this gives apache rights to execute everything from anywhere if he knows the password; but he can also execute the /usr/local/bin/reload_httpd script without a password.</p>
<p>I also had to comment out the line:</p>
<pre class="brush: bash;">#Defaults   requiretty</pre>
<p>to allow sudo to function properly from a script not executed in a terminal.</p>
<p>Finally I had to disable proxying for the register script in my balancer.conf file:</p>
<pre class="brush: bash;">ProxyPass /register/ !</pre>
<p>And then your server is configured to dynamically update its list of balance members, you can check by going to the balancer-manager if you&#8217;ve got that enabled.  Next I will discuss how to handle the web server side of things.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=494</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Warning: mysql_connect(): Can&#8217;t connect to MySQL server on&#8230; (13)</title>
		<link>http://googolflex.com/?p=482</link>
		<comments>http://googolflex.com/?p=482#comments</comments>
		<pubDate>Tue, 02 Feb 2010 17:34:43 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[HTTP Servers]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[error message]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[selinux]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=482</guid>
		<description><![CDATA[I created some barebones Fedora servers that I&#8217;m intending to create a load balanced cluster from using Apache&#8217;s mod_proxy_balancer.  My topology will eventually look like this:
load_balancer -> (ws1, ws2, ws3) -> mysql_server
As you can see, it&#8217;s nothing fancy.  To test the balancer, each web server has a PHP script that connects to the [...]]]></description>
			<content:encoded><![CDATA[<p>I created some barebones Fedora servers that I&#8217;m intending to create a load balanced cluster from using Apache&#8217;s mod_proxy_balancer.  My topology will eventually look like this:</p>
<p>load_balancer -> (ws1, ws2, ws3) -> mysql_server</p>
<p>As you can see, it&#8217;s nothing fancy.  To test the balancer, each web server has a PHP script that connects to the MySQL database and inserts its hostname and IP address.  Then I could run a simple query to determine whether the balancer was distributing the load according to my rules.</p>
<p>The PHP script was basic too:</p>
<pre class="brush: php;">
$dbhost = &quot;mysql.host.com&quot;;
$dbuser = &quot;testuser&quot;;
$dbpass = &quot;testpass&quot;;

$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die (mysql_error());
$dbname = &quot;testdb&quot;;
mysql_select_db($dbname);

$query = &quot;INSERT INTO testtable(ip, host) VALUES('&quot; . $_SERVER[&quot;SERVER_ADDR&quot;] . &quot;', '&quot; . $_SERVER[&quot;SERVER_NAME&quot;] . &quot;');&quot;;

print $query;
mysql_query($query);
mysql_close($conn);
</pre>
<p>I&#8217;ve done this a thousand times, so you can imagine my frustration at getting this error message:</p>
<pre class="brush: bash;">[Mon Feb 01 16:22:21 2010] [error] [client 192.168.1.1] PHP Warning:  mysql_connect() [&lt;a href='function.mysql-connect'&gt;function.mysql-connect&lt;/a&gt;]: Can't connect to MySQL server on 'mysql.host.com' (13) in /var/www/html/index.php on line 7
</pre>
<p>I spent almost 2 hours looking for various solutions. I&#8217;ll list the most common ones in case you&#8217;re searching for a solution and mine doesn&#8217;t work for you:<br />
&#8211;Ensure that MySQL user permissions are configured correctly.<br />
&#8211;Ensure that MySQL is running on the server and on the correct port<br />
&#8211;Ensure that selinux is not blocking the MySQL port or the mysqld process</p>
<p>These three items can be tested by simply logging into MySQL from a remote host using the following command:</p>
<pre class="brush: bash;">mysql -u testuser -p -h mysql.host.com testdb</pre>
<p>If that gives you a MySQL prompt, you can rule out the above three causes.</p>
<p>Some of the less obvious suggestions, which didn&#8217;t solve my problem either were:<br />
&#8211;Ensure MySQL is using the correct path to the mysql.sock in my.ini<br />
&#8211;Ensure that the server wasn&#8217;t started with &#8211;skip-networking</p>
<p>Though I tried a number of configuration changes for both MySQL, the server MySQL was running on (including disabling selinux completely), and PHP, I failed to overlook that selinux was blocking Apache&#8217;s outgoing connections to the MySQL database.</p>
<p>So what finally solved my problem was disabling selinux completely on the server Apache was running on. I should have done this in the first place, as I normally do with my Linux desktop installations.</p>
<p>This can be accomplished by changing a line in /etc/selinux/config. Change the line that says:</p>
<pre class="brush: bash;">SELINUX=enforcing</pre>
<p>to</p>
<pre class="brush: bash;">SELINUX=disabled</pre>
<p>If you do some searching you can find out how to add an exception for Apache, after 2 hours I didn&#8217;t feel like fussing with those.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=482</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Book Review: MySQL Stored Procedure Programming</title>
		<link>http://googolflex.com/?p=479</link>
		<comments>http://googolflex.com/?p=479#comments</comments>
		<pubDate>Thu, 28 Jan 2010 01:58:40 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Book Reviews]]></category>
		<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[book review]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[stored procedures]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=479</guid>
		<description><![CDATA[I&#8217;ve been using MySQL for almost 7 years now without realizing it had stored procedure capabilities.  So when I saw MySQL Stored Procedure Programming, by Guy Harrison with Steven Feurerstein, I decided to take the opportunity to advance my skills with MySQL.  It&#8217;s a pretty good sized book, and it took me a while to [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using MySQL for almost 7 years now without realizing it had stored procedure capabilities.  So when I saw <em>MySQL Stored Procedure Programming</em>, by Guy Harrison with Steven Feurerstein, I decided to take the opportunity to advance my skills with MySQL.  It&#8217;s a pretty good sized book, and it took me a while to get through it because it&#8217;s just one of those books you have to keep putting down.</p>
<p>That&#8217;s a good thing in my opinion, because it means the material is so interesting that I can&#8217;t read for more than a chapter without getting on the computer and trying it out.  The first chapter was a tutorial, I thought I knew everything after I had gone through it and it took quite a bit of discipline (as well as a few error messages) for me to get back to the book and go through the topics.</p>
<p>There are three things I especially like about the book.</p>
<p>First was the additional coverage on triggers and transactions.  After reading this I feel like I haven&#8217;t really used MySQL at all&#8211; having never used stored procedures, OR transactions, OR triggers.  They were all topics that have been immediately applicable to my projects, because they were needed somewhere I just didn&#8217;t realize I could do them.</p>
<p>Second was the discussion of the material in the context of sound software engineering principles.  I always enjoy a refresher in those, and when I&#8217;m learning a new technology that&#8217;s usually when I need it most because I&#8217;m ready to hack everything together in my excitement.  For example, there&#8217;s an entire chapter on &#8220;Creating and Maintaining Stored Programs&#8221; as well as som optimization material and a discussion of best practices.</p>
<p>Third was their treatment on using stored procedures with specific programming languages.  These may some day go out of date, but they had chapters devoted to showing how to use stored procedures from PHP, Java, Perl, Python, and .NET.  All of which are relevant 4 years after publishing.</p>
<p>This book was an excellent choice for someone who has database experience, and some stored procedure experience (Oracle).  Even if you&#8217;re only familiar with the basics of MySQL, you will benefit from this book.  And it isn&#8217;t at all over the head of anybody with some database programming experience.  My only regret is that I didn&#8217;t find this book 4 years ago when it came out.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=479</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
