Sunday, April 29, 2018

How to scale your services with session affinity on docker in 5 minutes!

Assumes you know docker, docker swarm concepts and can understand something easy about node.js
Developing services with an eye on scalability? Who isn't right! This should give you some ideas on how to minimally setup and run a load balancer with your docker swarm to create sticky sessions where you want them.
I have two example Node.js services in this use case running, one of which I wish to track application state, and the other running stateless.
  1. Create two of these index.js files in separate directories, service1 and service2.
  2. Change the src root /serviceX and the res.end(`<h1> I'm serviceX.... to service1 and service2 to match the aforementioned directory naming
  3. In each service dir run npm init, then npm i S cookie-parser express express-session
  4. run node index.js and test each out individually by hitting localhost:8080/serviceX, you should see each subsequent reload increment a counter.
var express = require('express');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var os = require('os');
var app = express();

app.use(cookieParser());

app.use(session({secret: "Shh, its a secret!"}));

app.get('/service1', function(req, res){

   if(req.session.page_views){

      req.session.page_views++;

   } else {

      req.session.page_views = 1;

   }

     res.writeHead(200, {'Content-Type': 'text/html'});

     res.write(JSON.stringify(req.headers));     

     res.end(`<h1>I'm service1 on ${os.hostname()} non unique visits ${req.session.page_views}</h1>`);

});

app.listen(8080);

Now dockerize each service like this in directories service1, service2, with a Dockerfile.
FROM node

RUN mkdir -p /usr/src/app

COPY index.js /usr/src/app

COPY package*.json ./

RUN npm install

EXPOSE 8080

CMD ["node","/usr/src/app/index"]
  1. Add a .dockerignore file in each to leave behind the modules.
node_modules

npm-debug.log
2. Build a docker image in each directory docker build -t serviceX .
3. Build a docker compose file, one level up from the service dirs, here it is
version: '3'

services:

  service1:

   image: service1 

   ports:

     - 8080

   environment:

     - SERVICE_PORTS=8080

     - COOKIE=connect.sid prefix nocache

     - VIRTUAL_HOST=*/service1

   deploy:

     replicas: 2

     update_config:

       parallelism: 5

       delay: 10s

     restart_policy:

       condition: on-failure

       max_attempts: 3

       window: 120s

   networks:

     - web



  service2:

   image: service2 

   ports:

     - 8080

   environment:

     - SERVICE_PORTS=8080

     - VIRTUAL_HOST=*/service2

   deploy:

     replicas: 2

     update_config:

       parallelism: 5

       delay: 10s

     restart_policy:

       condition: on-failure

       max_attempts: 3

       window: 120s

   networks:

     - web



  proxy:

    image: dockercloud/haproxy

Only two replicas, make it whatever you want. What's really interesting about this are two things, BOTH javascript files build a session but only one in the compose file is affinity assigned, service1.
- COOKIE=connect.sid prefix nocache
That's the default cookie name given by express-session you can of course make changes to that, prefix adds the server routing and nocache is uh, no cacheing it.
The other thing interesting is this entry, virtual hosts, these must match the /root of your services for routing purposes, both services must have this unless you are serving from a plain root e.g. "/"
 - VIRTUAL_HOST=*/service1
Run this command to launch the replicated services with affinity on service1.
  1. docker swarm init
  2. docker stack deploy --compose-file=docker-compose.yml test
  3. docker service -ls
  4. point to localhost/serviceX for results, service1 will be sticky and incrementing each time, service2 you will see a new service and session each time. Clear cookies to get over to another server1.
Here are the official options for haproxy.
http://cbonte.github.io/haproxy-dconv/1.9/configuration.html#7.1
I'd add this to git but five min was up ten minutes ago.

Saturday, September 12, 2015

Summit Everest! Surviving the engineering death zone.




The lifecycle of a software product can seem mysteriously vague,  complex, or overly simplified depending on the audience.  I liken it to a climb with the highs, lows, and ultimately a conquest or defeat.

Base Camp

The beginning of a new project and the buzz of fresh energy throughout the team is palpable.  Ideas, roles, and a vision of the possible emerges from every situation or get together. The morale and excitement is at an all time high! Every creature comfort is available and the team starts off as well rested and prepared as they will ever be.

Camp One

Camp one is reached in record time, the time to market forecast is being wildly exceeded as sheer energy and momentum lifts the team seemingly without effort. Prototypes and functionality appear weekly out of nowhere.  Checkins litter the git history from what looks like 24/7 output people trying to write as fast as their brains can think.  Product management is struggling to keep track of all the new work.
   

Camp Two

Camp two is also quickly reached but the renaissance of creativity yields to the thinner air of coalescing effort. Some time is now being spent acclimatizing instead of rapidly moving forward, fewer feature branches appear as product management steers a unified course up the mountain.  Some re-planning and adjustment are implemented.

Camp Three (Lhotse wall)   

Arrival at camp three is signaled by the teams progress velocity returning to real world numbers. It took longer to get here then expected, maybe a lot longer. A unified codebase along with the requisite build and test process has appeared. Creativity is scaled back to solving many of the initial hand waves done earlier in the climb that kept the forward momentum at the expense of problem solving each detail.  Some doldrums will set in and those truly in shape will seem less affected,  leaders may rise and fall here.

Camp Four (The death zone)

You have reached the death zone, this is the 10% of remaining work that will take 90% of the projects total effort to complete.  The go to market schedule which was insanely optimistic and ahead of schedule now suddenly seems to be behind.  The engineering progress as been reduced to a crawl. Any small change in requirements,  code refactoring, or new feature development has wide ranging implications that can tie up the team for days to sort out.  As people sip oxygen from what remains in the tanks it takes supreme confidence and leadership to overcome the fear and exhaustion for the final push to the summit.  Lingering at camp four seems to go on forever,  you must have confidence.

At this point it can sometimes be necessary to bring in finishers to help with the final push. Finishers are fresh eyes and legs that can give some perspective to the team that is not tunnel visioned or snow-blinded from fighting up every inch of the trail to this point,  A fresh perspective can help chart the easiest path to the summit, it can also lead you into an avalanche so the right guide is CRUCIAL.

Summit 

What needs to be said here really, pop a champagne and take a picture. But don't tarry or bask too long on the top of the world its dangerous to do so. Quickly get back down to basecamp to rest and rebuild the team, and begin to prepare for the next climb.

Thursday, June 12, 2014

Google Web Toolkit (GWT) Event Bus

Recently doing some GWT development and wanted to expand an example of the toolkit's event bus.
This contrived example doesn't involve widgets, or UI handling and is only meant to highlight the principle using simple example/pseudo-code. This assumes some knowledge on the internal workings of the GWT Event Bus or observer design pattern, treated as a black box here.

Imagine a virtual restaurant where you have a cook, waiter, and a customer.

The business process is, "The waiter takes the customer's order and gives it to the cook."
In this familiar scenario you have; cook, waiter, order, and customer.

In the GWT Event Bus world you have Events, Event Handlers, and Entities(Widgets, Objects etc).

Mapping to our little scenario thusly.

Events {OrderPlacedEvent}
Event Handler {OrderPlacedEventHandler}
Entity {Waiter, Customer, Order}

The real question is, how to design for an event bus, or, what to design first?

Handlers are used by entities that need to "handle" events.  Our waiter is interacting directly with the customer and so doesn't need to handle an order "event", he's the interface (virtually maybe) taking/constructing the orders. The cook on the other hand is in the kitchen and busy doing non customer related tasks, but he's very interested in orders so he can do his job of making the food.

So, the cook wants to be informed of orders being placed, and what they are, and the waiter will be the one to inform. With the event bus ANYONE can be informed about the order immediately as it's placed, cooks, managers, supply systems, etc.

First thing is to create the Handler. The reason is that the Event will actually need to register the Handler Type in the Event bus, and your Event will also reference it.

/**
 *
 */
public interface OrderPlacedEventHandler extends EventHandler {

     void onOrderPlaced(OrderPlacedEvent event);

}

Now we have a handler interface with a method to invoke with an event IF one occurs.

Next we create OrderPlacedEvent,  but first the order would be helpful.

/**
 *
 */
public class Order{ 

      private List<FoodItems> items;          

      public Order(FoodItems...items){
            items = new ArrayList<>(Arrays.asList(items));
      }

      public List<FoodItems> getItems{
             return this.items; 
      }
      ...
}

The actual Event, conventions as per GWT plus a reference to the order.

/**
 *
 */
public class OrderPlacedEvent extends GwtEvent<OrderPlacedEventHandler>{

       public final Order order;
       public static final Type<OrderPlacedEventHandler> TYPE =
                                     new TYPE<OrderPlacedEventHandler>();

        public OrderPlacedEvent(Order order){
              this.order = order;
        }

        public Order getOrder(){
              return this.order;
        }

       @Override
        public Type<OrderPlacedEventHandler> getAssociatedType() {
              return TYPE;
        }

        @Override
        protected void dispatch(OderPlacedEventHandler handler) {
               handler.onOrderPlaced(this);
        }

}


The cook needs to register the handler and do something with the return value, in this simple case he adds it to the internal list of orders he's working on. The event bus listens for the TYPE to arrive and then iterates through every registered handler calling it's implementation as defined in dispatch.

/**
*
*
*/
public class Cook{

     private List<Order> orders = new ArrayList<>();

     public Cook(EventBus bus){
                eventBus.addHandler(new OrderPlacedEventHandler(){
                                void onOrderPlaced(OrderPlacedEvent event){
                                                   addOrder(event.getOrder);
                                                   }}, OrderPlacedEvent.TYPE);
     }

     public addOrder(Order order){
              orders.add 
     }     
}


Waiter will be the one to "fire off" an order placed event to let everyone know at the end of his order taking process.


/**
 *
 */
public class Waiter{

    private EventBus eventBus;
    
    public Waiter(EventBus eventBus){
            ...

     }

     public void takeFoodOrder(Order order){ 
           ...
         eventBus.fireEvent(new OrderPlacedEvent(order));

      }

}



That's it! Hope it clears up some of the design and workings using this simple scenario.  I highly suggest using the EventBinder when coding in GWT proper instead the classes you see here, does all the same things but it's less coding!