<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Logistimo Engineering Blog - Medium]]></title>
        <description><![CDATA[Insights from building tech for the last mile. Big data, SaaS, Android, Kubernetes.. - Medium]]></description>
        <link>https://medium.com/logistimo-engineering-blog?source=rss----b690d71b4d79---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Logistimo Engineering Blog - Medium</title>
            <link>https://medium.com/logistimo-engineering-blog?source=rss----b690d71b4d79---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 23:34:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/logistimo-engineering-blog" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[OSRM data generation and deployment]]></title>
            <link>https://medium.com/logistimo-engineering-blog/osrm-data-generation-and-deployment-2f5a66269342?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/2f5a66269342</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[openstreetmap]]></category>
            <category><![CDATA[maps]]></category>
            <category><![CDATA[osrm]]></category>
            <category><![CDATA[routing]]></category>
            <dc:creator><![CDATA[Narendiran D]]></dc:creator>
            <pubDate>Tue, 23 Jun 2020 09:32:20 GMT</pubDate>
            <atom:updated>2020-06-25T07:01:35.691Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fhbkyl9rQ5qw9MjarB1YZg.png" /><figcaption>Open Source Routing Machine</figcaption></figure><p>The Open Source Routing Machine (OSRM) is an open-source router designed for use with data from the OpenStreetMap project. The following services are available via HTTP API, C++ library interface and NodeJs wrapper:</p><ul><li>Nearest — Snaps coordinates to the street network and returns the nearest matches</li><li>Route — Finds the fastest route between coordinates</li><li>Table — Computes the duration or distances of the fastest route between all pairs of supplied coordinates</li><li>Match — Snaps noisy GPS traces to the road network in the most plausible way</li><li>Trip — Solves the Traveling Salesman Problem using a greedy heuristic</li><li>Tile — Generates Mapbox Vector Tiles with internal routing metadata</li></ul><h4>Why OpenStreetMap over Google Maps ?</h4><p>Open Street Maps (OSM) is an open source project maintained by the OpenStreetMap Community that provides free editable maps of the whole world. The most obvious advantage in using OpenStreetMap-based software over a commercial solution is economical convenience, because OpenStreetMap comes as free software.</p><p>The downside is that it takes a little configuration in order to setup a working web service. The easiest and quickest way to setup your own routing engine is to use Docker images</p><p>There are two pre-processing pipelines available:</p><ul><li>Contraction Hierarchies (CH)</li><li>Multi-Level Dijkstra (MLD)</li></ul><p>We recommend using MLD by default except for special use-cases such as very large distance matrices where CH is still a better fit for the time being. In the following we explain the MLD pipeline. If you want to use the CH pipeline instead replace osrm-partition and osrm-customize with a single osrm-contract and change the algorithm option for osrm-routed to --algorithm ch.</p><h4>Generate data using Docker:</h4><p>Our web service will be based on a map export from OpenStreetMap. There are several possible ways to obtain a map export.</p><p>The first option is to point your browser to the OpenStreetMap’s <a href="http://www.openstreetmap.org/export">export page</a>, zoom on the interested area, and click on Export. (You may need to use one of the other sources if the native export does not work; Overpass API is a good choice.) This will allow you to finely choose which areas to include in your map and, in general, to cut down on the pre-processing times.</p><p><a href="https://www.openstreetmap.org/export#map=6/16.225/73.059">https://www.openstreetmap.org/export#map=6/16.225/73.059</a></p><p>However, there are limits on the size of the export you can get from the OSRM website, so you might want to download a ready-made export. A number of services, such as <a href="http://download.geofabrik.de/">Geofabrik</a> and <a href="https://mapzen.com/metro-extracts">Mapzen</a> offer updated and ready-made map exports of countries and selected metropolitan areas, which are good for most use cases.</p><p>In this article we will see how the OSRM data is generated for India using MLD pipeline.</p><p>To generate the routing data you need to download the <strong>.<em>pbf</em> </strong>file for India from <a href="http://download.geofabrik.de/">Geofabrik</a>.</p><pre><em>wget http://download.geofabrik.de/asia/india-latest.osm.pbf</em></pre><p>OSM data comes in a variety of formats including XML and PBF, and contain a plethora of data. The data includes information which is irrelevant to routing, such as positions of public waste baskets. Also, the data does not conform to a hard standard and important information can be described in various ways. Thus it is necessary to extract the routing data into a normalized format. This is done by the OSRM tool named extractor.</p><p><a href="https://github.com/Project-OSRM/osrm-backend/wiki/Profiles">Profiles</a> are used during this process to determine what can be routed along, and what cannot (private roads, barriers etc.).</p><p>For the MLD pipeline we need to extract (osrm-extract) a graph out of the OpenStreetMap base map</p><pre><em>docker run -t -v $(pwd):/data osrm/osrm-backend:latest osrm-extract -p /opt/car.lua /data/india-latest.osm.pbf</em></pre><p>The flag -v $(pwd):/data creates the directory /data inside the docker container and makes the current working directory $(pwd) available there. The file /data/india-latest.osm.pbf inside the container is referring to $(pwd)/india-latest.osm.pbf on the host</p><p>Then partition (osrm-partition) this graph recursively into cells, by using the following command</p><pre><em>docker run -t -v $(pwd):/data osrm/osrm-backend:latest osrm-partition /data/india-latest.osrm</em></pre><p>Note that india-latest.osrm has a different file extension.</p><p>Once the graph is partitioned in to cells, customize the cells (osrm-customize) by calculating routing weights for all cells</p><pre>docker run -t -v $(pwd):/data osrm/osrm-backend:latest osrm-customize /data/india-latest.osrm</pre><p>For CH the partition and customize pipeline stage gets replaced by adding shortcuts from the Contraction Hierarchies algorithm (osrm-contract)</p><p>Once the graph is customized, then spawning up the development HTTP server (osrm-routed) responding to queries</p><h4>OSRM Docker Deployment</h4><p>Docker image can be run standalone without Kubernetes</p><pre>docker run -t -i -p 5000:5000 -v $(pwd):/data -d osrm/osrm-backend:latest osrm-routed — algorithm mld /data/india-latest.osrm</pre><p>Make requests against the HTTP server</p><p>Optionally start a user-friendly frontend on port 9966, and open it up in your browser</p><pre><em>docker run -p 9966:9966 osrm/osrm-frontend</em></pre><h4>OSRM Kubernetes Deployment</h4><p>To deploy the OSRM in Kubernetes cluster, we need the routing data inside the Kubernetes cluster. There are multiple ways to achieve this. The reliable way is to use persistent volume model in a dynamic Kubernetes cluster. On a standalone k8s cluster the simple and easiest way is to use the hostPath.</p><p>To deploy on standalone cluster once the data generation is completed, copy all the generated files to the following location <strong><em>/data/osrm/india</em></strong> on the server. Make sure this data is available on all the Kubernetes nodes.</p><p>Now use the below mentioned YAML file to deploy the osrm-backend application in k8s.</p><p><em>osrm-backend-india.yaml</em></p><pre>apiVersion: v1<br>kind: Service<br>metadata:<br>  name: osrm-india<br>  labels:<br>    app: osrm-india<br>spec:<br>  ports:<br>  - port: 5000<br>    targetPort: 5000<br>    name: http<br>  selector:<br>    app: osrm-india<br>  type: NodePort<br>---<br>apiVersion: extensions/v1beta1<br>kind: Deployment<br>metadata:<br>  name: osrm-india<br>spec:<br>  replicas: 1<br>  template:<br>    metadata:<br>      labels:<br>        app: osrm-india<br>    spec:<br>      containers:<br>      - name: osrm-india<br>        image: osrm-backend:latest<br>        command: [&quot;/bin/sh&quot;, &quot;-c&quot;]<br>        args: [&quot;osrm-routed --algorithm mld /data/india-latest.osm.pbf&quot;]<br>        ports:<br>        - containerPort: 5000<br>          name: osrm-port<br>        volumeMounts:<br>        - name: india<br>          readOnly:  true<br>          mountPath: /data<br>      volumes:<br>      - name: india<br>        hostPath:<br>          path: /data/osrm/india<br>        resources:<br>          requests:<br>            memory: &quot;512Mi&quot;<br>            cpu: &quot;0.5&quot;<br>          limits:<br>            memory: &quot;512Mi&quot;<br>            cpu: &quot;0.5&quot;</pre><p>Below config make sure the data is mounted to the docker container while deploying</p><pre>        volumeMounts:<br>        - name: india<br>          readOnly:  true<br>          mountPath: /data<br>      volumes:<br>      - name: india<br>        hostPath:<br>          path: /data/osrm/india</pre><p>Command to run the osrm-backend image in Kubernetes</p><pre>kubectl apply -f <em>osrm-india.yaml</em></pre><p>To deploy the user-facing frontend with map, apply the below file</p><p><em>osrm-frontend.yaml</em></p><pre>kind: Service<br>metadata:<br>  name: osrm-frontend<br>  labels:<br>    app: osrm-frontend<br>spec:<br>  ports:<br>  - port: 9966<br>    targetPort: 9966<br>    name: http<br>  selector:<br>    app: osrm-frontend<br>  type: NodePort<br>---<br>apiVersion: extensions/v1beta1<br>kind: Deployment<br>metadata:<br>  name: osrm-frontend<br>spec:<br>  replicas: 1<br>  template:<br>    metadata:<br>      labels:<br>        app: osrm-frontend<br>    spec:<br>      containers:<br>      - name: osrm-frontend<br>        image: osrm/osrm-frontend<br>        ports:<br>        - containerPort: 9966<br>          name: osrm-frontend<br>        env:<br>        - name: BACKEND<br>          value: &#39;<a href="http://osrm-backend:5000&#39;">http://osrm-india:5000&#39;</a></pre><p>Command to run the osrm-backend image in Kubernetes</p><pre>kubectl apply -f <em>osrm-frontend.yaml</em></pre><p><strong>Note:</strong></p><p>OSRM data can be generated for any countries. The data generation consumes lot of memory on your server based on the country . To generate OSRM data for India, docker runs consumes almost 7 GB of RAM on the server.</p><h4>Conclusion</h4><p>This blog covers the configuration and maintenance of a web service which can answer questions such as:</p><ul><li>What is the closest street to a given pair of coordinates?</li><li>What’s the best way to get from point A to point B?</li><li>How long does it take to get from point A to point B with a car, or by foot?</li></ul><h4><strong>References</strong></h4><ul><li><a href="https://download.geofabrik.de/">Geofabrik Download Server</a></li><li><a href="https://extract.bbbike.org/">BBBike extracts OpenStreetMap</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2f5a66269342" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/osrm-data-generation-and-deployment-2f5a66269342">OSRM data generation and deployment</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Programming and Broken windows]]></title>
            <link>https://medium.com/logistimo-engineering-blog/programming-and-broken-windows-5a52bb1b3f0b?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/5a52bb1b3f0b</guid>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Charan Malemarpuram]]></dc:creator>
            <pubDate>Tue, 23 Jun 2020 09:29:26 GMT</pubDate>
            <atom:updated>2020-06-23T09:29:26.807Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/797/1*F-q_f6BR6mB74Ke5L-nUUA.jpeg" /><figcaption>By Joshua Jebb or employee — <a href="http://www.ucl.ac.uk/Bentham-Project/journal/Steadman_fig19.htm">http://www.ucl.ac.uk/Bentham-Project/journal/Steadman_fig19.htm</a>, Public Domain, <a href="https://commons.wikimedia.org/w/index.php?curid=2993483">https://commons.wikimedia.org/w/index.php?curid=2993483</a></figcaption></figure><p>I was quite fascinated by a simple principle defined by Andrew Hunt and David Thomas in their <a href="https://read.amazon.in/kp/embed?asin=B003GCTQAE&amp;preview=newtab&amp;linkCode=kpe&amp;ref_=cm_sw_r_kb_dp_TGe8EbPQF1SRJ">Pragmatic programmer book</a> derived from the “<a href="https://www.britannica.com/topic/broken-windows-theory">Broken window theory</a>” in programming. This book was originally published in 1999, but the principles apply to this date. <a href="https://www.amazon.com/Freakonomics-Revised-Edition-audiobook/dp/B000TK5BS2/ref=sr_1_2?dchild=1&amp;keywords=Freakanomics&amp;qid=1592805671&amp;s=books&amp;sr=1-2">Freakanomics</a> is where I have originally encountered this theory, some years ago. I was probably more interested in the economics part of it then. It is quite brilliant in my view to apply this to software development.</p><p>The crux of the broken window theory in it’s original context was that</p><blockquote>Disorder causes crime, Crime causes further disorder and crime.</blockquote><p>It is not hard to imagine what this would mean in the software world. Imagine a project where there is large code base but has limited tests, when a piece of code is submitted, It is unlikely that the new code being submitted has tests to cover. Compare this to a codebase in the same project and has good unit test coverage, would the same developer submit code without tests? Extremely unlikely. We can extend this to bugs, technical debt, design, quality of pull requests, documentation and everything else that is involved in software development.</p><p>So, over sufficient time in projects that are not managed well, a lot of disorder occurs which makes it even more difficult to maintain order later on. Entropy kicks in.</p><h4>Software entropy</h4><p>Entropy in physics, defines the amount of disorder in a system. And the amount of disorder tends to reach maximum over time, according to laws of physics. Any software system, if not managed well through the time will tend to “rot”. Bad designs, wrong decisions or just plain badly written code if left unrepaired will cause more disorder and rot.</p><p>The most important reason for Software entropy is the culture of the team. It is the mindset of the team, regardless of the size of the team that matters. When the team maintains and fixes the broken pieces at the earliest, the rot naturally reduces. This is precisely the point of the “Broken window theory”, isn’t it?</p><blockquote>Don’t live with broken windows</blockquote><p>Good teams strive to fix broken windows at the earliest, and will continue to maintain the hygiene of the software. If not possible to fix and some times it really may not possible, at least have a plan and board it up temporarily. But again, the culture if the team tends to frequently resort to boarding up temporarily, then it would end up in the same rot again.</p><h4>What do you do about existing broken windows?</h4><p>Let’s say hypothetically (most possibly practically), we are working on a project which has lot of broken windows, what should we do now. One succesful strategy is to aggressively identify all broken windows, board them up, plan “Refactoring”, talk to your boss, the benefits of fixing it have to outweigh. I am not going to talk about how you convince your team, but usually benefits outweigh the cost of effort in long run and you can negotiate a time in upcoming sprint/release for sure.</p><p>Go ahead and chalk out a plan to aggressively fix those broken windows now.</p><p>Due credit has to go to the authors of this book for this simple and effective insight. If you have not read <a href="https://read.amazon.in/kp/embed?asin=B003GCTQAE&amp;preview=newtab&amp;linkCode=kpe&amp;ref_=cm_sw_r_kb_dp_TGe8EbPQF1SRJ&amp;reshareId=7T0Y7H50RT222K511YEQ&amp;reshareChannel=system">The Pragmatic programmer book</a>, it is never a bad time to learn from the best.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a52bb1b3f0b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/programming-and-broken-windows-5a52bb1b3f0b">Programming and Broken windows</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tomcat JVM metrics monitoring using Prometheus in Kubernetes]]></title>
            <link>https://medium.com/logistimo-engineering-blog/tomcat-jvm-metrics-monitoring-using-prometheus-in-kubernetes-c313075af727?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/c313075af727</guid>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[prometheus]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Narendiran D]]></dc:creator>
            <pubDate>Mon, 11 Feb 2019 13:02:56 GMT</pubDate>
            <atom:updated>2019-05-18T03:04:09.649Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ENTzvKobw86_5oDI78gT0w.png" /></figure><p>Monitoring metrics and runtime characteristics of an application server is essential to ensure the adequate functioning of the applications running on that server, as well as to prevent or resolve potential issues in a timely manner. As far as Java applications go, one of the most commonly used web application servers is Apache Tomcat, which will be the focus of this article.</p><p>Tomcat performance monitoring in Kubernetes cluster can be done either by relying on JMX beans or other tools available in the market. We have listed the prerequisite with which this monitoring can be achieved.</p><ol><li>Prometheus Agent</li><li>Kubernetes YAML for application</li><li>Annotations</li><li>Scraping Policy</li><li>Prometheus Server</li></ol><h4>Prometheus Agent</h4><p>Prometheus provides a collector that can scrape and expose the mBeans of a JMX target. It runs as a Java Agent, exposing an HTTP server and serving metrics of the local JVM. It can also be run as an independent HTTP server and scrape remote JMX targets, but this comes with various disadvantages, such as it being harder to configure and it being unable to expose process metrics (e.g., memory and CPU usage). Running the exporter as a Java Agent is thus strongly encouraged.</p><p>The following Dockerfile adds support for the options we’ve listed.</p><pre>FROM tomcat</pre><pre>RUN mkdir /data</pre><pre>ADD jmx_prometheus_javaagent-0.7-SNAPSHOT.jar /data/jmx_prometheus_javaagent-0.7-SNAPSHOT.jar</pre><pre>ADD prometheus-jmx-config.yaml /data/prometheus-jmx-config.yaml</pre><pre>CMD java -javaagent:/data/jmx_prometheus_javaagent-0.7.jar=8088:/data/prometheus-jmx-config.yaml -jar $TOMCAT_HOME/start.jar</pre><ul><li>Connect to an exposed JMX port of the JVM (not recommended)</li><li>Java agent version (recommended)</li></ul><p>If you use the agent version, you’ll have to modify three configuration options:</p><ul><li>the Jar file location</li><li>the port for the http(s) interface, where the metrics will be available for scraping, already in Prometheus friendly format</li><li>additional configuration options</li></ul><p>An example looks like this:</p><pre><em>-javaagent:/opt/jmx-exporter/</em>jmx_prometheus_javaagent-0.7.jar<em>=8088</em></pre><p>The latest jar can be downloaded from the following link:</p><pre>wget <a href="http://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.7/jmx_prometheus_javaagent-0.7.jar">http://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.7/jmx_prometheus_javaagent-&lt;latest-version&gt;.jar</a></pre><p>Create<em> prometheus-jmx-config.yaml with following config in it</em></p><pre>---<br>hostPort: 127.0.0.1:1234<br>lowercaseOutputName: false<br>lowercaseOutputLabelNames: false</pre><p>The complete options for the prometheus-jmx-config.yaml <em>is available </em><a href="https://github.com/prometheus/jmx_exporter"><em>here</em></a><em>.</em></p><h4>Kubernetes YAML for application</h4><p>When you run the tomcat image in Kubernetes infrastructure, the JMX port needs to be exposed to scrape the data from the container. Following sample tomcat YAML file shows how to deploy the basic tomcat service in K8s infrastructure with prometheus JMX port exposed and annotated.</p><pre>apiVersion: v1<br>kind: Service<br>metadata:<br>  name: &lt;service name&gt;<br>  labels:<br>    app: &lt;service name&gt;<br>spec:<br>  ports:<br>  - port: 8080<br>    targetPort: 8080<br>    name: http<br>  - port: 8088<br>    targetPort: 8088<br>    name: prom<br>  selector:<br>    app: &lt;service name&gt;<br>  type: NodePort<br>---<br>apiVersion: extensions/v1beta1<br>kind: Deployment<br>metadata:<br>  name: &lt;deployment name&gt;<br>spec:<br>  # this replicas value is default<br>  # modify it according to your case<br>  replicas: 1<br>  template:<br>    metadata:<br>      labels:<br>        app: &lt;deployment name&gt;<br>        type: java<br>      annotations:<br>        prometheus.io/scrape: &#39;true&#39;<br>        prometheus.io/port: &#39;8088&#39;<br>    spec:<br>      containers:<br>      - name: &lt;container name&gt;<br>        image: &lt;docker image&gt;<br>        ports:<br>        - containerPort: 8080<br>        env:<br>        - name: JAVA_AGENT_PORT<br>          value: &quot;8088&quot;<br>        resources:<br>          requests:<br>            memory: &quot;1024Mi&quot;<br>            cpu: &quot;1&quot;<br>          limits:<br>            memory: &quot;1024Mi&quot;<br>            cpu: &quot;1&quot;</pre><h4>Annotations</h4><p>Annotations on pods allow a fine grained control of the scraping process:</p><ul><li>prometheus.io/scrape: The default configuration will scrape all pods and, if set to false, this annotation will exclude the pod from the scraping process.</li><li>prometheus.io/path: If the metrics path is not /metrics, define it with this annotation.</li><li>prometheus.io/port: Scrape the pod on the indicated port instead of the pod’s declared ports (default is a port-free target if none are declared).</li></ul><p>These annotations need to be part of the pod metadata. They will have no effect if set on other objects such as Services or DaemonSets. The above Deployment manifest will instruct Prometheus to scrape all of its pods on port 8088.</p><h4>Scraping Policy</h4><p>To minimise the amount of configuration required from the user, the default setup will try to scrape all pods present in the system. This may have some undesirable side-effects such as:</p><ul><li>Prometheus issuing HTTP GET requests to TCP ports not even exposing an HTTP server.</li><li>Prometheus issuing HTTP GET requests to fetch /metrics on services that may not export any metric, polluting logs.</li></ul><p>While the annotations described in the previous section allow the user to <strong>opt-out</strong> of the scraping process, we also offer an alternative Prometheus configuration that only scrapes a minimal set of system metrics and requires the user to <strong>opt-in</strong> on a per-pod basis. In other words, in this mode the prometheus.io/scrape: true annotation is required for Prometheus to scrape the pod.</p><p>Now that we have all the required configs in place to scrape the JVM data from the tomcat container. Let see how it can be scraped via prometheus server.</p><h4>Prometheus Server</h4><p>Prometheus is a monitoring platform that collects metrics from monitored targets by scraping metrics HTTP endpoints on these targets. Please use the following docker-compose.yaml for downloading the Prometheus Image</p><pre>---<br>version: &#39;2&#39;<br>services:<br>  prometheus:<br>    container_name: prometheus<br>    image: prom/prometheus:latest<br>    restart: always<br>    ports:<br>      - &quot;9090:9090&quot;<br>    volumes:<br>    - /data/prometheus/prometheus.yml:/prometheus/prometheus.yml:ro<br>    command: [ &#39;--config.file=/prometheus/prometheus.yml&#39;, &#39;--web.enable-lifecycle&#39;, &#39;--web.enable-admin-api&#39;, &#39;--storage.tsdb.retention=1y&#39; ]</pre><h4>Configuring Prometheus</h4><p>The Prometheus download comes with a sample configuration in a file called prometheus.yml</p><pre>global:<br>  scrape_interval:     15s<br>  evaluation_interval: 15s<br><br>rule_files:<br>  # - &quot;first.rules&quot;<br>  # - &quot;second.rules&quot;<br><br>scrape_configs:<br>  - job_name: &#39;prometheus<br>    scrape_interval: 30s<br>    kubernetes_sd_configs:<br>    - role: pod<br>      namespaces:<br>        names:<br>        - staging<br>    scheme: http<br>    relabel_configs:<br>    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]<br>      action: keep<br>      regex: true<br>    - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]<br>      action: replace<br>      regex: ([^:]+)(?::\d+)?;(\d+)<br>      replacement: $1:$2<br>      target_label: __address__<br>    - action: labelmap<br>      regex: __meta_kubernetes_pod_label_(.+)<br>    - source_labels: [__meta_kubernetes_namespace]<br>      action: replace<br>      target_label: kubernetes_namespace<br>    - source_labels: [__meta_kubernetes_pod_name]<br>      action: replace<br>      target_label: kubernetes_pod_name</pre><p>There are three blocks of configuration in the example configuration file: global, rule_files, and scrape_configs.</p><ul><li>The global block controls the Prometheus server&#39;s global configuration. We have two options present. The first, scrape_interval, controls how often Prometheus will scrape targets. The evaluation_interval option controls how often Prometheus will evaluate rules.</li><li>The rule_files block specifies the location of any rules we want the Prometheus server to load. For now we&#39;ve got no rules.</li><li>The last block, scrape_configs, controls what resources Prometheus monitors. Since Prometheus also exposes data about itself as an HTTP endpoint it can scrape and monitor its own health. Prometheus expects metrics to be available on targets on a path of /metrics. So this default job is scraping via the URL: <a href="http://localhost:9090/metrics">http://&lt;hostname&gt;:9090/metrics</a>.</li></ul><p>When you scrape data from the containers running inside the Kubernetes cluster, don’t forget to mentions the namespace from where the data should be scraped as mentioned in the above config file.</p><p>Once you have all prerequisites configured and deployed, the JVM metrics will be collected and stored in the prometheus. We use Grafana to create a graphical dashboard and measure the performance as shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EdamiGwYa_VLNhKHL-ksXA.png" /><figcaption>Kube JVM Metrics</figcaption></figure><p><strong>References</strong></p><ul><li><a href="https://grafana.com/dashboards/3066">JVM overview - Prometheus dashboard for Grafana</a></li><li><a href="https://github.com/prometheus/jmx_exporter">GitHub - prometheus/jmx_exporter: A process for collecting metrics using JMX MBeans for Prometheus consumption</a></li><li><a href="https://docs.docker.com/config/thirdparty/prometheus/">Collect Docker metrics with Prometheus</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c313075af727" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/tomcat-jvm-metrics-monitoring-using-prometheus-in-kubernetes-c313075af727">Tomcat JVM metrics monitoring using Prometheus in Kubernetes</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OOM Killer and Java applications]]></title>
            <link>https://medium.com/logistimo-engineering-blog/oom-killer-and-java-applications-c0dfd7f6b036?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/c0dfd7f6b036</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[containers]]></category>
            <dc:creator><![CDATA[Charan Malemarpuram]]></dc:creator>
            <pubDate>Fri, 11 Jan 2019 04:41:00 GMT</pubDate>
            <atom:updated>2019-01-11T04:18:04.404Z</atom:updated>
            <content:encoded><![CDATA[<h3>OOM Killer and Java applications in containers</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*x_onkS0e1sTKEecG69fUVA.png" /></figure><p>At <a href="http://www.logistimo.com/">Logistimo</a>, all of our applications are containerized and run as docker containers inside Kubernetes. We had noticed lot of restarts on containers with Java apps and is quite random. Docker inspection revealed that the pod was killed by OOMKiller code:137. This meant that the application is consuming more memory than allocated to the container. It didn’t sound right, since we have limits on the Java application using -Xmx and we left about 20% buffer as Kubernetes resource limit (docker container) for the Meta space and GC data.</p><p>For e.g., 2 GB for Java process, and 2.4 GB for the Kubernetes resource.</p><p>Subsequent sections cover this problem and how to solve it in detail.</p><p><strong>JVM memory usage</strong></p><p>Obviously the first step was to review why the container is exceeding the said limit, clearly these are sufficiently buffered.</p><p>“ps” command confirms that the Xmx is indeed in place, and is set to max of 4GB.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/428/1*xDvwU97WF3lOK2sEMqy8XQ.png" /><figcaption>Java process set to Max 4G</figcaption></figure><p>“top” command, however reveals that the physical memory used is 4.5 GB.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3uECmaea45oTSp0e8I-mNA.png" /><figcaption>Actual memory usage of the Java process</figcaption></figure><p><strong>Why would Java take 500 MB more than allocated?</strong></p><p>Since JDK 1.8.40 there is a <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html">Native memory tracker tool</a> introduced which provides a detailed breakup of memory used by Java application with every byte accounted for. Note that NMT tool shows committed, resident might be less.</p><blockquote>Actual usage = Heap memory + Meta space + Off heap</blockquote><p>Off heap typically consists of class meta data, compiled code, threads and GC data. GC data is variable while rest of it should remain static for most applications. This memory is native (<a href="https://dzone.com/articles/java-8-permgen-metaspace">yes including the meta space</a>), and JVM uses available memory on host to grow or garbage collect this data.</p><p>I would encourage you to read <a href="http://trustmeiamadeveloper.com/2016/03/18/where-is-my-memory-java/">this excellent blog post by Mikhail</a> to get better perspective.</p><p>Coming back to the problem at hand, JVM took 500 MB more because the underlying host had 16 GB memoy. At times this number could go higher than the buffer we had set, which would cause the container to be terminated. Shouldn’t the JVM be reading docker container’s memory limit?</p><p><strong>Containers and Java</strong></p><p>It turns out Java versions 9 and below do not understand containers/dockers at all (by default). It picks up available CPUs and Memory from the underlying host. Each Java app running on a host inside container relies on the host configuration. Considering that we are Kubernetes and many pods run on single node, this could lead to problems like the ones we are facing.</p><p>Java 10 supports containers out of the box, and it will lookup the linux cgroup information. This allows the JVM to garbage collect based on containers limits. This is turned on by default using the flag.</p><blockquote>-XX:+UseContainerSupport</blockquote><p>Thankfully, some of these features have been backported to 8u131 and 9 onwards. They can be turned on using the following flags.</p><blockquote>-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap</blockquote><p><strong>Summary</strong></p><p>Older versions of Java read the underlying host, and don’t understand cgroups. This would cause mismatch between container configuration and the Java process. This mismatch is on both CPU and the memory. Java has an Off heap memory component which has a dynamic GC data component, which could grow. Best way to solve this is to use the container support features available in recent versions of Java. Do not rely on buffering (It is waste of money).</p><p>Upgrade to Java 8u131+ or Java 9, if you have to remain on these major versions and turn on the experimental flags. Even better, if you can get all the container love available Java 10 onwards.</p><p><strong>References</strong></p><ul><li><a href="https://dzone.com/articles/java-ram-usage-in-containers-top-5-tips-not-to-los">Java RAM Usage in Containers: Top 5 Tips for Not Losing Your Memory - DZone Performance</a></li><li><a href="http://trustmeiamadeveloper.com/2016/03/18/where-is-my-memory-java/">Analyzing java memory usage in a Docker container</a></li><li><a href="https://jaxenter.com/nobody-puts-java-container-139373.html">Nobody puts Java in a container - JAXenter</a></li><li><a href="https://developers.redhat.com/blog/2017/03/14/java-inside-docker/">Java inside docker: What you must know to not FAIL - RHD Blog</a></li><li><a href="https://stackoverflow.com/questions/31455644/should-i-set-a-maxmetaspacesize">Should I set a MaxMetaspaceSize?</a></li></ul><p><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html">https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html</a></p><ul><li><a href="https://dzone.com/articles/permgen-and-metaspace">PermGen and Metaspace - DZone Performance</a></li><li><a href="https://stackoverflow.com/questions/31173374/why-does-a-jvm-report-more-committed-memory-than-the-linux-process-resident-set">Why does a JVM report more committed memory than the linux process resident set size?</a></li><li><a href="https://royvanrijn.com/blog/2018/05/java-and-docker-memory-limits/">Java and Docker, the limitations</a></li></ul><p><a href="https://blog.docker.com/2018/04/improved-docker-container-integration-with-java-10/">https://blog.docker.com/2018/04/improved-docker-container-integration-with-java-10/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c0dfd7f6b036" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/oom-killer-and-java-applications-c0dfd7f6b036">OOM Killer and Java applications</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A way to detect the rootkits and exploits in CentOS/RHEL]]></title>
            <link>https://medium.com/logistimo-engineering-blog/a-way-to-detect-the-rootkits-and-exploits-in-centos-rhel-5b125a8d6a25?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/5b125a8d6a25</guid>
            <category><![CDATA[system-administration]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[malware]]></category>
            <category><![CDATA[virus]]></category>
            <dc:creator><![CDATA[Narendiran D]]></dc:creator>
            <pubDate>Thu, 10 Jan 2019 07:06:38 GMT</pubDate>
            <atom:updated>2019-01-10T06:59:12.017Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/484/1*tzW6lHG66V0rB4-7xAKx0Q.png" /></figure><p>There are many ways that your server can be compromised by remote systems and malicious softwares. It’s important that once you discovered the attack, you try to find out how. Knowing how the attacker got in can help you reduce the risk of future compromises. Few such malwares and vulnerabilities are rootkit, backdoor and exploit.</p><p><strong>Rootkits</strong> are softwares that can provide the administrative access to the servers. This malware can be planted into the targeted system by an attacker through following means:</p><ol><li>Network port</li><li>An un-patched system</li><li>System with a weak administrator password etc.</li></ol><p>Rootkits replace normal programs and system libraries that are part of the operating system on victim machines with versions that superficially appear to be normal, but that in reality subvert the security of the machine and cause malicious functions to be executed. This kind of attack does not usually trigger automated network security controls like intrusion detection systems. It can be discovered only by digging deep on the affected system for behavioural change.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P4q7AVRA7JJUKx4otXQbiw.png" /></figure><p><strong>Backdoor</strong> is a means to access a computer system or encrypted data that bypasses the system’s security mechanisms. Attackers often use back-doors that they detect or install themselves as part of exploit. In some cases, a <a href="https://searchsecurity.techtarget.com/definition/worm">worm</a> or <a href="https://searchsecurity.techtarget.com/definition/virus">virus</a> is designed to take advantage of a backdoor created by an earlier attack. In simple words, the default password can function as back-doors if they are not changed by the user. Another example would be some debugging features that can also act as back-doors if they are not removed in the release version.</p><p><strong>Exploit</strong> is a piece of software, data or a sequence of commands that takes advantage of a bug or vulnerabilities to cause unanticipated behaviour. In simple words “<em>to use something for one’s own advantage”.</em></p><p><strong>rkhunter</strong> is a popular tool to detect such vulnerabilities and malwares . It can scan the entire system for rootkits and help us to defend ourselves against potential threats.</p><h3>rkhunter</h3><p><strong>rkhunter</strong> (<strong>Rootkit Hunter</strong>) is a Unix-based tool that scans for rootkits, backdoors and possible local exploits. It checks the system against a database of known rootkits as well as perform the following security checks:</p><ul><li>Compare MD5 hash</li><li>Look for default files used by rootkits</li><li>Check wrong file permissions for binaries</li><li>Look for suspected strings in LKM and KLD modules</li><li>Look for hidden files</li><li>Optional scan within plaintext and binary files</li></ul><h4>Install rkhunter on CentOS and RHEL</h4><p>All files required for installation of rkhunter are contained in the EPEL repository.</p><pre>$ yum install epel-release</pre><p>Once the EPEL repository is installed, issue the following commands as root to start the installation routine and for updating the database.</p><pre>$ sudo yum install rkhunter<br>$ rkhunter --update</pre><h4>Update system file properties</h4><p>This is a necessary step to establish a foundation database file to compare scans. On a clean install, the first run of <strong><em>propupd</em></strong> creates a new database file. On later scans, running the <strong><em>propupd</em></strong> command updates the database file. Update the database file when you are satisfied you have only trusted source system file changes.</p><pre>$ rkhunter --propupd</pre><h4>Automate Rootkit Hunter using CRON</h4><p>rkhunter can be setup to run checks every day so that we always have up-to-date information about intrusions. This can be accomplished by creating a cronjob.</p><p>Create a cron file in the following location <em>/etc/cron.daily/rkhunter.sh </em>and place the following script in the file.</p><pre>#!/bin/sh<br>(<br>/usr/local/bin/rkhunter --versioncheck<br>/usr/local/bin/rkhunter --update<br>/usr/local/bin/rkhunter --cronjob --report-warnings-only<br>) | /bin/mail -s &#39;rkhunter Daily Scan Report (PutYourServerNameHere)&#39; your@email.here</pre><p>Update the script with the email address to which the report should be sent.</p><ul><li>The --versioncheck checks if our threat definitions are up to date.</li><li>The --update option updates our threat definitions, if required.</li><li>The --cronjob option bypasses interactive key presses.</li></ul><p>Set execute permission on the file you have just created</p><pre>$ chmod 755 /etc/cron.daily/rkhunter.sh</pre><p>The cron utility will run once daily and a report will be sent via email. Emails will be sent only if issues/problems surface. Otherwise, no emails will be sent.</p><p><strong>Manual Scan</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/699/1*g-lFQPzOOM6lcPG6TG_sXQ.png" /></figure><p>You can initiate a manual scan by issuing the following command:</p><pre>rkhunter -c</pre><p>which runs rkhunter in interactive mode. In other words, when it gets to the end of a particular scan, you need to press ‘enter’ to continue. If you want to “auto-skip” interactive mode, add the -sk option:</p><pre>rkhunter -c -sk</pre><p>Your scan results will look as follows:</p><pre>System checks summary<br>=====================</pre><pre>File properties checks...<br>    Files checked: 130<br>    Suspect files: 0</pre><pre>Rootkit checks...<br>    Rootkits checked : 498<br>    Possible rootkits: 0</pre><pre>Applications checks...<br>    All checks skipped</pre><pre>The system checks took: 14 minutes and 34 seconds</pre><pre>All results have been written to the log file: /var/log/rkhunter/rkhunter.log</pre><pre>No warnings were found while checking the system.</pre><p><strong>Conclusion</strong></p><p>If a rootkit has been installed in a compromised system, rebuilding the system is the best course of action. Because rootkits are so proficient in hiding themselves. Extremely strong monitoring and intrusion-detection/intrusion-prevention efforts need to be implemented. This article serves as an introductory tutorial to detection of rootkits.</p><p><strong>References</strong></p><ul><li><a href="https://www.woktron.com/secure/knowledgebase/79/Installation-Rootkit-Hunter-rkhunter-on-CentOS-5-and-6.html">Knowledgebase</a></li><li><a href="https://searchsecurity.techtarget.com/definition/back-door">What is backdoor (computing)? - Definition from WhatIs.com</a></li><li><a href="https://docs.microsoft.com/en-us/windows/security/threat-protection/intelligence/exploits-malware">Exploits and exploit kits</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5b125a8d6a25" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/a-way-to-detect-the-rootkits-and-exploits-in-centos-rhel-5b125a8d6a25">A way to detect the rootkits and exploits in CentOS/RHEL</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dynamo vs Cassandra : Systems Design of NoSQL Databases]]></title>
            <link>https://medium.com/logistimo-engineering-blog/dynamo-vs-cassandra-systems-design-of-nosql-databases-fb0ab618ea6f?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/fb0ab618ea6f</guid>
            <category><![CDATA[distributed-systems]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[dynamodb]]></category>
            <category><![CDATA[nosql]]></category>
            <category><![CDATA[cassandra]]></category>
            <dc:creator><![CDATA[Sujith Jay Nair]]></dc:creator>
            <pubDate>Mon, 22 Oct 2018 08:20:35 GMT</pubDate>
            <atom:updated>2018-10-04T19:36:17.990Z</atom:updated>
            <content:encoded><![CDATA[<h3>Dynamo vs Cassandra : Systems Design of NoSQL Databases</h3><p>State-of-the-art distributed databases represent a distillation of years of research in distributed systems. The concepts underlying any distributed system can thus be overwhelming to comprehend. This is truer when you are dealing with databases without the strong consistency guarantee. Databases without strong consistency guarantees come in a range of flavours; but they are bunched under a category called <a href="http://www.christof-strauch.de/nosqldbs.pdf">NoSQL databases</a>.</p><p>NoSQL databases do not represent a single kind of data model, nor do they offer uniform guarantees regarding consistency and availability. However, they are built on very similar principles and ideas.</p><p>From a historical perspective, the advent of NoSQL databases was precipitated by the publication of <a href="https://courses.cs.washington.edu/courses/csep552/18wi/papers/decandia-dynamo.pdf">Dynamo</a> by Amazon¹ &amp; <a href="https://static.googleusercontent.com/media/research.google.com/en//archive/bigtable-osdi06.pdf">BigTable</a> by Google, and the emergence of a number of open-source distributed data stores, which were (improved?) clones of either (or both) of these systems. Bigtable-inspired NoSQL stores are referred to as column-stores (e.g. <a href="http://www.hypertable.com/documentation/">HyperTable</a>, <a href="https://hbase.apache.org/">HBase</a>), whereas Dynamo influenced most of the key/value-stores. We will term these systems loosely as Dynamo-family databases, which include <a href="http://docs.basho.com/">Riak</a>, <a href="https://www.aerospike.com/docs/">Aerospike</a>, <a href="http://www.project-voldemort.com/voldemort/">Project Voldemort</a>, and <a href="http://cassandra.apache.org/">Cassandra</a>.</p><p>I would like to focus on systems design ideas in Dynamo-family NoSQL databases in this article, with a particular focus on Cassandra. The approach of this article is to compare and contrast Cassandra with Dynamo; and in this process, touch upon the underlying ideas. Expect a lot of homework &amp; further readings; I will have copious amounts of references throughout the article.</p><h3>Caveats</h3><p>Cassandra, although heavily influenced by Dynamo, also borrows from <a href="https://cloud.google.com/bigtable/docs/">BigTable</a>.</p><p>A chunk of the differences between Cassandra &amp; Dynamo stem from the fact that the data-model of Dynamo is a key-value store, while Cassandra is designed as a <a href="https://en.wikipedia.org/wiki/Standard_column_family">column-family</a> data store (which is a concept from BigTable in which the primary abstraction is a sparsely populated wide table).</p><p>For what it’s worth, Cassandra is full-fledged database implementation while Dynamo is a set of ideas which when taken together can form a highly available distributed data-store (courtesy of it being a walled system with its implementation never released to public domain).</p><p>We will focus on a comparison of the implementation choices in Cassandra &amp; Dynamo which address the challenges of a distributed system; and will try to steer clear of contrasts arising from differences in the data models.</p><h3>Meat of the Matter</h3><p>The essence of this article can be summarized as below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y-QunHLxeHCZi4ZSxRo8xg.png" /><figcaption>Comparison of Techniques between Dynamo &amp; Cassandra</figcaption></figure><p>The remainder of this article is little more than a collection of introductions to the above concepts.</p><h3>High Availability for Writes</h3><p>High-availability writes in a distributed database with <a href="https://www.brianstorti.com/replication/">leaderless replication</a> (both Dynamo and Cassandra employ leaderless replication) requires a heuristic for conflict resolution between concurrent writes. This is essential because every replica of data is considered equal and concurrent writes on the same record at two different replicas are considered perfectly valid.</p><p>The common heuristics for conflict resolution are <a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/#vector-clocks">vector clocks</a> or <a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/#last-write-wins">last-write-wins</a>.</p><h4>Vector Clocks</h4><p>Vector Clocks are a mechanism to notify the actors about the occurrence of conflicts.</p><p>To illustrate the process, assume three actors with actor IDs Anu, Baba and Chandra respectively. Let an existing data-point in the data-store be {&quot;street&quot; : &quot;Lavelle&quot;, &quot;city&quot; : &quot;Bangalore&quot;} with key ‘address’. We will call this version of ‘address’ <em>V0</em>. Anu updates the street such that the data now reads {&quot;street&quot; : &quot;Cubbon&quot;, &quot;city&quot; : &quot;Bangalore&quot;}, which we will call <em>V1</em>. This is updated to a single replica. A concurrent update is performed by Baba, who changes the city such that the data now reads {&quot;street&quot; : &quot;Lavelle&quot;, &quot;city&quot; : &quot;Bombay&quot;} (<em>V2</em>). This is updated to another replica.</p><p>In a data-store using vector clocks, the data-store holds onto both <em>V1</em> and <em>V2</em> because they do not descend from each other. When an actor reads the data at a future point of time (for example, Chandra is reading the ‘address’ data), the data-store will hand back both values. The client decides on the merge strategy of the sibling data returned to it. Once descendancy can be calculated, values stored with vector clocks that have been succeeded will be removed.</p><p>Vector Clocks were proposed as a conflict resolution mechanism in the original Dynamo paper; however, most Dynamo-family databases have last-write-wins as their conflict resolution mechanism.²</p><p>The maintainers of Riak have lucid explanations of how vector clocks work and the associated challenges in <a href="http://basho.com/posts/technical/why-vector-clocks-are-easy/">Why Vector Clocks Are Easy</a> and <a href="http://basho.com/posts/technical/why-vector-clocks-are-hard/">Why Vector Clocks Are Hard</a>.</p><h4>Last Write Wins</h4><p>In last-write-wins, the latest change to a data-point alone is retained. Thus, in the above example, <em>V2</em> will be the final version of the data in a last-write-wins data-store. Thus, last-write-wins is a simplification over the vector clock approach. It could lead to potential data loss (such as the update to ‘street’ introduced in <em>V1</em> is lost).</p><p>The maintainers of Cassandra believe this simplification is justified because of the data model is different from a key-value database. Each row is broken up into columns which are updated independently. This fine-grained implementation of last-write-wins is argued to work well for Cassandra. In case of time-ties for the same column, Cassandra has a <a href="http://cassandra.apache.org/doc/latest/faq/index.html#what-on-same-timestamp-update">rule-based, deterministic method to get a commutative result</a>. You can read more on why Cassandra doesn’t need vector clocks <a href="https://www.datastax.com/dev/blog/why-cassandra-doesnt-need-vector-clocks">here</a>.</p><h3>Temporary Failures</h3><p>Temporary failures occur when a replica is unavailable for read and/or write operations for a small duration of time. This could arise because of GC stalls, network and hardware outages, or maintenance shutdowns.</p><p><a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/#hinted-handoff">Hinted Handoff</a> is a common strategy in write paths to handle and repair temporary failures in systems with leaderless replication. In read paths, the approach for handling temporary failures could be either <a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/#strict--sloppy-quorum">strict or sloppy quorum</a>.</p><h4>Hinted Handoff</h4><p>In Hinted Handoff, when a write is performed and a replica node for the row is either known to be down ahead of time, or does not respond to the write request, the coordinator will store a hint locally. This hint is basically a wrapper around the mutation indicating that it needs to be replayed to the unavailable node(s).</p><p>Once a node discovers via gossip that a node for which it holds hints has recovered, it will send the data row corresponding to each hint to the target.</p><p>Hinted Handoff has two purposes:</p><ul><li>It allows the database to offer full write availability when consistency is not required.³</li><li>It improves response consistency after temporary outages.⁴</li></ul><p>The implications of hinted writes on read &amp; write consistencies are covered in the next section on <a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/#strict--sloppy-quorum">strict &amp; sloppy quorum</a>. Notes on Cassandra’s implementation of hinted handoff can be found <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/operations/opsRepairNodesHintedHandoff.html">here</a>.</p><h4>Strict &amp; Sloppy Quorum</h4><p>Quorum is the number of replicas which should acknowledge a particular read or write operation; it is closely associated with the replication factor. The use of hinted writes to meet consistency requirements in read paths decides whether a quorum is strict or sloppy.</p><p>In Dynamo, in scenarios where the available replicas is less than the total replicas, sloppy quorum is used to ensure read availability. The hinted writes stored in a node other than the replicas count towards read consistency requirements, and thus reads can be served even in cases where available replicas is less than the consistency requirements.</p><p>In Cassandra, strict quorum is used. This means that hinted writes do not count towards read or write consistency requirements (with the exception of <a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/(https://docs.datastax.com/en/cassandra/3.0/cassandra/dml/dmlConfigConsistency.html#Writeconsistencylevels)">ANY write consistency</a>).</p><h3>Consistent Hashing</h3><p>This article started with saying that distributed databases represent a distillation of years of research in distributed systems. No other concept illustrates this better than consistent hashing (or ring hashing). Consistent hashing has been around <a href="https://www.akamai.com/es/es/multimedia/documents/technical-publication/consistent-hashing-and-random-trees-distributed-caching-protocols-for-relieving-hot-spots-on-the-world-wide-web-technical-publication.pdf">since 199</a>7 ⁵, and formed the basis of the formation of Akamai Technologies, and the subsequent birth of the Content Distribution Network industry.</p><p>In consistent hashing, the output range of a hash function is treated as a fixed circular space or “ring” (i.e. the largest hash value wraps around to the smallest hash value). Each node in the system is assigned multiple random value within this space. Each random value is called a <em>vnode</em> position; a single node is associated to multiple <em>vnodes</em> &amp; consequently multiple positions on the ring.</p><p>Each data item identified by a key is assigned to a node by hashing the data item’s key to yield its position on the ring, and then walking the ring clockwise to find the first <em>vnode</em> with a position larger than the item’s position. The node associated with the <em>vnode</em> is the location of the data item.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/0*is1uapIWNkFewfNj.png" /><figcaption>Consistent Hashing</figcaption></figure><p>The principle advantage of consistent hashing is incremental stability; the departure or arrival of a node into the cluster only affects its immediate neighbours and other nodes remain unaffected.</p><p>However, ring hashing is prone to uneven load distribution. The table below, taken from <a href="https://arxiv.org/pdf/1406.2294.pdf">the paper on Jump Hash</a> (an alternative algorithm to ring hash), shows the standard error in loads &amp; the 99% confidence interval of bucket sizes as multiples of average loads.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vdx05j3I4uoor_6GXM1xkg.png" /><figcaption>Uneven Load Distribution in Consistent Hashing</figcaption></figure><p>This table can be read in the following way: in an implementation with 10 <em>vnodes</em> per node, the standard deviation of load is within (1– 0.3151810) ≈ 0.69. The 99% confidence interval for the bucket sizes lies between 0.37 to 1.98 times the average load. Such a high variance could make capacity planning tricky (although I am yet to see this in practice with Cassandra). In Cassandra, the number of <em>vnodes</em> is controlled by the parameter <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/configCassandra_yaml.html#configCassandra_yaml__num_tokens"><em>num_tokens</em></a>.</p><p>Consistent hashing is also a part of the replication strategy in Dynamo-family databases. In Cassandra, <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/architecture/archDataDistributeReplication.html">two strategies exist</a>. In <em>SimpleStrategy</em>, a node is anointed as the location of the first replica by using the ring hashing partitioner. Subsequent replicas are placed on the next nodes clockwise on the ring. In <em>NetworkTopologyStrategy</em>, for each datacenter, the same steps are performed with a difference when choosing subsequent replicas: subsequent replicas are placed on the next node clockwise on the ring which belongs to a different rack than the location of the previous replica.</p><p>The use of consistent hashing in <a href="http://www.project-voldemort.com/voldemort/design.html">Voldemort</a> and <a href="http://docs.basho.com/riak/kv/2.2.3/learn/concepts/replication/">Riak</a> follow the same above-illustrated pattern. An excellent primer on alternatives to ring hashing &amp; their respective trade-offs can be found <a href="https://medium.com/@dgryski/consistent-hashing-algorithmic-tradeoffs-ef6b8e2fcae8">here</a>.</p><h3>Anti-Entropy using Merkle trees</h3><p>The distributed nature of data means data in a replica can become inconsistent with other replicas over time. Dynamo-family databases have a multi-pronged approach to deal with it. <a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/#hinted-handoff">Hinted Hand-offs</a> is a strategy in write-paths to handle and repair temporary failures. <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/operations/opsRepairNodesReadRepair.html">Read repair</a> is a strategy to repair inconsistencies observed in the read-path.</p><p>The above two strategies work behind the scene to repair data; but due to their very nature of repairing data accessed during reads or writes alone, they cannot repair every data item in the replicas. They work best if the system membership churn is low and node failures are transient. Hence, these databases provide a manual way to trigger repairs of data. This is called an anti-entropy repair.⁶</p><p>Anti-entropy is a process of comparing the data of all replicas and updating each replica to the newest version. It relies on <a href="http://en.wikipedia.org/wiki/Merkle_tree">Merkle tree</a> hash exchanges between nodes. The following extract, from <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/operations/opsRepairNodesManualRepair.html">Cassandra documentation</a>, is a good overview of the use of Merkle trees in the anti-entropy process.</p><blockquote><em>Merkle trees are binary hash trees whose leaves are hashes of the individual key values. The leaf of a Cassandra Merkle tree is the hash of a row value. Each Parent node higher in the tree is a hash of its respective children. Because higher nodes in the Merkle tree represent data further down the tree, Casandra can check each branch independently without requiring the coordinator node to download the entire data set.</em></blockquote><blockquote><em>After the initiating node receives the Merkle trees from the participating peer nodes, the initiating node compares every tree to every other tree. If a difference is detected, the differing nodes exchange data for the conflicting range(s), and the new data is written to SSTables. The comparison begins with the top node of the Merkle tree. If no difference is detected, then the data requires no repair. If any difference is detected, the process proceeds to the left child node and compares and then the right child node. When a node is found to differ, inconsistent data exists for the range that pertains to that node. All data that corresponds to the leaves below that Merkle tree node will be replaced with new data.</em></blockquote><p>The key difference in Cassandra’s implementation of anti-entropy from Dynamo is that the Merkle trees are built per column family, and they are not maintained for longer than it takes to send them to neighboring nodes.⁷ Instead, the trees are generated as snapshots of the dataset during major compactions: this means that excess data might be sent across the network, but it saves local disk IO, and is preferable for very large datasets.</p><p>Notes on Cassandra’s implementation of anti-entropy can be found <a href="https://wiki.apache.org/cassandra/ArchitectureAntiEntropy">here</a>. A more-detailed blog-entry on anti-entropy, with a similar take on comparing Riak, Cassandra &amp; Dynamo as this article, can be found <a href="https://loveforprogramming.quora.com/Distributed-Systems-Part-3-Managing-Anti-Entropy-using-Merkle-Trees">here</a>.</p><h3>Gossip Protocols</h3><p>Gossip protocols are a class of peer-to-peer communication protocols inspired by information dissemination in real-life social networks. In Dynamo, decentralized failure detection protocols use a simple gossip-style protocol that enable each node in the system to learn about the arrival (or departure) of other nodes. Failure detection helps nodes in avoiding communication with unresponsive peers during read and write operations. Dynamo’s failure detection protocol is based on <a href="http://www.ict.uom.gr/teaching/distrubutedSite/eceutexas/dist2/papers/On_scalable_and_efficient_distributed_failure_detectors.pdf">Gupta et al. (2001)</a>, although the exact implementation details are obscure.</p><p>The Cassandra implementation of gossip is very similar to Dynamo, and we have a lot more information on it via its <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/architecture/archGossipAbout.html">documentation</a>. The gossip process runs every second and exchanges state messages with up to three other nodes in the cluster. The nodes exchange information about themselves and about the other nodes that they have gossiped about, so all nodes quickly learn about all other nodes in the cluster. A gossip message has a version associated with it, so that during a gossip exchange, older information is overwritten with the most current state for a particular node.</p><p>The gossip process tracks state from other nodes both directly (nodes gossiping directly to it) and indirectly (nodes communicated about secondhand, third-hand, and so on). Rather than have a fixed threshold for marking failing nodes, Cassandra uses an accrual detection mechanism to calculate a per-node threshold that takes into account network performance, workload, and historical conditions. During gossip exchanges, every node maintains a sliding window of inter-arrival times of gossip messages from other nodes in the cluster. Configuring the <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/configCassandra_yaml.html#configCassandra_yaml__phi_convict_threshold">phi_convict_threshold</a> property adjusts the sensitivity of the failure detector.</p><h3>That’s All, Folks!</h3><p>The scope of topics covered in this article are vast; and I do not believe a single article does justice to them. However, the attempt here was to compile a compendium on the ideas behind NoSQL distributed systems. A future article will attempt a similar take on <a href="https://en.wikipedia.org/wiki/NewSQL">NewSQL databases</a>, but that’s for another day. Hope you find this useful. Until next time!</p><h3>Notes</h3><ol><li>A fair amount of review-articles exists for the Dynamo paper: a few interesting takes can be found <a href="http://glinden.blogspot.com/2007/10/highly-available-distributed-hash.html">here</a> &amp; <a href="http://muratbuffalo.blogspot.com/2010/11/dynamo-amazons-highly-available-key.html">here</a>.</li><li>Riak has last-write-wins as its default mechanism for conflict resolution, inspite of a high chance of data-loss. As its maintainers put it,</li></ol><blockquote><a href="http://basho.com/posts/technical/why-vector-clocks-are-hard/">Vector clocks are hard: even with perfect implementation you can’t have perfect information about causality in an open system without unbounded information growth</a>.</blockquote><p>3. The catch here is ‘when consistency is not required’. In Dynamo which uses sloppy quorum, hinted writes count towards write consistency requirements, and hence hinted handoff helps offer full write availability.</p><p>In Cassandra, <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/dml/dmlConfigConsistency.html#Writeconsistencylevels">for every write consistency other than ANY</a>, hinted writes do not count towards write consistency requirements. Hence, full write availability may not be available.</p><p>4. In a similar vein to the note above, sloppy quorum in Dynamo means that hints stored in nodes other than the replicas count towards read consistency requirements; thus, improving read availability.</p><p>Cassandra does not use hinted writes in computing <a href="https://docs.datastax.com/en/cassandra/3.0/cassandra/dml/dmlConfigConsistency.html#Readconsistencylevels">read consistency requirements</a>; thus hinted handoffs do not improve read availability.</p><p>5. This may not be entirely true. <a href="https://info.teradata.com/HTMLPubs/DB_TTU_16_00/index.html#page/Database_Management%2FB035-1094-160K%2Fpho1472240585397.html%23wwID0EEPUO">A form of consistent hashing</a> is claimed to have existed in Teradata since 1986. I could not find any source to back this claim. However, it is clear the <a href="https://www.akamai.com/es/es/multimedia/documents/technical-publication/consistent-hashing-and-random-trees-distributed-caching-protocols-for-relieving-hot-spots-on-the-world-wide-web-technical-publication.pdf">Akamai paper</a> was the first to name this technique as consistent hashing.</p><p>6. Anti-entropy processes need not always be manual. Riak periodically clears &amp; regenerates the Merkle hash trees used in the anti-entropy process. They term it <a href="http://docs.basho.com/riak/kv/2.2.3/learn/concepts/active-anti-entropy/">active anti-entropy</a>.</p><p>7. Cassandra does not persist the hash trees generated during anti-entropy. On the other hand, Riak (which seems to have followed the original Dynamo approach on this) uses persistent, on-disk hash trees instead of in-memory hash trees. The advantages of this approach, <a href="http://docs.basho.com/riak/kv/2.2.3/learn/concepts/active-anti-entropy/">as stated by its maintainers</a>, are twofold: i) Riak can run anti-entropy operations with a minimal impact on memory usage. ii) Riak nodes can be restarted without needing to rebuild hash trees.</p><p><em>Originally published at </em><a href="https://sujithjay.com/data-systems/Dynamo-vs-Cassandra/"><em>sujithjay.com</em></a><em> on October 2, 2018.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fb0ab618ea6f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/dynamo-vs-cassandra-systems-design-of-nosql-databases-fb0ab618ea6f">Dynamo vs Cassandra : Systems Design of NoSQL Databases</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Understanding Apache Spark on YARN]]></title>
            <link>https://medium.com/logistimo-engineering-blog/understanding-apache-spark-on-yarn-9bfe25e5b2f?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/9bfe25e5b2f</guid>
            <category><![CDATA[big-data]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[hadoop]]></category>
            <category><![CDATA[apache-spark]]></category>
            <category><![CDATA[tutorial]]></category>
            <dc:creator><![CDATA[Sujith Jay Nair]]></dc:creator>
            <pubDate>Fri, 03 Aug 2018 07:28:54 GMT</pubDate>
            <atom:updated>2018-08-03T07:28:54.276Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>TL; DR</strong> Apache Spark is a lot to digest; running it on YARN even more so. I hope this post helps a bit.</p><h3>Introduction</h3><p>This article is an introductory reference to understanding Apache Spark on YARN. Since our data platform at <a href="http://logistimo.com/">Logistimo</a> runs on this infrastructure, it is imperative you (my fellow engineer) have an understanding about it before you can contribute to it. This article assumes basic familiarity with Apache Spark concepts, and will not linger on discussing them.</p><h3>Overview on YARN</h3><p>YARN is a generic resource-management framework for distributed workloads; in other words, a cluster-level operating system. Although part of the Hadoop ecosystem, YARN can support a lot of varied compute-frameworks (such as Tez, and Spark) in addition to MapReduce.</p><p>The central theme of YARN is the division of resource-management functionalities into a global ResourceManager (RM) and per-application ApplicationMaster (AM). An application is the unit of scheduling on a YARN cluster; it is either a single job or a DAG of jobs (jobs here could mean a Spark job, an Hive query or any similar constructs).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/622/0*3kMj1DZ3VL3o0vuY.gif" /><figcaption>Fig. 1: YARN Architecture [1]</figcaption></figure><p>The ResourceManager and the NodeManager form the data-computation framework. The ResourceManager is the ultimate authority that arbitrates resources among all the applications in the system. The NodeManager is the per-machine agent who is responsible for containers, monitoring their resource usage (cpu, memory, disk, network) and reporting the same to the ResourceManager/Scheduler [1].</p><p>The per-application ApplicationMaster is, in effect, a framework specific library and is tasked with negotiating resources from the ResourceManager and working with the NodeManager(s) to execute and monitor the tasks [1].</p><h3>Glossary</h3><p>The first hurdle in understanding a Spark workload on YARN is understanding the various terminology associated with YARN and Spark, and see how they connect with each other. I will introduce and define the vocabulary below:</p><h4>Application</h4><p>A Spark application is the highest-level unit of computation in Spark. A Spark application can be used for a single batch job, an interactive session with multiple jobs, or a long-lived server continually satisfying requests. A Spark job can consist of more than just a single map and reduce. On the other hand, a YARN application is the unit of scheduling and resource-allocation. There is a one-to-one mapping between these two terms in case of a Spark workload on YARN; i.e, a Spark application submitted to YARN translates into a YARN application.</p><h4>Spark Driver</h4><p>To understand the driver, let us divorce ourselves from YARN for a moment, since the notion of driver is universal across Spark deployments irrespective of the cluster manager used.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/596/0*Lb9mEt7Ggywz0pvF.png" /><figcaption>Fig. 2: Spark Cluster Overview [4]</figcaption></figure><p>Spark applications are coordinated by the SparkContext (or SparkSession) object in the main program, which is called the Driver. In plain words, the code initialising SparkContext is your driver. The driver process manages the job flow and schedules tasks and is available the entire time the application is running (i.e, the driver program must listen for and accept incoming connections from its executors throughout its lifetime. As such, the driver program must be network addressable from the worker nodes) [4].</p><h4>YARN Client</h4><p>A program which submits an application to YARN is called a YARN client, as shown in the figure in the <a href="http://sujithjay.com/2018/07/24/Understanding-Apache-Spark-on-YARN/#overview-on-yarn">YARN</a> section. Simple enough.</p><p>The notion of driver and how it relates to the concept of client is important to understanding Spark interactions with YARN. In particular, the location of the driver w.r.t the client &amp; the ApplicationMaster defines the deployment mode in which a Spark application runs: YARN client mode or YARN cluster mode.</p><p><em>Client mode:</em> The driver program, in this mode, runs on the YARN client. Thus, the driver is not managed as part of the YARN cluster.</p><p>Take note that, since the driver is part of the client and, as mentioned above in the <a href="http://sujithjay.com/2018/07/24/Understanding-Apache-Spark-on-YARN/#spark-driver">Spark Driver</a> section, the driver program must listen for and accept incoming connections from its executors throughout its lifetime, the client cannot exit till application completion.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/620/0*eLggBKLNQTJXYovL.png" /><figcaption>Fig. 3: YARN Client Mode [2]</figcaption></figure><p><em>Cluster mode:</em> The driver program, in this mode, runs on the ApplicationMaster, which itself runs in a container on the YARN cluster. The YARN client just pulls status from the ApplicationMaster. In this case, the client could exit after application submission.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/620/0*IessgdE1Kcies5Gr.png" /><figcaption>Fig. 4: YARN Cluster Mode [2]</figcaption></figure><p>The first fact to understand is: each Spark executor runs as a YARN container [2]. This and the fact that Spark executors for an application are fixed, and so are the resources allotted to each executor, a Spark application takes up resources for its entire duration. This is in contrast with a MapReduce application which constantly returns resources at the end of each task, and is again allotted at the start of the next task.</p><p>Also, since each Spark executor runs in a YARN container, YARN &amp; Spark configurations have a slight interference effect. I will illustrate this in the next segment.</p><h3>Configuration and Resource Tuning</h3><p>With our vocabulary and concepts set, let us shift focus to the knobs &amp; dials we have to tune to get Spark running on YARN. We will be addressing only a few important configurations (both Spark and YARN), and the relations between them.</p><p>We will first focus on some YARN configurations, and understand their implications, independent of Spark.</p><ul><li><em>yarn.nodemanager.resource.memory-mb</em></li></ul><p>It is the amount of physical memory, in MB, that can be allocated for containers in a node. This value has to be lower than the memory available on the node.</p><pre>&lt;name&gt;yarn.nodemanager.resource.memory-mb&lt;/name&gt;<br>&lt;value&gt;16384&lt;/value&gt; &lt;!-- 16 GB --&gt;</pre><ul><li><em>yarn.scheduler.minimum-allocation-mb</em></li></ul><p>It is the minimum allocation for every container request at the ResourceManager, in MBs. In other words, the ResourceManager can allocate containers only in increments of this value. Thus, this provides guidance on how to split node resources into containers. Memory requests lower than this will throw a InvalidResourceRequestException.</p><pre>&lt;name&gt;yarn.scheduler.minimum-allocation-mb&lt;/name&gt;<br>&lt;value&gt;2048&lt;/value&gt;&lt;!-- 2 GB --&gt;</pre><ul><li><em>yarn.scheduler.maximum-allocation-mb</em></li></ul><p>The maximum allocation for every container request at the ResourceManager, in MBs. Memory requests higher than this will throw a InvalidResourceRequestException.</p><pre>&lt;name&gt;yarn.scheduler.maximum-allocation-mb&lt;/name&gt; &lt;value&gt;8192&lt;/value&gt;&lt;!-- 8 GB --&gt;</pre><p>Thus, in summary, the above configurations mean that the ResourceManager can only allocate memory to containers in increments of <em>yarn.scheduler.minimum-allocation-mb</em> and not exceed <em>yarn.scheduler.maximum-allocation-mb</em>, and it should not be more than the total allocated memory of the node, as defined by <em>yarn.nodemanager.resource.memory-mb</em>.</p><p>We will refer to the above statement in further discussions as the <em>Boxed Memory Axiom</em> (just a fancy name to ease the discussions). A similar axiom can be stated for cores as well, although we will not venture forth with it in this article.</p><p>Let us now move on to certain Spark configurations. In particular, we will look at these configurations from the viewpoint of running a Spark job within YARN.</p><ul><li><em>spark.executor.memory</em></li></ul><p>Since every executor runs as a YARN container, it is bound by the Boxed Memory Axiom. However, a source of confusion among developers is that the executors will use a memory allocation equal to <em>spark.executor.memory</em>. In essence, the memory request is equal to the sum of <em>spark.executor.memory</em> + <em>spark.executor.memoryOverhead</em>. Thus, it is this value which is bound by our axiom.</p><ul><li><em>spark.driver.memory</em></li></ul><p>In cluster deployment mode, since the driver runs in the ApplicationMaster which in turn is managed by YARN, this property decides the memory available to the ApplicationMaster, and it is bound by the Boxed Memory Axiom. But as in the case of <em>spark.executor.memory</em>, the actual value which is bound is <em>spark.driver.memory</em> + <em>spark.driver.memoryOverhead</em>.</p><p>In case of client deployment mode, the driver memory is independent of YARN and the axiom is not applicable to it. In turn, it is the value <em>spark.yarn.am.memory</em> + <em>spark.yarn.am.memoryOverhead</em> which is bound by the Boxed Memory Axiom.</p><p>I hope this article serves as a concise compilation of common causes of confusions in using Apache Spark on YARN. More details can be found in the references below. Please leave a comment for suggestions, opinions, or just to say hello. Until next time!</p><h3>References</h3><p>[1] “Apache Hadoop 2.9.1 — Apache Hadoop YARN”. hadoop.apache.org, 2018, Available at: <a href="https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/YARN.html">Link</a>. Accessed 23 July 2018.</p><p>[2] Ryza, Sandy. “Apache Spark Resource Management And YARN App Models — Cloudera Engineering Blog”. Cloudera Engineering Blog, 2018, Available at: <a href="https://blog.cloudera.com/blog/2014/05/apache-spark-resource-management-and-yarn-app-models/">Link</a>. Accessed 22 July 2018.</p><p>[3] “Configuration — Spark 2.3.0 Documentation”. spark.apache.org, 2018, Available at: <a href="https://spark.apache.org/docs/2.3.0/configuration.html">Link</a>. Accessed 22 July 2018.</p><p>[4] “Cluster Mode Overview — Spark 2.3.0 Documentation”. spark.apache.org, 2018, Available at: <a href="https://spark.apache.org/docs/2.3.0/cluster-overview.html">Link</a>. Accessed 23 July 2018.</p><p><em>Originally published at </em><a href="http://sujithjay.com/2018/07/24/Understanding-Apache-Spark-on-YARN/"><em>sujithjay.com</em></a><em> on July 24, 2018.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9bfe25e5b2f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/understanding-apache-spark-on-yarn-9bfe25e5b2f">Understanding Apache Spark on YARN</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Elastic APM in Kubernetes]]></title>
            <link>https://medium.com/logistimo-engineering-blog/how-did-i-use-apm-in-kubernetes-ecosystem-8f22d52beb03?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/8f22d52beb03</guid>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[apm]]></category>
            <category><![CDATA[elk]]></category>
            <dc:creator><![CDATA[Narendiran D]]></dc:creator>
            <pubDate>Fri, 03 Aug 2018 07:22:07 GMT</pubDate>
            <atom:updated>2018-10-12T02:24:18.585Z</atom:updated>
            <content:encoded><![CDATA[<blockquote><strong>“If it isn’t monitored, it isn’t production!”</strong></blockquote><p>In a microservice environment handling huge workloads, a performance dip of a single microservice will mean the performance degradation of an entire application. A single weak link in the chain can endanger our SLAs. The SCM product at <a href="http://www.logistimo.com/">Logistimo</a> handles mission-critical public-health supply chains for host of countries, via an array of microservices. Since the vitality of these systems is important at many levels, we take monitoring performance very seriously.</p><p>Our microservices are managed in a Kubernetes (K8s) cluster. The K8s ecosystem provides an array of options to monitor health and performance of the services. However, we wanted a solution which could monitor the performance of the application at the micro-service level. This brought us to the use of Elastic APM for our Kubernetes cluster. APM stands for <strong><em>Application Performance Monitoring</em></strong>. Deploying Elastic APM in Kubernetes ecosystem is a topic on which not much literature is found on the web. Hence, We decided to share our experience.</p><h3>Elastic APM system:</h3><p>If you are using the ELK stack( <strong><em>Elasticsearch, Logstash and Kibana</em></strong> ) for log aggregation in your infrastructure, you might be recording all the application logs in the Elasticsearch. While this in itself is useful, It is necessary to have APM monitoring for microservices. Elastic APM streams all events to Elastic search much like the Logstash.</p><p>Since data is stored as raw documents in Elasticsearch, your service metrics can coexist with your infrastructure logs making it easy to explore all of your data in one place. These metrics can be visualised in Kibana with pre-configured dashboards.</p><p>To do this APM metrics collection, you need two components:</p><ol><li>APM server</li><li>APM agent</li></ol><h4><strong>APM server</strong></h4><p>APM Server is a central component in the Elastic APM system. It receives data from APM agents and transforms them into Elastic search documents</p><p>A single APM server can handle data from multiple microservices. APM Server works by exposing an HTTP server to which agents post the APM data they collect.</p><p>To deploy the basic APM Server in K8s infrastructure, you can use following <em>Kube-apm-server.yaml</em> file:</p><pre>---<br>apiVersion: v1<br>kind: ConfigMap<br>metadata:<br>  name: apm-server-config<br>  labels:<br>    k8s-app: apm-server<br>data:<br>  apm-server.yml: |-<br>    apm-server:<br>      host: &quot;0.0.0.0:8200&quot;<br>      frontend:<br>        enabled: false<br>    setup.template.settings:<br>      index:<br>        number_of_shards: 1<br>        codec: best_compression<br>    setup.dashboards.enabled: true<br>    setup.kibana:<br>      host: &quot;&lt; kibana endpoint &gt;&quot;<br>    output.elasticsearch:<br>      hosts: [&quot;&lt; elasticsearch endpoint &gt;&quot;]<br>      indices:<br>        - index: &quot;apm-%{[beat.version]}-sourcemap&quot;<br>          when.contains:<br>            processor.event: &quot;sourcemap&quot;</pre><pre>- index: &quot;apm-%{[beat.version]}-error-%{+yyyy.MM.dd}&quot;<br>          when.contains:<br>            processor.event: &quot;error&quot;</pre><pre>- index: &quot;apm-%{[beat.version]}-transaction-%{+yyyy.MM.dd}&quot;<br>          when.contains:<br>            processor.event: &quot;transaction&quot;</pre><pre>- index: &quot;apm-%{[beat.version]}-span-%{+yyyy.MM.dd}&quot;<br>          when.contains:<br>            processor.event: &quot;span&quot;<br>---<br>apiVersion: v1<br>kind: Service<br>metadata:<br>  name: apm-server<br>  labels:<br>    app: apm-server<br>spec:<br>  ports:<br>  - port: 8200<br>    targetPort: 8200<br>    name: http<br>    nodePort: 31000<br>  selector:<br>    app: apm-server<br>  type: NodePort<br>---<br>apiVersion: extensions/v1beta1<br>kind: Deployment<br>metadata:<br>  name: apm-server<br>spec:<br>  # this replicas value is default<br>  # modify it according to your case<br>  replicas: 1<br>  template:<br>    metadata:<br>      labels:<br>        app: apm-server<br>    spec:<br>      containers:<br>      - name: apm-server<br>        image: docker.elastic.co/apm/apm-server:6.3.1<br>        ports:<br>        - containerPort: 8200<br>          name: apm-port<br>        volumeMounts:<br>        - name: apm-server-config<br>          mountPath: /usr/share/apm-server/apm-server.yml<br>          readOnly: true<br>          subPath: apm-server.yml<br>      volumes:<br>      - name: apm-server-config<br>        configMap:<br>          name: apm-server-config</pre><blockquote>Replace the host: “&lt; Kibana endpoint &gt;” and hosts: [“&lt; Elasticsearch endpoint &gt;”] with end points.</blockquote><p>APM Server comes with predefined Kibana dashboards and index templates for APM data.</p><p>Following is the list of default dashboards available. You can also configure custom dashboards according to your needs.</p><ol><li>Transactions</li><li>Span Details</li><li>Services</li><li>Errors</li><li>Error Details</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vWV6P4XoCbF20xMnYys6RQ.png" /><figcaption>APM predefined Kibana dashboards</figcaption></figure><p>These dashboards give you an instant overview of application response times, requests per minutes, error occurrences and more.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VOnts9LMsgecv438tqltDA.png" /><figcaption>Response time and Request per minute metric</figcaption></figure><h4>APM Agent</h4><p>The agents are libraries that run inside your application process. Agents automatically instrument your application in order to measure the duration of requests to your service. It also automatically measures things like database queries, cache calls, external http requests and errors. Ensure you add APM agent to all of your micro services to get the metrics.</p><p><strong><em>APM agent for Dockerized Java application:</em></strong></p><p>The first step in getting started with the Elastic APM Java agent is to download the latest release of the agent jar file from <a href="http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22co.elastic.apm%22%20AND%20a%3A%22elastic-apm-agent%22">maven central</a>.</p><p>Add the following code in your Dockerfile to download and set the javaagent environment variable at the build time of the microservice.</p><pre>RUN wget -P &lt; $TOMCAT_HOME/ &gt; <a href="http://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent/">http://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent/</a>&lt;latest-version&gt;/elastic-apm-agent-&lt;latest-version&gt;.jar</pre><pre>ENV JAVA_OPTS=-javaagent:$TOMCAT_HOME/elastic-apm-agent-&lt; elastic-apm.version &gt;.jar</pre><p>Elastic APM agent has lot of configuration options.The most important ones are <em>service_name (required), server_url,</em> and <em>application_packages.</em></p><pre>System properties:</pre><pre>-Delastic.apm.service_name=my-service<br>-Delastic.apm.application_packages=org.example<br>-Delastic.apm.server_url=<a href="http://localhost:8300/">http://localhost:8200</a></pre><p>The complete Dockerfile entry for apm-agent will look like this</p><pre>RUN cd $TOMCAT_HOME &amp;&amp; wget <a href="http://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent/">http://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent/</a>&lt;latest-version&gt;/elastic-apm-agent-&lt;latest-version&gt;.jar<br> </pre><pre>ENV JAVA_OPTS=-javaagent:$TOMCAT_HOME/elastic-apm-agent-&lt;latest-version&gt;.jar \<br>              -Delastic.apm.service_name=&lt; Service name &gt; \<br>              -Delastic.apm.application_packages=&lt; application pakage name &gt; \<br>              -Delastic.apm.server_url=&lt; APM server url/endpoint &gt;</pre><p>The service name is used by Elastic APM to differentiate data coming from different services and to group data coming from the same services. When configuring an agent, you need to supply a service name.</p><p>The service name can only contain alphanumeric characters, spaces, underscores, and dashes (must match ^[a-zA-Z0–9 _-]+$).</p><p>You can set the Service Name and APM server url as the docker environmental variable as the value for these properties changes per environment you deploy.</p><p><strong><em>APM agent for Dockerized Node.js application</em></strong></p><p>In Dockerfile add the follwoing line</p><pre>RUN npm install elastic-apm-node --save</pre><p>Agent should be started before you mark other modules as dependency using require in your Node.js application . You will include the following code to enable agent in your application’s main file (usually <em>index.js, server.js or app.js</em>).</p><pre>// Add this to the VERY top of the first file loaded in your app<br>  var apm = require(&#39;elastic-apm-node&#39;).start({<br>    <br>    // Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)<br>    serviceName: &#39;&lt; Service Name&gt;&#39;,</pre><pre>// Use if APM Server requires a token<br>    secretToken: &#39;&lt; Secret token &gt;&#39;,</pre><pre>// Set custom APM Server URL (default: <a href="http://localhost:8200/">http://localhost:8200</a> )<br>    serverUrl: &#39;&lt; APM Server URL &gt;&#39;,<br>  })</pre><pre>var app = require(&#39;express&#39;)()</pre><p>Provided the correct value for the serviceName and serverUrl for the metrics to be collected.</p><h4>End Note:</h4><p>Elastic APM allowed us to avoid developing additional metering and instrumentation inside the micro services. APM agent takes care of monitoring all the key metrics. The data has been immensely useful for us to detect problems early and understand the state of the systems in production.</p><p>Happy Monitoring !!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8f22d52beb03" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/how-did-i-use-apm-in-kubernetes-ecosystem-8f22d52beb03">Using Elastic APM in Kubernetes</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Multiple Parameter Lists in Scala]]></title>
            <link>https://medium.com/logistimo-engineering-blog/multiple-parameter-lists-in-scala-521146d6908?source=rss----b690d71b4d79---4</link>
            <guid isPermaLink="false">https://medium.com/p/521146d6908</guid>
            <category><![CDATA[scala]]></category>
            <category><![CDATA[currying]]></category>
            <dc:creator><![CDATA[Sujith Jay Nair]]></dc:creator>
            <pubDate>Fri, 03 Aug 2018 07:08:01 GMT</pubDate>
            <atom:updated>2018-08-03T07:08:00.758Z</atom:updated>
            <content:encoded><![CDATA[<p>27 Jan 2018</p><p><strong>Note</strong>: I wrote this article as part of a contribution to Scala Documentation. The original post can be found <a href="http://docs.scala-lang.org/tour/multiple-parameter-lists.html">here</a>.</p><p>Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments. This is formally known as <a href="https://en.wikipedia.org/wiki/Currying">currying</a>.</p><p>Here is an example, defined in <a href="http://sujithjay.com/overviews/collections/trait-traversable.html">Traversable</a> trait from Scala collections:</p><pre>def foldLeft[B](z: B)(op: (B, A) =&gt; B): B</pre><p>foldLeft applies a binary operator op to an initial value z and all elements of this traversable, going left to right. Shown below is an example of its usage.</p><p>Starting with an initial value of 0, foldLeft here applies the function (m, n) =&gt; m + n to each element in the List and the previous accumulated value.</p><pre>val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) <br>val res = numbers.foldLeft(0)((m, n) =&gt; m + n) <br>print(res) // 55</pre><p>Multiple parameter lists have a more verbose invocation syntax; and hence should be used sparingly. Suggested use cases include:</p><h4>Single functional parameter</h4><p>In case of a single functional parameter, like op in the case of foldLeft above, multiple parameter lists allow a concise syntax to pass an anonymous function to the method. Without multiple parameter lists, the code would look like this:</p><pre>numbers.foldLeft(0, {(m: Int, n: Int) =&gt; m + n})</pre><p>Note that the use of multiple parameter lists here also allows us to take advantage of Scala type inference to make the code more concise as shown below; which would not be possible in a non-curried definition.</p><pre>numbers.foldLeft(0)(_ + _)</pre><p>Also, it allows us to fix the parameter z and pass around a partial function and reuse it as shown below:</p><pre>val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) <br>val numberFunc = numbers.foldLeft(List[Int]())_ <br>val squares = numberFunc((xs, x) =&gt; xs:+ x*x) print(squares.toString()) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100) <br>val cubes = numberFunc((xs, x) =&gt; xs:+ x*x*x) print(cubes.toString()) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)</pre><h4>Implicit parameters</h4><p>To specify certain parameters in a parameter list as implicit, multiple parameter lists should be used. An example of this is:</p><pre>def execute(arg: Int)(implicit ec: ExecutionContext) = ???</pre><p><em>Originally published at </em><a href="http://sujithjay.com/2018/01/27/Multiple-Parameter-Lists-in-Scala/"><em>sujithjay.com</em></a><em> on January 27, 2018.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=521146d6908" width="1" height="1" alt=""><hr><p><a href="https://medium.com/logistimo-engineering-blog/multiple-parameter-lists-in-scala-521146d6908">Multiple Parameter Lists in Scala</a> was originally published in <a href="https://medium.com/logistimo-engineering-blog">Logistimo Engineering Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>