Ali J Fahs
email: ali.fahs@irisa.fr

Guillaume Pierre
email: guillaume.pierre@irisa.fr

Proximity-Aware Traffic Routing in Distributed Fog Computing Platforms

Keywords: Fog Computing, Proximity-Awareness, Load-Balancing, Kubernetes

Container orchestration engines such as Kubernetes do not take into account the geographical location of application replicas when deciding which replica should handle which request. This makes them ill-suited to act as a generalpurpose fog computing platforms where the proximity between end users and the replica serving them is essential. We present proxy-mity, a proximity-aware traffic routing system for distributed fog computing platforms. It seamlessly integrates in Kubernetes, and provides very simple control mechanisms to allow system administrators to address the necessary trade-off between reducing the user-to-replica latencies and balancing the load equally across replicas. proxy-mity is very lightweight and it can reduce average user-to-replica latencies by as much as 90% while allowing the system administrators to control the level of load imbalance in their system.

I. INTRODUCTION

Fog computing extends datacenter-based cloud platforms with additional resources located in the immediate vicinity of the end users. By bringing computation where the input data was produced and the resulting output data will be consumed, fog computing is expected to support new types of applications which either require very low network latency to their end users (e.g., augmented reality applications [START_REF] Elbamby | Toward lowlatency and ultra-reliable virtual reality[END_REF]) or produce large volumes of data which are relevant only locally (e.g., IoT-based data analytics).

Geographical proximity of the computing resources with the end users makes fog computing platforms very different from traditional datacenter-based clouds: when cloud platforms aim to concentrate huge amounts of computing resources in a small number of data centers, fog computing rather aims to distribute resources as broadly as possible across some geographical area so some resources are always located in the immediate vicinity of every end user's devices.

A large range of fog computing applications such as fogassisted social networks and autonomous driving systems will need to serve numerous users or devices at the same time. To maintain proximity, these applications deploy multiple instances in relevant locations and provide a homogeneous interface to their users through the use of classical data partitioning and/or (partial) replication techniques. In this model, from a functional point of view any interaction with the application may be addressed to any instance of the application, but performance-wise it is highly desirable that interactions are addressed to nearby nodes.

A geo-distributed system such as a fog computing application must necessarily choose a suitable trade-off between resource proximity and load-balancing. A system which would always route every request to the closest instance may face severe load imbalance between instances if some users create more load than others [START_REF] Fan | Towards workload balancing in fog computing empowered IoT[END_REF]. On the other hand, systems like Mesos [START_REF] Hindman | Mesos: A platform for fine-grained resource sharing in the data center[END_REF], Docker Swarm [START_REF] Inc | Swarm mode overview[END_REF] and Kubernetes [START_REF]Cloud Native Computing Foundation[END_REF] implement location-unaware traffic redirection policies which deliver excellent load-balancing between application instances but very suboptimal user-to-resource network latencies.

In this paper we propose proxy-mity, a proximity-aware request routing plugin for Kubernetes. We chose Kubernetes as our base system because it matches many requirements for becoming an excellent fog computing platform: it can exploit even very limited machines thanks to its usage of lightweight containers rather than VMs, while remaining highly scalable and robust in highly dynamic and unstable computing infrastructures. Our approach can however easily be adapted to integrate in other container orchestration systems.

proxy-mity exposes a single easy-to-understand configuration parameter α which enables system administrators to express their desired trade-off between load-balancing and proximity (defined as a low user-to-instance network latency). It integrates seamlessly within Kubernetes and introduces very low overhead. In our evaluations, it can reduce the end-toend request latencies by up to 90% while allowing the system administrators to control the level of load imbalance in their system.

This paper is organized as follows. In Section II, we discuss the background and related work. In Section III, we present the design of proxy-mity, and in Section IV we evaluate its performance. Finally, in Section V we conclude.

II. RELATED WORK A. Background

Kubernetes is an open-source container orchestration platform which automates the deployment, scaling and management of containerized applications on large-scale computing infrastructures [START_REF]Cloud Native Computing Foundation[END_REF]. Kubernetes deploys every application instance in a Pod, which is a tight group of logically-related containers running in a single worker node. The containers which belong to the same pod expose a single private IP address to the rest of the Kubernetes system, and they can communicate with one another using an isolated private network. Pods are usually not managed directly by the developers. Rather, application developers are expected to create a Deployment Controller which is in charge of the creation and management of a set of identical pods providing the expected functionality. A Deployment Controller can dynamically add and remove pods to/from the set, for example to adjust the processing capacity according to workload variations or to deal with end-user mobility.

As illustrated in Figure 1, a set of identical pods can be made publicly accessible to external end users by creating a Service which exposes a single stable IP address and acts as a front end for the entire set of pods.

Although a Kubernetes service is conceptually a single component, it is implemented in a highly distributed manner. When an end user sends a request to an application's service IP address, this request is routed to one of the application's pods following a two-step process.

First step: routing external requests to the Kubernetes system. A variety of mechanisms such as DNS redirection and software-defined networking must be used to route the request to any node belonging to the Kubernetes system. This means in particular that every node in Kubernetes (which may or may not contain a pod of the concerned application) can actually act as a Gateway node between the end users and the Kubernetes system.

When using Kubernetes as a fog computing platform, we assume that the fog system is somehow able to route end user traffic to a nearby gateway node. In our implementation every fog compute node also acts as a WiFi hotspot to which end user's devices may connect to access the system. This organization naturally routes every request to a Kubernetes node in a single wireless network hop. Other implementations may rely on a wide variety of technologies such as LTE and SDN to provide the same functionality. Note that every fog computing platform must necessarily implement such a mechanism, otherwise it would not be able to provide any form of network proximity between the end users and the fog resources serving them.

Second step: internal request routing to one of the application's pods. The request is further routed internally to the Kubernetes cluster using DNAT (Destination Network Address Translation) which chooses one of the service pods' private IP address as a destination. When the application comprises more than one pod, Kubernetes load-balances requests equally between all available pods.

Internal request routing is implemented by a daemon process called kube-proxy which runs in every Kubernetes node. When the Kubernetes master node detects a change in the set of pods belonging to a service, it sends a request to all kube-proxy daemons to update their local routing tables. Such changes may be caused by an explicit action from the system such as starting or stopping a pod, or by a variety of failure scenarios.

The kube-proxy daemons are in charge of updating the kernel-level routing configuration using iptables or IPVS. For each service's IP address, kube-proxy creates rules which load-balance incoming connections among the service pods' private IP addresses. As shown in Figure 2, network traffic is addressed toward a Serving node which contains the actual Serving pod that will process the incoming request.

In the standard Kubernetes implementation, every incoming connection has an equal probability to be processed by each of the service pods. This load-balancing strategy is very sensible in a cluster-based environment where all service pods are equivalent in terms of their functional and non-functional properties. However, it clearly does not fit our requirement of proximity-based routing in the context of a fog computing platform. The objective of our work is therefore to re-design the internal network routing in Kubernetes such that every gateway node creates specific local routes that favorize nearby pods. In a broadly geo-distributed system such as a fog computing platform this will significantly decrease the mean and standard deviation of network latencies experienced by the end users, thereby providing them with a better and more predictable user experience.

B. State of the art

Fog computing aims at providing compute, storage and networking resources that are geographically distributed across a geographical area such as a building, a neighborhood and a city [START_REF] Bonomi | Big Data and Internet of Things: A Roadmap for Smart Environments[END_REF], [START_REF] Yousefpour | All one needs to know about fog computing and related edge computing paradigms: A complete survey[END_REF]. Much like cloud platforms, fog platforms rely on virtualization techniques to support multi-tenancy and increase resource utilization. For resource-efficiency reasons, most fog computing platforms rely on lightweight container technologies [START_REF] Pahl | A container-based edge cloud PaaS architecture based on Raspberry Pi clusters[END_REF] rather than virtual machines, enabling one to envisage fog computing platforms making use of resources as limited as Raspberry Pis for example [START_REF] Tso | The Glasgow Raspberry Pi cloud: A scale model for cloud computing infrastructures[END_REF], [START_REF] Van Kempen | MEC-ConPaaS: An experimental single-board based mobile edge cloud[END_REF].

The main purpose of fog computing is to allow applications to use resources located in the immediate vicinity of the end users. This for example enables applications which can offload parts of their tasks to the fog infrastructure. Optimizing the trade-off between latency and using the limited edge resources is relevant for example for video analytics applications [START_REF] Yi | Lavea: Latencyaware video analytics on edge computing platform[END_REF]. Such applications must carefully control the trade-off between user-perceived latency and energy consumption [START_REF] Deng | Optimal workload allocation in fog-cloud computing toward balanced delay and power consumption[END_REF].

When multiple fog nodes provide equivalent functionality, it is the task of a load balancer to choose the best available node which should process each end user request. Puthal et al. propose a secure and sustainable load balancing technique which aims to distribute the load to the less-loaded edge data centers [START_REF] Puthal | Secure and sustainable load balancing of edge data centers in fog computing[END_REF]. Similarly, Beraldi et al. propose a cooperative load balancing technique to distribute the load over different edge data centers to reduce the blocking probability and the task overall time [START_REF] Beraldi | Cooperative load balancing scheme for edge computing resources[END_REF]. However, these techniques do not aim to reduce the network latency between the end user and the fog node serving them. Also, they were evaluated using simulations only, with no actual system implementation.

Kapsalis et al. propose a fog-aware publish-subscribe system which aims to deliver messages to the best possible node according to a combination of network latency, resource utilization and battery state [START_REF] Kapsalis | A cooperative fog approach for effective workload balancing[END_REF]. To our best knowledge this is the only proposed fog system which aims, similarly to our work, at implementing a trade-off between proximity and fair load balancing. However, this approach was implemented and evaluated only in simulation. It is unclear how network latencies, resource utilization and battery states would be measured in a real implementation nor how messages would be routed to their destination without being dispatched by a single central broker node.

PiCasso is a container orchestration platform that specifically targets edge clouds with a focus on lightness and platform automation [START_REF] Lertsinsrubtavee | PiCasso: A lightweight edge computing platform[END_REF]. The developers of PiCasso intend to develop a service proxy that will redirect user's request to the closest node. However, no technical detail is provided. PiCasso is still under development and not publicly available.

OpenStack++ is a set of OpenStack extensions that enable the deployment of Cloudlets in an edge computing environment [START_REF] Ha | OpenStack++ for cloudlet deployment[END_REF]. However, applications in OpenStack++ are implemented as a single (migratable) VM so requests addressed to any application always have only a single possible destination.

Fogernetes is an extension of Kubernetes which, similarly to our work, aims to extend Kubernetes for fog computing scenarios [START_REF] Wöbker | Fogernetes: Deployment and management of fog computing applications[END_REF]. Fogernetes and proxy-mity rely on the same application model based on pods and replication controllers. However, in Fogernetes, the selection of which pod should be used to process which request is done manually through the use of node labels. In contrast, proxy-mity aims to automate the pod selection to implement any trade-off between proximity and fair load balancing defined by the platform's administrator.

III. SYSTEM DESIGN

proxy-mity1 is a plug-in designed to integrate in a Kubernetes system and implement proximity-aware traffic routing. It however has very few dependencies with Kubernetes and may arguably be adapted to work in different platforms.

Similarly to the standard kube-proxy Kubernetes component, proxy-mity is deployed in every worker node of the system. It continuously monitors network latencies with the other worker nodes using Serf [START_REF] Hashicorp | Serf: Decentralized cluster membership, failure detection, and orchestration[END_REF], a lightweight implementation of Vivaldi coordinates [START_REF] Dabek | Vivaldi: A decentralized network coordinate system[END_REF]. When a proxy-mity daemon detects a change in the set of pods belonging to any service, it recomputes a new set of traffic routing rules (with their weights determining the probability that a request follows each route) according to preferences expressed by the system administrator, and injects them in the local Linux kernel using iptables.

In the next sections we respectively discuss the overall system architecture, the representation and measurement of proximity between nodes, the calculation of weights to be associated with each route, and the injection of new routes in the local Linux kernel.

A. Architecture

Kubernetes is designed as a set of control loops. It therefore continuously monitors itself, and takes corrective actions when the state it observes deviates from the specification of the desired system state. This organization makes it highly dynamic and robust against a wide range of situations. The master node maintains a view of the current system state which can be queried by other components.

As shown in Figure 3a, in unmodified Kubernetes a kubeproxy daemon is started in every worker node to maintain its local iptables routes. When a change is detected in the set of pods belonging to a service (caused by a pod start or stop operation or by any kind of failure), all kube-proxy daemons re-inject new routes in their local iptables system. All kube-proxy daemons inject the same set of rule which ensures that every pod from the application receives an equal 1/N share of the load (where N is the number of pods of the application). This ensures excellent load balancing between the pods. However, in a fog computing scenario where nodes are broadly geo-distributed, it actually routes significant amounts of end user requests to pods located far away from them. This results in unacceptably high mean network latencies, and also in very high standard deviations. The architecture of proxy-mity, presented in Figure 3b, is very similar to that of kube-proxy. It receives the same notifications as kube-proxy upon a change in the set of pods belonging to a service. However, each kube-proxy daemon computes a specific set of weights to be attached to each route according to the measured network latencies. Different worker nodes therefore compute different sets of rules, and the weights attached to different routes in each gateway node are explicitly biased to send more load to nearby nodes.

i Pod 1 Pod N W 1 = 1/N W i = 1/N W N = 1/N W 1 = 1/N W i = 1/N W N = 1/N W 1 = 1/N W i = 1/N W N =
W i = F(X 1,pi ) W N = F(X 1,pN ) W 1 = F(X i,p1 ) W i = F(X i,pi ) W N = F(X i,pN ) W 1 = F(X K,p1 ) W i = F(X K,pi ) W N = F(X K,
These sets of rules are recomputed and re-injected every time a modification is detected in the set of pods which constitute an application, and also periodically to account for possible variations in the measured network latencies between nodes.

B. Measuring proximity

Data center networks often follow very complex topologies to provide cloud users with many interesting properties such as excellent bisection bandwidth and resilience toward a wide range of possible disruptions. They often have excellent performance which means that the inter-node latencies within a data-center are usually low enough to be ignored in practice. Nodes in a data center may be located far from the end users, but they are very close from each other. This is the reason why orchestration systems such as Kubernetes that were designed for data center environments do not make any attempt at routing end user requests to nearby nodes. However, in fog computing environments resources are physically distributed across some geographical area in order to provide compute, storage and networking resources in the immediate vicinity of the end users. Nodes in this case will be close to the end users, but necessarily far from each other.

There are many ways to represent proximity. For example, the broad availability of inexpensive GPS receivers makes it easy to measure the geographical distance between nodes. However, geographical distance is known to be a poor predictor for route lengths or latencies in large-scale network infrastructures [START_REF] Subramanian | Geographic properties of internet routing[END_REF]. We therefore prefer directly relying on network latency as the measure of proximity.

To avoid the overhead of periodically measuring N 2 pairwise latencies between N nodes, proxy-mity relies on Vivaldi coordinates [START_REF] Dabek | Vivaldi: A decentralized network coordinate system[END_REF] for modeling the latencies between nodes. Vivaldi is a distributed, lightweight algorithm to accurately predict the latency between hosts without contacting them. Using Vivaldi, a node in the cluster can easily compute the latency with all the nodes by communicating with a few of them.

We specifically use Serf [START_REF] Hashicorp | Serf: Decentralized cluster membership, failure detection, and orchestration[END_REF], a mature open-source tool which maintains cluster membership, detects failures, and offers a robust implementation of Vivaldi coordinates. Serf is based on a gossiping protocol where each node periodically contacts a set of randomly-selected other nodes, measures latencies to them, and adjusts their Vivaldi coordinates accordingly. Latency between any pair of nodes is modeled as the Euclidean distance between their respective Vivaldi coordinates. The end result is a lightweight and robust system which can produce accurate predictions of inter-node latencies.

Figure 4 depicts the accuracy of latency predictions produced by Serf. Immediately after a fresh node joins a 12-node cluster, its latency predictions are highly inaccurate. However, the system converges very quickly. Roughly 20 seconds after startup, the prediction error consistently remains below 20%, and stabilizes in the order of 10%. In a fog computing system where latencies between nodes are expected to belong to a very wide range of values, this level of prediction accuracy is largely sufficient to distinguish a nearby node from a further away one.

C. Weight calculation

In Kubernetes, a set of identical pods is called a Deployment. A Kubernetes service associates a single IP address to such a set of pods to which incoming requests are distributed.

Consider a deployment Φ composed of N functionally identical pods:

Φ = {ϕ 1 , ϕ 2 , ..., ϕ N }
where each ϕ represent one pod in this deployment.

A Kubernetes service essentially implements a map function which determines the probability that an incoming connection gets routed to each of these pods. Kubernetes' kube-proxy component implements a very simple mapping function:

F (ϕ i ) = 1/N ∀ϕ i ∈ Φ
We can however generalize this formula to any function F which respects:

F : Φ -→ [0, 1] | N i=1 F (ϕ i ) = 1
As previously discussed, a request routing system for fog computing environments must necessarily implement a tradeoff between proximity and load balancing. A system which optimizes based on proximity only risks severe load imbalances between pods in case different numbers of requests are generated in different geographical areas of the system. On the other hand, balancing the load equally among pods will result in larger means and standard deviations of the latencies between the users and the pods serving them.

We address this challenge by proposing two mapping functions P (which aims for proximity regardless of load balancing) and L (which aims at load balancing regardless of proximity). These two functions can be combined in a single function F α :

F α (ϕ) = α.P (ϕ) + (1 -α).L(ϕ) (1)
Here α ∈ [0, 1] is a parameter chosen by the system administrator which represents the desired trade-off between pure load-balancing (when α = 0) and pure proximity-based routing (when α = 1).

Function L, which aims to balance the load, is the same as the original Kubernetes one:

L(ϕ i ) = 1/N ∀ϕ i ∈ Φ
Function P , which aims at maximizing proximity, takes into account the estimated network latencies between the local node and all the possible serving nodes in the system. These latencies are represented by the set L = {l 1 , l 2 , ..., l N } where l i represents the network latency to the physical node which holds pod ϕ i . In fact, any function where nodes with lower latencies are given greater weight than further away nodes may act as the proximity-maximizing decay function:

P (ϕ i ) = f β (l i ) N j=1 f β (l j ) (2)
where f β (l i ) is a weight determined from the estimated latency to every node. We use the secondary parameter β to determine how aggressive the proximity-oriented function should be to favorize nearby nodes.

We propose three possible decay functions to determine the weights f β (l):

f inverse β (l) = 1 βl (3)
f power β (l) = 1 l β (4)
f exponential β (l) = e -βl (5)
As we will discuss in Section IV, different decay functions have different levels of aggressiveness in selecting nearby pods.

The final weight function F α,β (ϕ) is therefore:

F α,β (ϕ i ) = (1 -α). 1 N + α. f β (l i ) N j=1 f β (l j ) ∀ϕ i ∈ Φ (6)
A special case in the computation of weights relates to fact that the node which computes new weights may also hold a pod of the concerned application. In this case, the latency attached to the localhost interface may be as low as 0.3 ms. When applying formulas 3, 4 or 5 this results in giving the localhost route an extremely high probability compared to the other pods of the application. To avoid this effect, we artificially increase the localhost latencies in the weight calculation by a parameter localrtt that is set to be slightly lower than the lowest inter-node latencies observed in the deployed system.

D. Updated routes injection

Once every node in proxy-mity has computed the fraction of requests it should route to every other node, the last step is to inject the corresponding routes in the Linux kernel firewall in the form of iptables rules. iptables defines chains of rules for the treatment of packets where every chain is associated with a different kind of packet processing. Packets are processed by sequentially traversing the rules in their chains.

As illustrated in Figure 5, iptables rules are organized in five chains. Incoming packets first traverse the PREROUTING chain, then they get split between two chains. The packets whose destination IP address is locally available are sent to the INPUT chain for immediate delivery. Other packets traverse the FORWARD chain which decides where they should be sent next. On the other hand, the packets issued from the local node traverse the OUTPUT chain. Finally, all outgoing packets traverse the POSTROUTING chain before being actually sent to the network. Kubernetes implements its internal network routing system by defining rules in the PREROUTING and OUTPUT chains: incoming network packets whose destination address matches the IP address of a Kubernetes service are redirected using rules in the PREROUTING towards the loadbalancing chain. On the other hand, the OUTPUT chain redirects the packets sent to the service by the local node itself.

As depicted in Figure 6a, every Kubernetes service is actually implemented as a separate chain which redirects packets to the respective pods using DNAT. To load-balance incoming requests among the service pods, each iptables rule i defines a probability P i for incoming requests to exit the iptables chain and get routed to the corresponding pod P od i .

Rules are executed in a predefined sequential order, so the probabilistic load-balancing system actually implements a Markov chain, as shown in Figure 6b. Every incoming packet sent to the service first undergoes rule 1 with a probability P 1 of exiting the chain and of being redirected to P od 1 . With probability 1 -P 1 the packet continues to the next rule. The same mechanism is used for all rules in the chain, except the last one which routes all remaining messages to the last pod with probability 1. Based on the individual probabilities P i , an incoming packet will therefore eventually get routed to P od i with probability P (P od i ):

P (P od i ) =                  P 1 if i = 1 P i × i-1 j=1 (1 -P j ) if 1 < i < N N -1 j=1 (1 -P j ) if i = N (7)
Injecting a set of weights W = {w 1 , w 2 , ..., w N } as computed in Equation 6for a deployment Φ therefore requires us to compute the probabilities P i which should be defined in the iptables Markov chain such that the resulting probabilities P (P od i ) match the desired weights w i : Fig. 6: Load balancing rules in iptables.

Load Balancing Chain

P i =                    w 1 if i = 1 w i × 1 i-1 j=1 (1-Pj ) if 1 < i < N 1 if i = N (8)
Upon every detected modification in the set of pods belonging to a Kubernetes service, proxy-mity therefore recomputes the weights w i using Equation 6 in every worker node of the system based on its estimated latencies to the other nodes, and converts them into iptables rule probabilities using Equation 8 before injecting them in the local Linux kernel. The same process is also applied periodically to account for possible modifications in the estimated inter-node network latencies.

We evaluate the performance of these newly applied rules in the next section.

IV. EVALUATION A. Experimental setup

We evaluate proxy-mity using an experimental testbed composed of 12 Raspberry Pi 3 B+ single-board computers (Rpi's), as depicted in Figure 7. Despite their obvious hardware limitations, Raspberry PIs offer excellent performance/cost/energy ratios and are well-suited to fog computing scenarios where the devices' physical size and energy consumption are important enablers for actual deployment [START_REF] Ahmed | Docker Container Deployment in Fog Computing Infrastructures[END_REF], [START_REF] Hajji | Understanding the performance of low power Raspberry Pi cloud for big data[END_REF].

All Rpi's are installed with HypriotOS 1.9.0 Linux distribution2 , Linux 4.4.50 kernel, and Kubernetes v1.9.3. In this setup, one machine acts as the Kubernetes master node while the eleven remaining nodes act as worker nodes. These machines are connected to each other using a dedicated Gigabit Ethernet switch. Every worker node also acts as a WiFi hotspot which allows end users and external IoT devices to connect to a nearby node. Any request addressed by an enduser device to a Kubernetes service therefore reaches one of the worker nodes in a single WiFi network hop, before being further routed via the wired network to one of the service's pods using the iptables rules created by proxy-mity.

We create artificial network latencies between every pair of nodes using the Linux tc command. We use actual measurements of city-to-city network latencies as a representation of realistic pairwise latencies between geo-distributed nodes. These pairwise latencies were obtained from the WonderNetwork 3 GeoIP testing solution, and are presented in Table I. In this configuration, network latencies range from 4 ms to 40 ms and can arguably represent a typical situation for a geodistributed fog computing infrastructure. 3 Fig. 8: CPU and Memory Usage For proxy-mity.

B. Performance overhead

The proxy-mity load-balancing system must carry additional tasks compared to the standard kube-proxy component of Kubernetes: it must execute Serf on every worker node (which creates periodic CPU and network activity), recompute weights and inject updated routes periodically. When the fog computing platform is composed of limited devices such as Raspberry PIs it is important to keep this performance overhead as low as possible.

Figure 8 shows the the total node's CPU and memory usage before and after starting proxy-mity on one of the cluster's nodes. proxy-mity is configured to check for changes every 10 seconds (this is the default value in our implementation).

Before proxy-mity starts at time 15 s, the monitored node is already acting as an (idle) Kubernetes worker node. It uses on average 3% of CPU and 187 MB of memory. After proxy-mity is started the memory usage grows by only 3 MB and the average CPU usage grows by ≈ 2-4%. We conclude that the performance overhead, although not totally negligible, remains sufficiently low not to disturb the good behavior of worker nodes in their operations.

This low performance overhead also indicates that the introduction of proxy-mity will not significantly affect the scalability or fault-tolerance properties of Kubernetes. Besides the introduction of the very lightweight, scalable and robust Serf system, proxy-mity does not require a re-organization of Kubernetes processes, and simply creates iptables rules with different weights at every node.

C. Service access latency

We first evaluate the effectiveness of proxy-mity in distributing load according to a given proximity/loadbalancing trade-off α and decay function f β (l). We deploy proxy-mity with a Kubernetes service which contains a small Web server that simply returns the IP address of the serving pod to every client. The execution time of the service function itself is extremely short, so any end-to-end latency measured at the client side accurately represents the network latency that was experienced by every request. In every experiment in this section, we issue 1000 HTTP requests originating from a single node of the system (the London node), and observe the distribution of latencies experienced by these requests. The requests address a Kubernetes service which is deployed either across 11 pods (one in every worker node of the system), or only 5 pods (with none of these pods running in the London node). Having all traffic originating from a single node can be seen as a worst-case scenario for load-balancing among pods, and therefore allows us to closely observe the behavior of proxy-mity. The parameters for this experiment are summarized in Table II Figure 9 shows the average measured end-to-end latency for various values of α, choices of decay function, and values of β: Figure 9a shows the results with a deployment of 11 pods, and Figure 9b shows the results with a deployment of 5 pods.

a) Effect of parameter α: In all presented figures, we observe that configurations where α = 0 experience high average latencies. This is due to the fact that requests are distributed equally among all the pods, so a significant fraction of requests gets routed over long-latency routes. This is the default Kubernetes behavior.

When α increases, requests experience much lower latencies, which indicates that the closest pods receive more load than the others. For example, in the case of {|Φ| = 11, β = 0.5, f β (l) = exp(-βl)}, the overall average request latency is 15.7 ms for α = 0 but only 1.09 ms for α = 1 (a 92% reduction of latency).

The parameter α therefore effectively allows the system administrator to control the latency/load-balancing trade-off: low values of α produce equal load balancing whereas high values of α favorize proximity.

b) Effect of parameter β and the choice of decay function: All evaluated decay functions achieve similar results where greater values of α produce lower average service latencies. However, they differ in their level of aggressiveness. Unsurprisingly, the exponential function exp(-βl) produces the fastest decay whereas the other two functions produce slower decay. The exponential function may therefore be used in scenarios where we want to strongly skew the request routing system toward proximity, whereas the other two functions may be used for implementing less skewed load distribution.

Interestingly, the choice of parameter β does not significantly influence the end results, except for the f β (l) = 1 l β decay function. This is due to the fact that the shape of the chosen decay function matters more than its own parameter.

In future experiments we therefore fix β to a single "medium" value per decay function.

D. Load distribution

We now focus more closely on the statistical distribution of request latencies. We execute the same experiment as in the previous section over a deployment of 11 pods, and measure the number of requests which get routed to each pod (sorted by their latency to the gateway node).

The experiment results are presented in Figure 10. Each bar in the figure indicates the number of requests processed by a pod with the associated latency to the gateway node. We can see when α = 0 that all the pods receive roughly the same number of requests regardless of their distance to the gateway node. The load per pod fluctuates slightly because the routing system is probabilistic and therefore experiences some amount of noise.

As the value of α increases, more packets get routed toward the pods with a lower latency. Finally, with α = 1 the load is balanced only based on the proximity function, which leads to extreme skew between nodes (in particular in the case of f (l) = exp(-l/2), where a single pod receives more than 90% of the total load).

The obvious possible drawback in the extreme case of α = 1 is that a single pod which processes most of the incoming traffic might become overloaded as a result of the load imbalance. Remember however that we are producing incoming traffic at a single node only. In a setup where traffic is being generated in multiple locations, we would observe much less load imbalance between the pods, as we discuss next.

E. Load (im)balance in the presence of multiple senders

A fog computing platform has very few reasons to deploy pods in regions where no user is accessing the considered service. Evaluations where all the traffic originates from a single sender therefore represent a worst-case scenario in terms of the load imbalance it creates. A more realistic scenario where traffic originates from multiple senders in various regions of the system would arguably experience a much lower load imbalance.

To study this effect, we simulated a system where a randomly-chosen subset of the worker nodes act as traffic senders. All senders issue the same number of requests, while the other nodes do not send any request at all. Using Equation 6 with f (l) = exp(-l/2) (where β = 0.5) we can compute the weights that each sender node would assign to each of the pods, based on the inter-node latencies from Table I. In the presence of multiple senders, each pod serves a large number of requests originating from nearby senders, and lower numbers of requests originating from senders located further away. We can therefore add these numbers together to compute the total load that each of the pods is expected to receive.

Figure 11 depicts the standard deviation among the predicted loads per pod, in a scenario where every node holds a pod of the service and a random subset of k nodes act as traffic senders.

We observe two interesting phenomena. The first one relates to the fact that a greater number of senders naturally creates a better-balanced system. Using one sender among 11 nodes, with α = 1, the standard deviation among predicted pods' loads is as high as 25% of the mean load among pods. When moving to two randomly-chosen senders, this standard deviation drops to 17% of the mean. The same trend continues until the scenario where all nodes act as senders: here the standard deviation drops to a mere 1% of the mean. This indicates that, although α = 1 requires proxy-mity to aggressively favorize proximity and low end-to-end request latencies, geographical distribution of the traffic sources naturally helps to balance the load among pods. The more uniform the distribution of traffic sources is, the better-balanced the resulting system will be (without sacrificing the objective of proximity and low service latencies).

The second phenomenon concerns the relation between α and the system load imbalance, measured as the standard deviation between predicted pods' load. When α = 0 the predicted load imbalance is obviously 0, as each sender equally distributes the load it creates between all the pods. When α = 1 the predicted load imbalance is a function of the distribution of traffic sources. Interestingly, when α takes intermediate values between 0 and 1, the load imbalance varies linearly between these two extremes 4 . This means that the criteria for choosing a good value for α can be explained to system administrators in a precise yet very intuitive manner: "α linearly controls the system imbalance between 0 when α = 0 and some value when α = 1 which is determined by the geographical heterogeneity of the traffic senders".

V. CONCLUSION

Container orchestration engines such as Kubernetes do not take the geographical location of service pods into account when deciding which replica should handle which request. This makes them ill-suited to act as general-purpose fog computing platforms where the proximity between end users and the replica serving them is essential. We presented proxy-mity, a proximity-aware traffic routing system for distributed fog computing platforms. It seamlessly integrates in Kubernetes, and gives very simple mechanisms to allow system administrators to control the necessary trade-off between reducing the user-to-replica latencies and balancing the load equally across replicas. When the pods are geographically distributed close to the sources of traffic, proxy-mity drastically reduces the end-to-end service access latencies without creating major system load imbalances.

This work demonstrates that orchestration systems which were originally designed for cluster-based environments can be extended to become proximity-aware with no need for major structural changes. It paves the way toward extending some of the major orchestration systems to become mainstream, general-purpose platforms for future fog computing scenarios.

Fig. 1 :

 1 Fig. 1: Organization of a Kubernetes service.

Fig. 2 :

 2 Fig. 2: Gateway and Serving Nodes.

  proxy-mity architecture.

Fig. 3 :

 3 Fig. 3: Architectures of kube-proxy and proxy-mity.

Fig. 4 :

 4 Fig. 4: Accuracy of Vivaldi latency predictions for a newly joined node in a 12-node cluster.

Fig. 5 :

 5 Fig. 5: Iptables chains and load balancing.

  iptables rule chains for both types of packets.

  Markov chain implementing the load-balancing rules for one Kubernetes service.

  (a) Deployment with 11 pods located in all the nodes. (b) Deployment with 5 pods (none of them in the London gateway node).

Fig. 9 :

 9 Fig. 9: Average service access latency.

Fig. 10 :

 10 Fig. 10: Load distribution as a function of α and f (l).

Fig. 11 :

 11 Fig. 11: Overall system load imbalance as a function of α and the number of senders.

TABLE I :

 I Inter-node network latencies (ms).

  https://wondernetwork.com/

	Proxy-mity Started	Cycle 1	Cycle 2	Cycle 3	Cycle 4	Cycle 5	Cycle 6	Cycle 7

  .

	α	{0.1, . . . , 1}
	β	{0.2, 0.5, 1, 1.5, 2}
	f β (l)	{1/βl, 1/l β , exp(-βl)}
	localrtt	3 ms
	Number of pods (|Φ|)	{5, 11}
	Transmitted requests/experiment 1000

TABLE II :

 II Evaluation parameters.

https://github.com/alijawadfahs/FOG-aware

https://blog.hypriot.com/downloads/

This can be explained analytically but detailing the proof would exceed the scope of the current paper.