The first step to getting started with Riak is to grab the source and compile it. You will need Erlang installed on your system.
mkdir getting_started
cd getting_started
hg clone http://hg.basho.com/riak/
cd riak
make
We created a new project directory, “getting_started”, to contain our work.
Next, we’ll prepare a configuration for our first node. Configuration files are plain text files that contain Erlang terms separated by ’.’. These types of files can be read directly by Erlang with file:consult/1.
We’ll create a new folder to house our nodes.
getting_started/
-riak/
-nodes/
--node1/
---config.erlenv
Within “config.erlenv” we input the following:
{cluster_name, "my_cluster"}.
{ring_state_dir, "priv/ringstate"}.
{ring_creation_size, 64}.
{gossip_interval, 60000}.
{storage_backend, riak_ets_backend}.
{riak_cookie, riak_demo_cookie}.
{riak_nodename, node1}.
{riak_hostname, "127.0.0.1"}.
{riak_web_ip, "127.0.0.1"}.
{riak_web_port, 8098}.
{jiak_name, "jiak"}.
Configuration parameters expected by Riak are described here. I’ve been reviewing the docs in the source rather than those on the website since the published docs tend to lag behind a bit.
In the above config you will notice I left out the “riak_heart_command”. This option is only needed when using heart and is only parsed by the Riak shell scripts (e.g. start-fresh.sh). For this post we are going to start our nodes directly with the erl command.
With our config file in place we can start our node. For this post we are going to start the node directly with erl and from within the node directory. Since we are starting from within the node directory the log and ringstate information for this node will be output into the node directory.
Here is the command to start the node from within “nodes/node1”:
erl -connect_all false \
-detached \
-pa ../../riak/deps/*/ebin \
-pa ../../riak/ebin \
-name node1@127.0.0.1 \
-setcookie riak_demo_cookie \
-run riak start config.erlenv
The options passed to erl are described here. The above command tells erl to start a new Erlang runtime system with the name “node1@127.0.0.1”, the cookie “riak_demo_cookie”, and the ebin directories of Riak and it’s dependencies (webmachine, mochiweb) included in the code path. The command also tells erl to run “riak:start[config.erlenv]”.
Querying Riak will be covered in a separate post.
To stop the node we’ll use rpc:cast/4 to issue an init:stop/0 on the running node.
erl -noshell \
-name node_stopper@127.0.0.1 \
-setcookie riak_demo_cookie \
-eval "net_adm:ping('node1@127.0.0.1'),
rpc:cast('node1@127.0.0.1', init, stop, [])" \
-run init stop
This method will also work for nodes with a corresponding heart.
So far we know how to setup a node configuration file, start the node, and stop the node. Now we want to setup two nodes and cluster them together. Let’s copy the “node1” folder to “node2” so was end up with the following directories:
nodes/
node1/
config.erlenv
node2/
config.erlenv
Edit “nodes/node2/config.erlenv” and change “riak_nodename” and “riak_web_port”.
{cluster_name, "my_cluster"}.
{ring_state_dir, "priv/ringstate"}.
{ring_creation_size, 64}.
{gossip_interval, 60000}.
{storage_backend, riak_ets_backend}.
{riak_cookie, riak_demo_cookie}.
{riak_nodename, node2}.
{riak_hostname, "127.0.0.1"}.
{riak_web_ip, "127.0.0.1"}.
{riak_web_port, 8099}.
{jiak_name, "jiak"}.
Updating “riak_nodename” will ensure the Erlang node names will not collide. Updating “riak_web_port” will ensure the RESTful web interface for each node will not conflict with one another.
Using the start command from above we’ll start both nodes.
From within “nodes/node1”:
erl -connect_all false \
-detached \
-pa ../../riak/deps/*/ebin \
-pa ../../riak/ebin \
-name node1@127.0.0.1 \
-setcookie riak_demo_cookie \
-run riak start config.erlenv
From within “nodes/node2”:
erl -connect_all false \
-detached \
-pa ../../riak/deps/*/ebin \
-pa ../../riak/ebin \
-name node2@127.0.0.1 \
-setcookie riak_demo_cookie \
-run riak start config.erlenv
Now we can join “node2” to “node1” by issuing riak_startup:join_cluster/1 with rpc:cast/4.
erl -noshell \
-name node_join@127.0.0.1 \
-setcookie riak_demo_cookie \
-eval "net_adm:ping('node2@127.0.0.1'),
rpc:cast('node2@127.0.0.1', riak_startup, join_cluster, ['node1@127.0.0.1'])" \
-run init stop
To ensure we’ve successfully clustered the nodes we’ll start a third node, join the cluster, and list the available nodes.
cp -r nodes/node1 nodes/node3
vi nodes/node3/config.erlenv
{cluster_name, "my_cluster"}.
{ring_state_dir, "priv/ringstate"}.
{ring_creation_size, 64}.
{gossip_interval, 60000}.
{storage_backend, riak_ets_backend}.
{riak_cookie, riak_demo_cookie}.
{riak_nodename, node3}.
{riak_hostname, "127.0.0.1"}.
{riak_web_ip, "127.0.0.1"}.
{riak_web_port, 8100}.
{jiak_name, "jiak"}.
cd nodes/node3
erl -connect_all false \
-pa ../../riak/deps/*/ebin \
-pa ../../riak/ebin \
-name node3@127.0.0.1 \
-setcookie riak_demo_cookie \
-run riak start config.erlenv
If you look closely at the erl command for “node3” you’ll notice that we’ve removed the “-detached” flag. This means the node will be attached to your console. Once the node finishes loading you can press enter to gain access to the erlang shell. From the erlang shell we can connect to node1 and list the nodes within the cluster.
=PROGRESS REPORT==== 9-Nov-2009::03:15:38 ===
application: riak
started_at: 'node3@127.0.0.1'
(node3@127.0.0.1)1> riak_startup:join_cluster('node1@127.0.0.1').
=PROGRESS REPORT==== 9-Nov-2009::03:15:52 ===
supervisor: {local,inet_gethost_native_sup}
started: [{pid,<0.271.0>},{mfa,{inet_gethost_native,init,[[]]}}]
=PROGRESS REPORT==== 9-Nov-2009::03:15:52 ===
supervisor: {local,kernel_safe_sup}
started: [{pid,<0.270.0>},
{name,inet_gethost_native_sup},
{mfa,{inet_gethost_native,start_link,[]}},
{restart_type,temporary},
{shutdown,1000},
{child_type,worker}]
ok
(node3@127.0.0.1)2> nodes().
['node2@127.0.0.1','node1@127.0.0.1']
(node3@127.0.0.1)3>
Above, we successfully configured three Riak nodes and clustered them together. Soon, we’ll look at creating buckets, storing keys, and walking links.
I’ve implemented the steps above as rake tasks and made them available on github.