How to start SLB

Neutrino can run in Virtual Machine, Bare Metals or in Container. Running Neutrino in Container is the easiest method to start Neutrino since the only requirement is docker executable. Please refer to docker website for docker installation.

Running Neutrino in Docker container

  • Create the slb.conf in "/etc/neutrino". Please refer to a sample slb.conf for reference
  • Run Docker command "docker run -d --net=host -v /etc/neutrino:/etc/neutrino -t neutrinoslb/latest"
  • Open hosts file and add canonical name(cname) entries
    • 127.0.0.1 cname1.com
    • 127.0.0.1 cnamewildcard.com
  • Run a webserver at 9999 port and/or 9998 port. Least Connection balancer will make sure that to send the traffic only if the server is up
  • Hit the URL curl cname1com:8080
  • Hit the URL curl cnamewildcard.com:8080/website

Neutrino Development Environment

If are planning to develop or modify Neutrino, it is better to install the development environment. Neutrino is developed in scala. Currently, building the core requires

  • JDK 1.7+
  • Scala 2.11+
  • SBT 0.13.7

Please follow the steps to build Neutrino

  • Checkout the Git Repo GitHub
  • Goto neutrino dir
  • Run the command "sbt pack"
  • "sbt pack" command will build Neutrino and create the jar files. You can find all the final jar files in "target/pack/lib"
  • Create the slb.conf in "/etc/neutrino". Please refer to a sample slb.conf for reference
  • Run "target/pack/sl-b"
  • Open hosts file and add canonical name(cname) entries
    • 127.0.0.1 cname1.com
    • 127.0.0.1 cnamewildcard.com
  • Run a webserver at 9999 port and/or 9998 port. Least Connection balancer will make sure that to send the traffic only if the server is up
  • Hit the URL curl cname1com:8080
  • Hit the URL curl cnamewildcard.com:8080/website

slb.conf


neutrino {
  # Use this to enable/disable the direct SLB api
  enable-api = true,
}
neutrino.datasource {
  #Refresh time for file

  refresh-period = 30s
  datasource-reader = "com.ebay.neutrino.datasource.FileReader"
}

resolvers.neutrino {


  listeners = [
    {
      # pool resolvers configured
      pool-resolver = ["cname", "layerseven"],
      # listening port of SLB
      port = 8080,
      protocol = "http"
    }
	

  ]
  
  initializers = [
    "com.ebay.neutrino.metrics.MetricsLifecycle"
  ]
  metrics = [
    # Support for console logging
    { type = "console",  publish-period = 1m }
  ]
  
  # pools configuration
  pools = [
    # pool 1, lc = least connection
    { id = "cname1_id", protocol = "http", balancer = "lc", port = "8080",
      # servers are the VM/Servers to which traffic will be routed
      servers = [
        { id="server1", host = "localhost", port = "9999" }
        { id="server2", host = "localhost", port = "9998" }
      ]
      # All traffic which comes with header Host=cname1.com will be routed to localhost.
      # cname1.com should uniquely to idenitfy a pool
      addresses = [
        { host="cname1.com" }

      ]
      # wildcard shares the balancer and protocol with addresses
      # All traffic which comes with header host=cnamewildcard.com amd path=local will be routed to localhost.
      # host + path should be unique to identify the pool
      wildcard = [
        {host="cnamewildcard.com", path="/website" }
      ]
	  timeout= {
        read-idle-timeout = 1s,
        write-idle-timeout = 1s,
        write-timeout = 1s,
        session-timeout = 1s,
        request-timeout = 1s,
        connection-timeout = 1s

      }
    },
    # pool 2
    { id = "cname2_id", protocol = "http", balancer = "round-robin", port = "8080",
      servers = [
        { id="server3", host = "www.ebay1.com", port = "80" }
      ]
      addresses = [
        {host="cname2.com" }
      ]
      wildcard = [
        {host="cnamewildcard.com", path="/ebay" }
      ]
    }

  ]
}									

								

Dynamic Configuration

Neutrino can be dynamically re-configured when it running without bringing down the connections. Following is the code which loads the confuguration in a fixed interval. Instead of that, it can changed to load the data from a API end point or DB. Also instead of a pull model, push model is implemented by exposing a update Refresh API in Neutrino


class SLBLoader extends Actor with Logging {
  import context.dispatcher

  // Create a new SLB Configuration based off the file
  val config  = SystemConfiguration(context.system)

  // Schedule a configuration reload
  override def preStart() {
    context.system.scheduler.schedule(5 seconds, config.settings.file.refreshPeriod, self, "reload")
  }

  def receive: Receive = {
    case "reload" =>
      // Create a new SLB configuration
      val results = Configuration.load("/etc/neutrino/slb.conf", "resolvers")
      logger.warn("Reloading the configuration: {}")
      config.topology.update(LoadBalancer(results))

  }
									

Multiport Configuration

Nuetrino can be configured to listen to multiple ports based on the requirements. Each pool in the configuration can be listened to a single port. But a single cname can shared between two pools, so that a cname can be listened in multiple port numbers

slb.conf


neutrino {
  # Use this to enable/disable the direct SLB api
  enable-api = true

}
neutrino.file {
  #Refresh time for file
  file-refresh-period = 30s
}

resolvers.neutrino {

  listeners = [
    {
      # pool resolvers configured
      pool-resolver = ["cname", "layerseven"],
      # listening port of SLB
      port = 8080,
      protocol = "http"
    },
    {
      # pool resolvers configured
      pool-resolver = ["cname", "layerseven"],
      # listening port of SLB
      port = 8082,
      protocol = "http"
    }

  ]
  # pools configuration
  pools = [
    # pool 1, lc = least connection
    { id = "cname1_id", protocol = "http", balancer = "lc", port = "8080",
      # servers are the VM/Servers to which traffic will be routed
      servers = [
        { id="server1", host = "localhost", port = "9999" }
        { id="server2", host = "localhost", port = "9998" }
      ]
      # All traffic which comes with header Host=cname1.com will be routed to localhost.
      # cname1.com should uniquely to idenitfy a pool
      addresses = [
        { host="cname1.com" }
        { host="cname5.com" }
        
      ]
      # wildcard shares the balancer and protocol with addresses
      # All traffic which comes with header host=cnamewildcard.com amd path=local will be routed to localhost.
      # host + path should be unique to identify the pool
      wildcard = [
        {host="cnamewildcard.com", path="/website" }
      ]
      timeout= {
        read-idle-timeout = 1s,
        write-idle-timeout = 2s,
        write-timeout = 3s,
        session-timeout = 4s,
        request-timeout = 5s,
        connection-timeout = 6s

      }
    },
    # pool 2
    { id = "cname2_id", protocol = "http", balancer = "round-robin", port = "8080",
      servers = [
        { id="server3", host = "www.ebay1.com", port = "80" }
      ]
      addresses = [
        {host="cname2.com" }
      ]
      wildcard = [
        {host="cnamewildcard.com", path="/ebay" }
      ]
    },

    # pool 3
    { id = "cname3_id", protocol = "http", balancer = "round-robin",  port = "8082",
      servers = [
        { id="server4", host = "www.yahoo.com", port = "80" }
      ]
      addresses = [
        {host="cname2.com" }
      ]
    }

  ]
}
									

Grapite Integration for metrics

Graphite is a useful tool to show metrics and it is opensource. Nuetrino allows metrics can be pushed to either to the console or to graphite. It is easy by adding following lines in slb.conf


resolvers.neutrino {

  listeners = [
    {
      # pool resolvers configured
      pool-resolver = ["cname", "layerseven"],
      # listening port of SLB
      port = 8080,
      protocol = "http"
    }

  ]
  
  initializers = [
    "com.ebay.neutrino.metrics.MetricsLifecycle"
  ]
  metrics = [
    # Support for console logging
    { type = "console",  publish-period = 1m },

    # Support for graphite publishing
    { type = "graphite", publish-period = 1m, host = "host where graphite is installed",port = 2003 }
  ]
									

Configuring Netty Thread count

Number of threads for handling connections can configured for each purpose. By default, number of Supervisor thread count is 1 and Worker thread count is 4. The Supervisor thread accepts an incoming connection. The Worker thread handles the traffic of the accepted connection once the Supervisor accepts the connection and registers the accepted connection to the worker. Please refer to the Netty Article to know about Netty Threads.


neutrino {
  # Use this to enable/disable the direct SLB api
  enable-api = true,
  
  supervisorThreadCount = 2,

  workerThreadCount = 8

}
									

Contributions

Any helpful feedback is more than welcome. This includes feature requests, bug reports, pull requests, constructive feedback, and etc. You must agree on this before submitting a pull request. Please reach out to the google groups for any questions

Credits & Acknowledgement

We thanks our manager Srivathsan Canchi, Sujit Gupta, Cloud Infrastructure & Platform Services (CIPS) and legal for the big support on this project and the open source effort.

Authors

Neutrino is served to you by Chris Brawn, Blesson Paul and eBay PaaS Team.