Simplifying go-kit toolkit for Microservices – Part I

Introduction

go-kit is one of the most complete and flexible toolkits for developing microservices in Go language. At the same time, the learning curve of go-kit is steep. In this post, I’m trying to explain go-kit fundamental components using general purpose client-server model of Linux.

General Purpose Client-Server Architecture

A server in Linux binds & listens on a port, accepts connections and server requests. A client creates its own socket, makes a request to the server (IP: PORT). The request is just a buffer. The server spawns a thread or runs the handler in the same process. The handler is a function that understands request parameters and typecast it to its expected type.
The client receives a response from the server. The response is read into a buffer and then interpreted.

go-kit in Client-Server Paradigm

go-kit helps create a service. A service listens on a well-known port and IP. It is the server equivalent of Linux server. The server defines handlers for different types of request (PUT, GET, POST). A handler is a function called for a service request. The handler is a generic wrapper over service specific business logic implementation. A handler for GET call may eventually call get_status_reservation() in a sample reservation system.

go-kit intends to keep the core logic away from go-kit influence. The core logic (set of functions that your service implements) stays in a file called service.go. The remaining go-kit code tries to access these functions in an abstract manner. There are entities called endpoints, transport and server. Each of these allows a generic interaction of service functions through HTTP (or gRPC).

The overall objective is to expose service functionality through go-kit toolchain.

Transport

It defines the send and receiver buffer structure. Each service API could expect and send different data. The transport defines structures that define request and response for each API

In the next post, I will share endpoints, the most interesting part of go-kit.

Advertisements

Find a String in Files Excluding Some Files


tags: ‘shell, linux, command, development, grep,find’
categories: development

I use the following command to find a string in a Go repo. The vendor directory is not needed, so skip it.

$ find . -type f |grep -v vendor|cut -d":" -f2|xargs grep -n my_search_string

The command find all files in current directory. Next, it removes all files that have vendor in their path.

401:./.git/HEAD
402:./.git/info/exclude
403:./.git/logs/HEAD

The cut command picks the filename and passed to xargs. Each file is then processed by grep for the search string.

Golang Type Assertions: Dynamic Type Checking

Type Assertions

Go supports dynamic type checking of variables. If the type of a variable is unknown till run-time, type assertions can run a validity check.

// getRequest definition
struct getRequest {
    name string
}
// Declare a void (anonymous) type variable
request interface{}

// Checking if variable request is not nil && 
// has type getRequest. 
request.(getRequest)

Summary

  • Type Assertion does runtime type check of a variable.
  • It also checks that value is non-nil.
  • Return true on success, false otherwise.

References

Written with StackEdit.

Euler Traversal & LCA in a Tree

Euler Traversal

  • Start as ROOT --> Subtree-1 --> ROOT --> Subtree-2 --> ROOT --> Subtree-3 --> ROOT
  • Recurse at each subtree as above
  • All nodes of a subtree appear together, contiguously in the traversal.

Why Euler Traversal Gets LCA?

enter image description here
Assume we want LCA of a node u in subtree a and node v in subtree c. A Euler walk of the tree will have all nodes of the subtree a followed by the LCA node ROOT and all the nodes of subtree c.

Thus Euler walk/ traversal of a tree will always have the LCA for any two nodes.

References

Written with StackEdit.

Height of a Binary Tree: Recursion Unrolled & Explained


tags: >-
development, C++, tree, height, programming, recursion, internals, complete
flow
categories: development

Height of a Binary Tree is the longest path in the tree.

Code
int getHeight(node *root)
{
    if (root == NULL) {
        return -1;
    }
    int leftHeight = getHeight(root->left);
    int rightHeight = getHeight(root->right);

    return (max(leftHeight, rightHeight) + 1);     
}

Suppose the tree is as follows:

         [10]
          |
       [8]  [12]
              |
           [4] [5]

The recursion flow is as following:

1. getHeight(10)
2. getHeight(left of 10) ==> getHeight(8)
3. getHeight(left of 8) ==> getHeight(NULL)
4. getHeight(NULL) returns -1
5. leftHeight = -1 and flow goes back to line # 3
6. Now, it calls right of 8, getHeight(right of 8)
7. getHeight(NULL) returns -1 to rHeight
8. Both subtree of 8 are traversed and leftHeight = -1, rightHeight = -1
9. It compares both values and return the max + 1
10. max( -1, -1) + 1 = 0
11. The node 8 is left subtree of 10, and returns to line # 2.
12. At node 10, leftHeight = 0
13. Now, rightHeight is calculated by moving to right of 10.
14. getHeight(right of 10) ==> getHeight(12)
15. Similar to above, height at node 12 is calculated as 1.
16. At the end, node 12 returns its height at line #14.
17. Again we compare max (0, 1) + 1
18. The answer is 2   
Summary

Usually, all recursion steps are not visualized and just assumed to be working. This post tries to exhaust a recursion flow and help understand it better.

Kubernetes for Dummies: StatefulSet

Kubernetes provides virtualized infrastructure components such as storage, compute and network. Imagine an operating system that allows users to allocate resources and run their applications.

StatefulSet is a type of application that needs to persist information across lifetimes 🙂

The storage is exposed as a class and name. Storage class mimic real world and has meta information such as size, type and provider of the storage. Kubernetes is following plugin based approcah like Linux kernel VFS :-). You can act as a provider of storage and define a class for such storage.

Storage type could be block or file. Like Linux, a file type storage gets a mountpoint.

The following snippet defines a storage class of type SSD, using Google’s storage. Retain means we keep the data even after the node (pod) is down.

  ---
  kind: StorageClass
  apiVersion: storage.k8s.io/v1
  metadata:
    name: my-storage-class
  provisioner: kubernetes.io/gce-pd
  reclaimPolicy: Retain
  parameters:
    type: pd-ssd
    replication-type: none
  ---

gce-pd means Google Cloud Engine- Persistent Disk.

The Kubernetes template for the instance would also specify how to use the storage with a PersistentVolumeClaim. The idea is that the instance first claims a persistent volume of a particular class. It also mentions access type and needed size.

volumeClaimTemplates:
  - metadata:
      name: a-new-claim
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi

ReadWriteOnce means that the volume is mounted once for read and write. It just menas a regular storage space.

Now just use the claim under containers section.

containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        volumeMounts:
        - name: a-new-claim
          mountPath: /usr/share/nginx/html

You will have a mounted path /usr/share/nginx/html in the container. Behavior is similar to local mount exported by NFS 🙂

REFERENCES

Written with StackEdit.