In this tutorial I’ll show you how to implement your own ElastiCache (Memcached) node Auto Discovery. Auto Discovery is useful when you need to add or remove nodes without having to manually add/remove the endpoints in your application. If in your application you’re only using one node your code would look like this:

mc := memcache.New("")

If that memcached node began to evict items a new node would be needed. Adding a new node in AWS easy, go to your Cache Cluster console and click on the “Add Node” button. In a couple of minutes your node will up & running.


Since your application does not have any node Auto Discovery code you would need to add that new node manually:

mc := memcache.New("", "")

Then you’d build & upload your project to your server or servers. All these steps can be avoided by implementing node Auto Discovery.

The Code

package main

import (

func main() {

   endpoints := []string{}
   client := elasticache.New(session.New(),&aws.Config{Region: aws.String("eu-west-1")})
   params := &elasticache.DescribeCacheClustersInput{
      CacheClusterId:    aws.String("eticket-cache"),
      MaxRecords:        aws.Int64(20),
      ShowCacheNodeInfo: aws.Bool(true),

   go func(endpoints *[]string) {
      for {
         *endpoints = nil
         resp, err := client.DescribeCacheClusters(params)

         if err == nil {
            for _, cluster := range resp.CacheClusters {
               for size, node := range cluster.CacheNodes {
                  if size == 0 {
                     if *cluster.CacheNodes[0].CacheNodeStatus == "available" {
                        *endpoints = append(*endpoints, fmt.Sprintf("%s:%d", *cluster.CacheNodes[0].Endpoint.Address, *cluster.CacheNodes[0].Endpoint.Port))
                  } else {
                     if *node.CacheNodeStatus == "available" {
                        *endpoints = append(*endpoints, fmt.Sprintf("%s:%d", *node.Endpoint.Address, *node.Endpoint.Port))
            time.Sleep(time.Second * 2)

   for {
      time.Sleep(time.Second * 2)
      if endpoints != nil {


You only need to replace the region and CacheClusterId with your own. You can find the CacheClusterId in your ElastiCache console:


DescribeCacheCluster returns a lot of information regarding your cache cluster:

  CacheClusters: [{
      AutoMinorVersionUpgrade: true,
      CacheClusterCreateTime: 2016-06-20 09:39:44.379 +0000 UTC,
      CacheClusterId: "eticket-cache",
      CacheClusterStatus: "available",
      CacheNodeType: "cache.t2.micro",
      CacheNodes: [{
          CacheNodeCreateTime: 2016-06-20 09:39:44.379 +0000 UTC,
          CacheNodeId: "0001",
          CacheNodeStatus: "available",
          CustomerAvailabilityZone: "eu-west-1a",
          Endpoint: {
            Address: "",
            Port: 11211
          ParameterGroupStatus: "in-sync"
          CacheNodeCreateTime: 2016-07-12 13:57:48.598 +0000 UTC,
          CacheNodeId: "0002",
          CacheNodeStatus: "available",
          CustomerAvailabilityZone: "eu-west-1a",
          Endpoint: {
            Address: "",
            Port: 11211
          ParameterGroupStatus: "in-sync"
      CacheParameterGroup: {
        CacheParameterGroupName: "default.memcached1.4",
        ParameterApplyStatus: "in-sync"
      CacheSubnetGroupName: "cache-subnet",
      ClientDownloadLandingPage: "",
      ConfigurationEndpoint: {
        Address: "",
        Port: 11211
      Engine: "memcached",
      EngineVersion: "1.4.24",
      NumCacheNodes: 2,
      PendingModifiedValues: {

      PreferredAvailabilityZone: "eu-west-1a",
      PreferredMaintenanceWindow: "sun:23:00-mon:00:00",
      SecurityGroups: [{
          SecurityGroupId: "sg-7d91121a",
          Status: "active"

We only need to know the endpoint address and port.

Running the demo application

When running the demo application remember that your EC2 instance must have AWS credentials (environment variables, shared credentials file or IAM roles).

You’ll get an output similar to this if you have one node:


If you add a new node the application will automatically identify a new node is available and it will add it to the slice:



Using node Auto Discovery is very useful since it avoids any manual intervention. Just add or remove a new node and your GO application will identify the changes automatically.

AWS ElastiCache Memcached cluster in a GO project

In this tutorial we’ll learn how to use AWS ElastiCache Memcached cluster in a GO project.
We’ll be using the most recommended GO library:

To follow this tutorial you’ll need a working ElastiCache Memcached cluster. Read the AWS getting started tutorial.


go get

Install git if you get the following error:

go: missing Git command. See
package exec: "git": executable file not found in $PATH

The code

package main

import (

func main() {

    if len(os.Args) < 3 {
        log.Fatalln(errors.New("Usage: main key value"))

    key := os.Args[1]
    value := os.Args[2]

    mc := memcache.New("")
    mc.Set(&memcache.Item{Key: key, Value: []byte(value)})

    it, err := mc.Get(key)

    if err != nil {
    } else {

You must replace the Memcached endpoints with your own. Go to your ElastiCache Dashboard, Cache Clusters & click on Nodes.
Click on “Copy Node Endpoint” to view all your available Memcached node endpoints.


If you have more than one node edit the memcache.New line:

mc := memcache.New("", "")

Build and run the application

go build main.go
./main Arg1 Arg2

Replace Arg1 & Arg2 with the key and value you wish to create.


You can test that your keys are being created by clicking on the node(s) and scroll to the “Current Items (Count)” graph.


From your EC2 instance you can telnet to your Memcached node and run commands to query the keys stored in that server.

· stats items retrieves stats from the node
· stats cachedump 1 5 retrieves keys 1 to 5

telnet 11211
[root@ip-10-0-1-39 ec2-user]# telnet 11211
Connected to
Escape character is '^]'.
stats items

STAT items:1:number 1
STAT items:1:age 276
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 0
STAT items:1:expired_unfetched 0
STAT items:1:evicted_unfetched 0
STAT items:1:crawler_reclaimed 0
STAT items:1:crawler_items_checked 0
STAT items:1:lrutail_reflocked 0
stats cachedump 1 5

ITEM foo [8 b; 1466415492 s]


In this simple example we connected to a Memcached server, created a key & retrieved its value. In the next tutorial we’ll learn how to add Auto Discovery to add/remove nodes dynamically.


In this tutorial I’ll show you how to configure GO in an AWS EC2 instance and use the AWS GO SDK.

Configuring GO

Connect to your EC2 instance

ssh ec2-user@PUBLIC_IP -i yourpemfile.pem

Execute the following commands to install & configure GO

sudo su
mkdir /downloads
cd downloads
tar xvfz go1.6.2.linux-amd64.tar.gz -C /usr/local
cd /usr/local/go
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
cd $HOME
mkdir work
export GOPATH=$HOME/work
cd work
mkdir bin | mkdir pkg | mkdir src

You should put the export commands in your shell startup script ($HOME/.bashrc)

vi $HOME/.bashrc

export GOPATH=$HOME/work
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin

You now have GO configured in your EC2 instance. You can test that it’s working by executing the following commands

cd src | mkdir aws-sdk-go
cd aws-sdk-go

vi main.go
package main

import "fmt"

func main() {
	 fmt.Printf("hello, world\n")

go run main.go

You should see the text “hello, world” when running the go command.

AWS credentials

To access AWS services you need to set your account credentials. You have three valid methods:

  1. Environment variables

  2. Shared credential files

    Edit ~/.aws/credentials
    aws_access_key_id = ACCESS_KEY_ID
    aws_secret_access_key = SECRET_ACCESS_KEY_ID
  3. EC2 instance profile credentials (IAM roles) This is the preferred method if running on EC2
    A) Create an IAM Role S3 Access
    B) Assign the role to the EC2 instance

You should never hardcode your credentials in your code. It makes it difficult to maintain (if keys are changed for example) and they might be exposed by mistake.

Let’s download the AWS SDK and create our S3 test app.

go get -u

Edit the main.go file:

package main

import (

func main() {
        client := s3.New(session.New(),&aws.Config{Region: aws.String("eu-west-1")})
        result, err := client.PutObject(&s3.PutObjectInput{
                Bucket: aws.String("yourbucketname"),
                Key:    aws.String("testkey"),
                Body:   strings.NewReader("Hello"),
        if err != nil {

You should change yourbucketname with a bucket that exists in your AWS account. You should also set the region bucket, changing eu-west-1 with your desired region.

Time to test your first GO AWS SDK app:

go run main.go

You should get a response similar to this:

[root@ip-10-0-1-39 ec2-user]# ./main 
  ETag: "\"8b1a9953c4611296a827abf8c47804d7\""

If your credentials are incorrect you will get a response similar to this:

[root@ip-10-0-1-39 ec2-user]# ./main 
InvalidAccessKeyId: The AWS Access Key Id you provided does not exist in our records.
	status code: 403, request id: C2A2BA80682D8ABB


In this short tutorial you’ve learned how to configure GO to access AWS services using Amazon’s SDK for GO. If you want to learn more about the AWS SDK for GO:

GO’s Beego Framework: Creating a web that connects to MySQL

This tutorial is intended for developers new to GO and the Beego framework ( You’ll learn how to create a very simple web app that connects to a MySQL database.

Installing & running Beego

You’ll first need to download Beego, from your command line:

cd ${GOPATH}/src

go get
go get

Create a new Beego project by typing:

Linux users, create a link of the bee utility in your /usr/bin/ folder:

ln -s ${GOPATH}/bin/bee /usr/bin/bee

bee new beegomysql

src $ bee new beegomysql
[INFO] Creating application…
2016/06/14 09:07:57 [SUCC] New application successfully created!

Beego creates some default folders and files following the MVC architecture pattern (Figure 1).

Figure 1

cd beegomysql

Run the project using Beego’s bee utility:

bee run watchall

beegomysql $ bee run watchall
bee :1.4.1
beego :1.6.1
Go :go version go1.5.3 darwin/amd64

2016/06/14 09:19:20 [INFO] Uses ‘beegomysql’ as ‘appname’
2016/06/14 09:19:20 [INFO] Initializing watcher…
2016/06/14 09:19:20 [TRAC] Directory(/Users/antonimassomola/golang/src/beegomysql/controllers)
2016/06/14 09:19:20 [TRAC] Directory(/Users/antonimassomola/golang/src/beegomysql)
2016/06/14 09:19:20 [TRAC] Directory(/Users/antonimassomola/golang/src/beegomysql/routers)
2016/06/14 09:19:20 [TRAC] Directory(/Users/antonimassomola/golang/src/beegomysql/tests)
2016/06/14 09:19:20 [INFO] Start building…
2016/06/14 09:19:24 [SUCC] Build was successful
2016/06/14 09:19:24 [INFO] Restarting beegomysql …
2016/06/14 09:19:24 [INFO] ./beegomysql is running…
2016/06/14 09:19:24 [asm_amd64.s:1721][I] http server Running on :8080

Project is running on localhost port 8080. Open your web browser and enter the following URL http://localhost:8080. If everything worked as expected you should see the “Welcome to Beego” page (Figure 2).

Figure 2

The bee utility logs every petition received:

2016/06/14 09:20:17 [router.go:829][D] | GET | / | 7.355621ms | match | / |

Building our first Beego web app

Beego’s default controller is located in controllers/default.go. By default Beego creates the Get method (Figure 3). This method is used to output the data you see when opening the http://localhost:8080 URL. Beego sends data to the template by assigning it to this.Data (map[string]interface{}).

Figure 3
Try passing a new value to the template by adding the following code:

c.Data["Test"] = "Test string"

Now open the index.tpl template file (views/index.tpl) and add the following code:

Test Data: {{.Test}}

bee automatically detects any change in the source code of the project and rebuilds it so you don’t need to worry about recompiling. Go back to your browser and refresh the page, you should see the “Test string” being passed to the template.

Let’s create a new router to test how to create new routes in our web app. Open the default routing file (routers/router.go). Add the following code below the main route:

beego.Router("/user/register/:username", &controllers.MainController{}, "get:UserRegister")

The first argument is the path, the second is the controller and the third is the method called when accessing that URL (http://localhost:8080/user/register/antonimassomola). We can define the methods we support, in our case we only accept GET petitions.

We must now create the UserRegister method in our controller’s file (controllers/default.go):

func (c *MainController) UserRegister() {

    c.Data["username"] = c.Ctx.Input.Param(":username")
    c.TplName = "register.tpl"


We’ll read the :username parameter being passed in the URL and load the register template.

The register template file must be created (views/register.tpl):

Username: {{.username}}

Go back to your browser and enter this URL: http://localhost:8080/user/register/your_username. You should see the register template being rendered with the username parameter being read from the URL.

We will be using MySQL as our relational database. Go to your console and type the following to install the MySQL GO driver: go get

Create a database named beegomysql:

create database beegomysql;
use beegomysql;

Create a new table and name it users:

create table users(id int(3) primary key auto_increment, username varchar(64));

Go back to your IDE (Sublime, WebStorm, etc.) and edit the main.go file. You’ll need to import the following files:

_ "beegomysql/models"
_ ""

The init() funciton is needed to register the MySQL driver and database:

func init() {
    orm.RegisterDriver("mysql", orm.DRMySQL)
    orm.RegisterDataBase("default", "mysql", "beego:beego@tcp(")

By default there is no models.go file created, so you’ll need to create one manually inside the models folder:

package models

import (

func AddUser(username string) (error) {

    o := orm.NewOrm()

    err := o.Raw("INSERT INTO users SET username = ?", username).QueryRow()

    return err


We now need to import the models file in our controller:


We must edit our UserRegister() function:

func (c *MainController) UserRegister() {

    username := c.Ctx.Input.Param(":username")

    err := models.AddUser(username)

    c.Data["Username"] = username
    c.Data["Result"] = false

    if(err == nil){
        c.Data["Result"] = true

    c.TplName = "register.tpl"


Finally we must edit our register.tpl template to inform if the user has been added to the users table:

Username: {{.Username}}
Result: {{.Result}}


Building web apps with GO’s Beego framework is easy and fast. Beego has a lot of functionality ( and is one the fastest GO frameworks (

You can download the project at: