Author Archive
Apache mod_proxy_balancer Running Scripts at Startup/Shutdown : Part 2
Posted by: | CommentsI think I have to break the self-registration into two posts, it took a lot longer than I expected last night. This post deals with getting scripts to run at startup and shutdown on Linux. I did this on Fedora, I imagine the process would be similar on Ubuntu, etc.
This is actually the last thing I did, but I’m ordering it first because it’s a bit more general. My goal was to have a script that I could call as follows to register with my load balancer manually:
service lb_register start|stop|status|restart|reload|force-reload
And then also to register this service to be called at startup and shutdown, to register and deregister with the load balancer respectively.
Let’s start with creating the script. You can find tutorials for creating shell scripts just about anywhere on the web. I found it easier to take an existing script from the /etc/init.d/ directory, clear it out and start from that shell. Ironically the one that I chose was the startup script for Pound, another load balancer (a very good one, I might add). It shouldn’t matter which one you use, since all we’re really after is the format. The basic format is essentially the same for all of them: you have your function definitions at the top, and a case statement at the bottom.
The cases match the option parameters (start and stop are very common, as well as the others listed above in the callout). And the case blocks generally call one or more of the functions. I won’t list the case statement in this post as they are all very similar. There are some important things to note in the function definitions, though.
Here is the definition for my start() function:
start() {
echo -n $"Registering with the load balancer:"
./usr/local/bin/register_with_lb.pl
touch /var/lock/subsys/lb_register
}
You can see that I call a perl script (which presumably registers with the load balancer). Then I touch a file in the /var/lock/subsys/ directory. This is very important if you want a script to automatically run at shutdown. At shutdown the rc script will check for the presence of this file, if it is there it will call stop(). If it is not there, it assumes the service is stopped already and will not call stop() on the service.
My stop function:
stop() {
echo -n $"Deregistering with the load balancer: "
./usr/local/bin/deregister_with_lb.pl
rm -f /var/lock/subsys/lb_register
}
This calls the deregister perl script, and then removes the lock file for good housekeeping. There is one more thing about the script itself I want to mention before moving on to the registration. There is a line in the comments of most of the scripts (if not all) in /etc/init.d/ that will look something like this:
# chkconfig: - 85 10
or
# chkconfig: 2345 55 15
These are directives to chkconfig (the command we’ll be getting to in a moment) on how to set this script up. The – or the first grouping of numbers deal with the run levels. It tells chkconfig what levels this script will be turned “on”. It is assumed that it will be “off” in the omitted ones.
The second number is a startup priority, different scripts can have different startup priorities in case there are prerequisite dependencies. In the two examples above, the script containing the bottom directive would run before the script containing the bottom one. The last number is the shutdown priority, which is the same thing only during the shutdown process.
Once you have your script, you will need to run the chkconfig command. To add your script to the startup process:
chkconfig --add lb_register
And should you need to remove it:
chkconfig --del lb_register
If you’ve done everything correctly, register_with_lb.pl will be called at startup, and deregister_with_lb.pl will be called at shutdown. If it doesn’t, check that you’re touching the pid file, and that your scripts are executable. You will also be able to make calls like this to deregister and register manually:
service lb_register start service lb_register restart service lb_register stop
I should mention a few sites that helped me out quite a bit:
Linux Init Processes
Introduction to BASH Programming
An interesting script for creating new scripts
Apache mod_proxy_balancer Self Registration : Part 1
Posted by: | CommentsLoad 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’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.
Here is my flowchart for how self registration will work:
1. Server comes online.
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).
3. The server will then call a PHP script on the load balancer: “register/register.php”.
4. The PHP script will verify that a server sent the request.
5. The PHP script will query the database to get the current list of balancer members, and regenerate the balancer_members.conf file.
6. The PHP script will then issue a command to reload Apache’s configuration files.
Deregistration, which my PHP script as presented doesn’t display, will work as follows:
1. Server sends its hash to the PHP script, and shuts down.
2. The PHP script will check the hash against the database.
3. The PHP script will remove the server from the database.
4. The PHP script will repeat steps 5 and 6 above.
First, set up the database and created a user with sufficient privileges.
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) );
Second, create the PHP script.
$dbhost = "mysql.host.com";
$dbuser = "lbuser";
$dbpass = "password";
$dbname = "lb_register";
$dbtable = "lb2_members";
$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die (mysql_error());
mysql_select_db($dbname);
$query = "SELECT count(*) as count FROM " . $dbtable . " WHERE hash='" . $_GET['hash'] . "';";
$result = mysql_query($query);
$row = mysql_fetch_assoc(mysql_query($query));
if ($row['count'] >= 1) {
$file = "<Proxy balancer://mycluster>" . "\n";
$member_query = "SELECT hostname, loadfactor FROM " . $dbtable . ";";
$member_result = mysql_query($member_query);
while ($row = mysql_fetch_array($member_result, MYSQL_BOTH)) {
$file .= " BalancerMember http://" . $row['hostname'] . " ";
$file .= ($row['loadfactor'] > 1) ? ("loadfactor=" . $row['loadfactor'] . "\n") : "\n";
}
$file .= "</Proxy>";
exec('echo "' . $file . '" > /etc/httpd/conf.d/balancer_members.conf');
exec("sudo /usr/local/bin/reload_httpd");
}
mysql_close($conn);
You can tell a few things about the server configuration by looking at the script:
1. User apache will need to be able to write to the “/etc/httpd/conf.d/balancer_members.conf” file.
2. User apache will need to be able to execute the script “/usr/local/bin/reload_httpd”.
3. User apache will need sudoer rights.
4. This script was used for debugging, and not by a server that is actually registering… tyou can see that deregistration is not handled yet.
To grant write privileges to apache, I changed the owner of the balancer_members.conf to apache.
chown apache /etc/httpd/conf.d/balancer_members.conf
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’m not sure how big a threat this is, but it’s something that concerns me at least enough to think about this some more (and invite suggestions).
Next is to grant apache privileges to execute “/usr/local/bin/reload_httpd”. We could accomplish this the same as we did above, but then it wouldn’t allow apache to execute what’s inside of the script, which is this:
#!/bin/bash service httpd reload
unless we give execution rights to apache on service, which we don’t want. What we also don’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’t change it) and then add apache to the sudoers file, granting rights to execute this script without a password.
visudo
is the generally accepted way to edit the sudoers file. And I added this line:
apache ALL=(ALL) NOPASSWD: /usr/local/bin/reload_httpd
I’m open to more secure ways of implementing this aspect as well, as I don’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.
I also had to comment out the line:
#Defaults requiretty
to allow sudo to function properly from a script not executed in a terminal.
Finally I had to disable proxying for the register script in my balancer.conf file:
ProxyPass /register/ !
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’ve got that enabled. Next I will discuss how to handle the web server side of things.
Some Thoughts on Adobe Catalyst
Posted by: | CommentsI attended a user group presentation on Adobe Catalyst today (2/2/2010), and I thought I’d express some of the thoughts I had, and on code generation in general.
This product seems to spark up a lot of debate, and I think it’s because most conversations are only focusing on two roles (designer vs developer) when there are actually three roles that need to be considered. Those are designer, developer, and (man I hate using this term, but haven’t got a better one) interaction designer. And this is such a touchy area because (putting the science of interaction design aside) in terms of implementation this is where designer and developer overlap.
So there is some overlapping interests in terms of how the application behaves, and there’s only one tool– Catalyst. So who gets to use it? Wrong!! Most hard core developers I know who have tried Catalyst swear they will steer clear of it. Our preferred interaction design implementation tool is the same one we use for developing the rest of our software. In my case that would be Flex Builder. In the designer’s case, it will probably be Catalyst (maybe?).
So if it was so cut and dry, only one tool for this overlapping area, both developer and designer could learn to use Catalyst and get along. I don’t think that’s likely to happen anytime soon. So now the problem becomes one of getting Catalyst and Flex Builder to work nicely together. And I’ve only used Catalyst a little bit, and from what others have told me, making changes in Catalyst and importing them into Flex Builder seems to be pretty smooth. What I haven’t seen is how it goes the other way. If I make changes in Flex Builder, and the artist needs to make some changes in Catalyst– does that work as well?
I don’t know to tell the truth, but until I see how this interaction is going to work out, the jury is still out on whether this overlap of responsibilities is going to work out. I suppose if it were able to compartmentalize all of the Catalyst generated fluff where I could just “use” it and not have to work in it, I think I might be able to live with that. I haven’t seen how this is going to work either, though.
Like I said, I just wanted to get some thoughts out there, and we’ll see how this continues to play out in the coming months. It may be that it ends up being too expensive for my employer to use, in which case it will be business as usual.
Update
Sean Murphy sent me this link that I know my fellow developers will get a kick out of. Warning: If you’re a designer or a print publisher, you’ll probably be wondering, “What was so funny about that?”
Catalyst question in Adobe Forums
Anyway, I’d be very interested in taking a look at his site, I hope he’ll post a link to it. More than anything to see what kinds of projects can be accomplished by Catalyst all by itself in the hands of an experienced artist.
Book Review: MySQL Stored Procedure Programming
Posted by: | CommentsI’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’s a pretty good sized book, and it took me a while to get through it because it’s just one of those books you have to keep putting down.
That’s a good thing in my opinion, because it means the material is so interesting that I can’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.
There are three things I especially like about the book.
First was the additional coverage on triggers and transactions. After reading this I feel like I haven’t really used MySQL at all– 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’t realize I could do them.
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’m learning a new technology that’s usually when I need it most because I’m ready to hack everything together in my excitement. For example, there’s an entire chapter on “Creating and Maintaining Stored Programs” as well as som optimization material and a discussion of best practices.
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.
This book was an excellent choice for someone who has database experience, and some stored procedure experience (Oracle). Even if you’re only familiar with the basics of MySQL, you will benefit from this book. And it isn’t at all over the head of anybody with some database programming experience. My only regret is that I didn’t find this book 4 years ago when it came out.
Book Review: Apache Cookbook
Posted by: | CommentsI was expecting to learn a little about Native American cuisine when I ordered Apache Cookbook, 2nd ed., by Ken Coar and Rich Bowen. I was disappointed in that respect, but I still found ample material to digest…
On a more serious note, I enjoyed reading this book and I learn a lot of new information about the Apache web server. I usually enjoy reading code cookbooks because their layout and organization facilitates skipping what you already know and getting onto things you don’t. I would consider myself an intermediate level Apache administrator, and I was able to get through the entire book in a single evening. I made notes on some of the recipes I found most interesting, and that I’m actually going to try implementing. I’ll list some of them here so you can get an idea what kinds of things you might learn if you read this book:
- Recipe 3.19 – Logging activity to a MySQL database
- Recipe 5.16 – Redirecting all- or part- of your server to SSL
- Recipe 5.17 – Turning Directories in to Hostnames
- Recipe 5.22 – Turning URL segments into Query Arguments
- Recipe 6.21 – Protecting files with a wrapper
- Recipe 6.33 – Using permanent redirects to obscure forbidden URLs
- Recipe 10.9 – Load balancing with mod_proxy_balancer
- Recipe 11.2 – Benchmarking Apache with ab
These were the topics that interested me most, but there are quite a few others that I’d like to play around with when I’ve got more time. Intermediate users can definitely skip the first 2 chapters which covers installing Apache on a number of platforms, and enabling certain mods. I highly recommend chapter 5: Aliases, Redirecting and Rewriting, that was one area I am particularly weak in and was able to get a lot of information out of it. Also helpful was Appendix A, which gives a concise refresher on regular expressions for those of you like me, who re-learn regular expressions every time you need one.
Overall I highly recommend this book. It’s not as comprehensive or as in depth as others I’ve browsed, but it is definitely dense with useful information about stuff you either didn’t know you could do with Apache, or weren’t quite sure how to do it.
Running IIS 6.0 and Apache Together
Posted by: | CommentsMy ColdFusion VPS runs IIS 6.0 on Windows Server 2003. I wanted to run Apache 2.2 on this server as well, and bind it to the IP address that IIS 6.0 wasn’t using. I opened the IIS management console to force IIS to listen on a single IP address, but when trying to start Apache I received an “already in use” error. I double checked that IIS was configured to listen on one IP address, and Apache was configured to listen on the other. Then I tried several variations of service startup order, etc, still without success.
Let me explain my requirements clearly: I wanted IIS and Apache to each use port 80 of different IP addresses. Before you leave a comment explaining I could have had them listen on different ports– I know that, but it’s not what I wanted.
My research lead me to this Microsoft knowledgebase article: http://support.microsoft.com/default.aspx?scid=kb;en-us;259349 which referenced IIS 5.0, but I assumed was relevant. The crux of the matter is this: “To enhance performance, IIS 5.0 uses “socket pooling”, in which IIS binds to all IP addresses when it starts.” Yep, you read that correctly. Regardless of the settings you made in the IIS console, it will bind to ALL available IP addresses.
The workaround in the article is as follows:
- Change to the C:\Inetpub\AdminScripts directory.
- Execute the following command:
CSCRIPT ADSUTIL.VBS SET W3SVC/DisableSocketPooling TRUE
Apparently there are some differences between IIS 5 and 6, because this didn’t correct the problem. Fortunately I was able to discover something that worked by browsing around a few other sites.
First, you need to install the Support Tools from the Windows Server 2003 cd. This includes the httpcfg.exe tool, which is what you can use to force IIS to listen only on specific IP addresses. After you have this installed (there is a start menu option that will open up a command prompt in the correct directory) here are the commands to make the fix:
net stop http /y(This stops IIS)httpcfg.exe set iplisten /i 10.0.0.2:80(You must specify the port! Or it will still steal them!)net start w3svc(Restart IIS)- Start up Apache
I wasn’t able to find any documentation explaining why it didn’t work when I didn’t specify the port. I guess IIS needs very specific rules when it comes to getting along with other HTTP servers. I have yet to have this problem with IIS 7.0, mainly because I haven’t tried installing Apache on my Windows 2008 box. When I try it, I’ll keep you posted as to whether this fix still works. Or if it’s required… which I’m sure it is since it’s not a bug, it’s a performance enhancer. I wonder if Microsoft’s STMP service uses a similar “mail enhancement” feature to grab all port 25s?
JUICE chat (Stratus Peer to Peer)
Posted by: | CommentsOne of my ongoing weekend projects is an AIR chat application, recently rechristened “JUICE” a.k.a. “John’s Ultimate Internet Chat Experience”. I realize that may only be the case for myself, but the project has been very educational and entertaining for me.
The initial release used AIR/Flex as the front-end, ColdFusion and MySQL for the backend, and BlazeDS messaging for message transmission and “peer discovery”. I worked on it over a couple weeks adding features like encryption, toast-style notifications, as well as a few other less notable things.
I knew the architecture was awful and would never scale beyond a couple hundred users (if that many). Here’s the basics of how it worked:
- The user would login, ColdFusion/MySQL would send back a list of chat buddies.
- Each logged in user would ping the messaging server every 10-30 seconds to announce “I’m still here!”
- The pings would be broadcast to everyone logged in (and connected to the messaging server). The application would filter out the ones it was interested in based on user id.
- Sending messages worked similarly, the user would send the message (which included information about the intended recipient), which would then be broadcast to EVERYONE.
- Everyone would filter this information, and the recipient would know it was for him, and would display it.
You can see why this would not scale well, the amount of traffic and pinging going on. Eventually even a user with only 1 or 2 buddies would notice a significant drop in performance as the number of total users increased. There are some applications of “chat” for which BlazeDS messaging and polling is well suited for (like a chat room). A chat application involving “buddies” is much better suited for P2P.
Enter Stratus. I discovered Stratus a few months ago but was unwilling to delve into it on account of my hectic schedule. Fortunately one of my friends went and did all the dirty work figuring out how to get it up and running (turns out it’s pretty easy) and I was able to apply it to my chat client.
I’m very pleased with the results, though it’s still very much a work in progress. I’ve even been able to add video and voice chat features, which is why I went through the trouble in the first place. Here is how my peer discovery mechanism operates. It requires only 3 calls to the server per client (which I could easily condense to 2 if I wanted).
- The user logs in.
- If the user successfully authenticated, he connects to Stratus and receives his peer ID.
- The user updates his peer ID in the database (which was set to 0) and gets a list of his buddies and their peer IDs. I also update information like whether or not I have a camera/mic.
- The user processes his buddy. If the peer ID is something other than 0, then I know this buddy logged in before me, so I must send him my peer ID.
- Any buddies that have a peer ID of 0 are not logged in, I need to listen for them though since they will get my peer ID when they log in.
- When I log out or close the application, I call the server and reset my peer ID to 0. I also notify all of my connected peers I’m logging out.
There are a few more steps in the process, but it decreases the load on the server significantly, transferring the “burden of proof” onto the clients.
Interesting to note is the way I get the peer ID of a client who connects after me (step 4). I don’t actually have to make a call for this, rather he simply has to start broadcasting to me on the NetStream I set up to listen for him (step 5). When the connection is made, an event will be dispatched by the NetStream class. In fact, 3 events will be fired, I just chose to act on one of them.
The peer ID can be obtained from the peerStreams array on the publishing NetStream. I then use that information to set up my subscribing NetSream.
if (this.peerId == null || this.peerId == &quot;0&quot;) {
this.peerId = publishNetStream.peerStreams[0].farID;
this.subscribeNetStream = new NetStream(model.netConnection, this.peerId);
this.subscribeNetStream.client = new NetStreamClient();
this.subscribeNetStream.play(streamName);
}
Anyway,I’m planning on doing another post to outline my video and voice handshake protocols. They’re nothing to write home about, but I’d love some feedback if there’s a better way. I’m also planning on releasing JUICE after I bring it’s level of functionality back up to where the original version was, so stay tuned and you should see my install badge at the bottom of my blog.
Adobe Stratus and Flash P2P
Posted by: | CommentsSean Murphy (my friend and fellow BYU-AUG member) just did a write up of some training he did last month for our user group. It’s an introduction to P2P with Flash+Stratus.
In my opinion, this is some really exciting technology as most communication of this sort (for Flash player) has to be routed through an intermediate server. Naturally there will still be cases where that makes the most sense, but for p2p apps (i.e. voice/video chat, p2p file transfer, etc) this is definitely a breath of fresh air.
I’ve been working on my own AIR chat application (previously implemented using polling channels on BlazeDS) which I may post more information about over the Christmas break. I’m converting it to use Stratus for real time P2P chatting. In the meantime if you’re interested in getting your feet wet with this, take a look at Sean’s write up: here.
He walks through a multi-user video conferencing app he built. The write up itself is still a work in progress (he’s cleaning up the source, and making a few other changes). He’s the kind of guy that appreciates feedback, so let him know what you think.
You might also want to register for your own Stratus beta dev key: here.

