Consoles
 

Brightercove/

by David Czarnecki, July 29th, 2010 at 03:13pm - No Comments »
Tagged As: , ,
Posted in: Engineering, Uncategorized

We’re using Brightcove here at Agora Games for some video platform work. In our group chats, we’ve talked about, “It would be nice if we had a Ruby API for interacting with Brightcove.”

And so I did just that, http://github.com/agoragames/brightcove


sudo gem install brightcove-api

>> require 'brightcove-api'
=> true
>> brightcove = Brightcove::API.new('0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.')
=> #<brightcove ::API:0x114dbc8 @token="0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.", @api_url="http://api.brightcove.com/services/library">
>> response = brightcove.get('find_all_videos', {:page_size => 3, :video_fields => 'id,name,linkURL,linkText'})
=> {"items"=>[{"name"=>"Documentarian Skydiving", "id"=>496518762, "linkText"=>nil, "linkURL"=>nil}, {"name"=>"Surface Tricks", "id"=>496518763, "linkText"=>nil, "linkURL"=>nil}, {"name"=>"Free Skiing", "id"=>496518765, "linkText"=>nil, "linkURL"=>nil}], "page_number"=>0, "page_size"=>3, "total_count"=>-1}

  • Reddit
  • Digg
  • del.icio.us
  • Technorati

Party for Misha/

by Brian Corrigan, July 29th, 2010 at 12:52pm - No Comments »
Posted in: Uncategorized

image

Today is Misha’s last day.  We wished him luck and toasted him off with some local microbrews from the Troy Pub and Brewery.

  • Reddit
  • Digg
  • del.icio.us
  • Technorati

Grabbing the Rabbit by the Horns/

by Aaron Westendorf, July 28th, 2010 at 11:17am - No Comments »
Posted in: Engineering, Infrastructure

RabbitMQ is a very powerful tool, especially when deployed in a cluster. Among RabbitMQ’s more useful features is rabbitmqctl, the command line tool which can be used to query a node and list its exchanges, queues, connections, number of consumers, memory usage and more.

The application, and cluster deployment in general, is hamstrung by Erlang’s standard approach to cookies. The cookie, typically .erlang.cookie in the HOME directory of an application, must have only user read permissions. For a Linux RabbitMQ install, that would look like this:

bofh@rabbit_host1:~$ ls -al /var/lib/rabbitmq/
total 333
drwxr-xr-x  3 rabbitmq rabbitmq    160 2010-07-12 17:49 .
drwxr-xr-x 37 root     root       1008 2010-07-02 14:29 ..
-r--------  1 rabbitmq rabbitmq     20 2010-05-04 20:44 .erlang.cookie
drwxr-xr-x  3 rabbitmq rabbitmq     72 2010-05-04 20:49 mnesia
-rw-r--r--  1 rabbitmq rabbitmq     27 2010-07-12 17:49 pids

Any variation on these permissions and Erlang will refuse to start. The permissions requirement is embedded into Erlang itself, making it more or less impossible to work around. This creates the following problems:

  • You must copy this file (or its contents) to all hosts in the cluster
  • All users of rabbitmqctl must run it as sudo
  • All monitoring tools must also run as root or have sudo capability
  • You must have the cookie file present on the host running rabbitmqctl

Given how powerful rabbitmqctl is, you will likely still want to limit access to it, but this can be readily accomplished with standard Unix permissions. By expanding who can use it and where, your system administrator will be thrilled to reduce need for sudo access and your customers will be happy with the additional tools you can deploy to monitor your cluster and its clients to ensure that all is well, 24/7.

Thankfully, RabbitMQ’s scripts accept a lot of environment variables which can be passed into the Erlang runtime, and Erlang kindly provides a way to bypass the cookie file through a command line literal. The scripts are all located in the scripts directory inside your RabbitMQ installation.

bofh@rabbit_host:~$ ls -ald `erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell`/rabbitmq-server*/scripts
drwxr-xr-x 2 root root 520 2010-07-21 14:47 /usr/local/lib/erlang/lib/rabbitmq-server-1.7.0/scripts
drwxr-xr-x 2 root root 520 2010-07-21 16:15 /usr/local/lib/erlang/lib/rabbitmq-server-1.7.2/scripts

The three standard scripts, rabbitmq-server, rabbitmq-multi and rabbitmqctl all source an environment script, rabbitmq-env, which in turn will source the file /etc/rabbitmq/rabbitmq.conf if it exists. This is the file that you can edit to take control of your RabbitMQ cluster.

SERVER_START_ARGS="+K true +A300 +P512000 -setcookie NOMNOMNOMYUMYUM -kernel inet_default_listen_options [{nodelay,true},{sndbuf,32768},{recbuf,32768}]"
MULTI_START_ARGS="-setcookie NOMNOMNOMYUMYUM"
CTL_ERL_ARGS="-setcookie NOMNOMNOMYUMYUM"

The value of each environment variable will be passed verbatim to the Erlang runtime. The SERVER_START_ARGS are passed to each node started by rabbitmq-multi, and directly affect the performance of a RabbitMQ instance. In this example, we have increased the number of native threads available to Erlang and allowed it to spin up numerous (Erlang) processes. We have also instructed the kernel to increase its TCP buffer sizes and disable Nagle's algorithm.

You can now run rabbitmqctl without sudo on any host which has this same configuration deployed. This solution still requires that you synchronize /etc/rabbitmq across your cluster, though there are many ways of solving that problem.

We have taken this a step further and enabled rabbitmqctl on any host in our network. All of our core software is deployed from source to /usr/local over NFS. We have deployed the rabbitmq.conf file there too, and have a small shell script wrapping rabbitmqctl.

#!/bin/bash
ERL_PATH=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell`
LATEST_VERSION=`ls $ERL_PATH | grep rabbitmq | sort | tail -1`
RABBIT_PATH="$ERL_PATH/$LATEST_VERSION"

set -f
[ -f /usr/local/etc/rabbitmq/rabbitmq.conf ] && . /usr/local/etc/rabbitmq/rabbitmq.conf
export CTL_ERL_ARGS
HOME=/var/lib/rabbitmq $RABBIT_PATH/scripts/rabbitmqctl $@

We can now connect to and monitor any RabbitMQ node from any host on our network

bofh@gateway:~$ rabbitmqctl -n rabbit@rabbit_host1 status
Status of node rabbit@rabbit_host1 ...
[{running_applications,[{rabbit,"RabbitMQ","1.7.2"},
                                {mnesia,"MNESIA  CXC 138 12","4.4.10"},
                                {os_mon,"CPO  CXC 138 46","2.2.2"},
                                {sasl,"SASL  CXC 138 11","2.1.6"},
                                {stdlib,"ERTS  CXC 138 10","1.16.2"},
                                {kernel,"ERTS  CXC 138 10","2.13.2"}]},
 {nodes,[rabbit@rabbit_host1,rabbit@rabbit_host2]},
 {running_nodes,[rabbit@rabbit_host1,rabbit@rabbit_host2]}]
...done.
  • Reddit
  • Digg
  • del.icio.us
  • Technorati

Rails 3.0.0.rc changes/

by David Czarnecki, July 27th, 2010 at 12:46pm - No Comments »
Tagged As: , ,
Posted in: Bending Rails, Engineering

Rails 3.0.0 now has a release candidate. These are the changes I made to a new application I am working on to clear up any deprecation warnings.

Read the rest of this entry »

  • Reddit
  • Digg
  • del.icio.us
  • Technorati

Lifting the Tail: Inside Agora Skunk Works/

by Aaron Westendorf, June 28th, 2010 at 09:08am - No Comments »
Posted in: Engineering, Infrastructure, Python
We’ve been hard at work for over a year developing the next generation of game integration technology here at Agora, and over the next few months we’ll be releasing some of the code that we’ve developed, discussing some of the challenges we face and how we’re using all the new technology to build the best gaming experience around.

To start, a brief explanation of the challenges we face.  As you might imagine, we deal with a lot of data.  The volume is only increasing, and with our friends at MLG, we expect significantly more of it.  Along with the volume of data, it also comes to us in many different forms and protocols; sometimes it’s pushed to us, and sometimes we have to go fetch it.  We have to respond to any number of business decisions made by developers and publishers, adapt to developers’ needs in a manner which does not negatively impact their schedule, and be a consistent and reliable partner to all our clients.  We have to deliver comprehensive documentation to both game and website developers, and our business relationships are aided by a consistent offering.

In the past, each game’s services would be its own Rails application.  We built a suite of re-usable components, but for each title we would have to re-write a lot of boiler-plate code and set up an entirely new suite of servers, complete with application hosts, web and caching proxies, databases and so on.  As our data throughput grew, we found that we needed to add additional components to our stack, such as Sparrow, to turn synchronous workloads into asynchronous ones.  Each project required extensive monitoring and reporting, an interactive console for viewing production data and testing staging code.

We were very successful, but found the business costs too high and that we were missing several features that were important to our long term strategy of being the best in the industry at game integration.  Our experience with a virtualized hosting environment opened our eyes to the possibilities of turning our data processing and web services loose on a commoditized, shared platform.

With a general set of requirements in hand, we set forth, and what we came away with has been incubating, gestating and flowering into a powerful toolset that has met all our expectations, and then some.

Our first task was to choose the core set of technologies and the basic processing scheme that we would be using.  After an exhaustive search, lots of hacking and whiteboard scribblings, we settled on the following key features:

  • Python for all application code
  • AMQP, via RabbitMQ, for all inter-process communication
  • MySQL, Tokyo Tyrant and memcache for data storage services
  • Protocol translators to bridge external traffic to AMQP via a simple binary protocol
  • libevent for as many as IO operation as possible

We chose Python from the suitable dyanmic languages primarily for its memory management and speed.  We were shifting to a single-threaded multi-process environment where memory costs are high and performance paramount, and Python has an extensive pedigree in this area.  We did choose to sacrifice some memory by adhering to a single-threaded model in order to keep the application stack simple and use the kernel for all context switching.

AMQP’s routing scheme gives us powerful tools to shard and aggregate traffic across our cluster.  We chose RabbitMQ because of its Erlang heritage, its performance, reliability, clustering capabilities and commercial support.  By splitting up each game’s services into discrete packages which can each run numerous instances, we can readily divide traffic across a cluster of RabbitMQ hosts and attach listeners for monitoring, diagnostics and metrics.  The dotted-notation of AMQP’s topic exchanges allow for routing traffic between titles, environments, services and even specific commands.

To get the most out of the kernel and reduce latency, we use libevent for all of our AMQP traffic and in our protocol translators.  We extensively patched the py-amqplib to work within this asynchronous environment.  This fork has been in production use for some time now but is slated for a ground-up re-write and release into the wild.

We considered many other database solutions, but at the time that we had to make our decision, felt that Tokyo Tyrant was the best NoSQL database to introduce into our stack because of its sparse table capabilities, high performance, low resource usage and simple setup.  We’re very excited with all the new development that is taking place in this field, and will be writing more about our experience with these tools over the coming years.

What we ended up with has met all of the goals that we set out to achieve.  We have successfully abstracted scaling, monitoring, protocol presentation and metric aggregation, allowing us to focus entirely on delivering functionality to our customers.  Now that our customers include MLG, this means that we’ll be rolling out some of the biggest and baddest applications in the gaming community, with confidence and reliability.
  • Reddit
  • Digg
  • del.icio.us
  • Technorati