Quo Vadis
Netflix Stack?
// Baris Cubukcuoglu & Fabian Keller
Photo by Ajeet Mestry on Unsplash
Baris Cubukcuoglu
Software Engineer
Photographer
@bariscubuk__
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 2
Fabian Keller
Software Engineer
Woodworker
@_fabiankeller
Netflix OSS – Well known Projects
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 4
Zuul
API Gateway
Eureka
Service Registry
Archaius
Centralized Config
Microservice A
Hystrix
Ribbon
Microservice B
Hystrix
Ribbon
Feign Feign
Eureka, Feign & Ribbon (with Spring Cloud)
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 5
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Hystrix (with Spring Cloud)
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 6
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Zuul (with Spring Cloud)
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 7
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Archaius (with Spring Cloud)
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 8
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
9
Maintenance Mode
Photo by Pandu Agus Wismoyo on Unsplash
Archaius
Centralized Config
Zuul
API Gateway
Eureka
Service Registry
Microservice A
Hystrix
Ribbon
Microservice B
Hystrix
Ribbon
Feign Feign
Which Projects are affected?
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 10
Maintenance Mode
Maintenance Mode
Are there any alternatives?
TL;DR: yes!
For Hystrix:
Resilience4j, Sentinel, Spring Retry
For Hystrix Dashboard / Turbine:
Micrometer + Monitoring System (e.g. Prometheus etc.)
For Archaius:
Spring Cloud Config, HashiCorp Vault
For Ribbon:
Spring Cloud Load Balancer, gRPC
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 11
Fallacies of Distributed Computing
see https://bit.ly/1IEpFC0
The network is reliable
Latency is zero
Bandwidth is infinite
The network is secure
Topology doesn’t change
There is one administrator
Transport cost is zero
The network is homogeneous
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 12
Patterns
• Stability
• Capability
• Transparency
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 13
Photo by chuttersnap on Unsplash
15% Internet Traffic
Service Discovery
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 15
Client
Registry
Service A
Service A
Service A
Service A
Service A
Service B
Load
balance
Register
Lookup
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Load Balancing
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 16
Client
Service Service
Availability
Filtering
Client
Service Service
Round Robin
Client
Service
0.7
Service
0.3
Weighted
Response Time
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Circuit Breaker
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 17
Execute Command
Run
Fallback
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Bulkhead
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 18
Thread pool
Service
X
Service
Z
Resource
Call
Resource
Call
Resource
Call
DB Y
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Bulkhead
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 19
Service
X
Service
Z
Resource
Call
Resource
Call
Resource
Call
DB Y
Pool X Pool Y Pool Z
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
API Gateway
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 20
Client
Resource
Resource
Resource
Resource
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
API Gateway
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 21
Client
Resource
Resource
Resource
Resource
API Gateway
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 22
The Modern Cloud Stack
Photo by Pero Kalimero on Unsplash
Where do we begin with?
A homogeneous microservice landscape, yeah right…
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 23
Netflix
OSS
Netflix
OSS
Netflix
OSS
Netflix
OSS
Netflix
OSS
Netflix
OSS
Netflix
OSS
Netflix
OSS
?!
So how do we solve all these challenges?
Using sidecars instead of libraries
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 24
Application Layer
Cross-cutting concerns
Infrastructure Layer
Cross-cutting concerns
Application
Netflix
OSS
Application
Egress
Ingress
Egress
Ingress
Egress
Ingress
Egress
Ingress
Egress
Ingress
Egress
Ingress
Egress
Ingress
Egress
Ingress
Egress
Ingress
Adding the sidecars to all containers
We can have the exact same architecture as before
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 25
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 26
Photo by Erdenebayar Bayansan on Pixabay
Cloud Foundry
What is Cloud Foundry?
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 27
Open Source Faster to iterate Scalable platform
cf push -p target/spring-music.jar
Container Network
Cloud Foundry Service Discovery
a.k.a. Container Networking. Also enables client-side load balancing via DNS
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 28
moments.apps.internal
10.254.40.156
media.apps.internal
10.254.40.148
media.apps.internal
10.254.40.123
media.apps.internal
10.254.40.42
myapp.com
10.254.40.156
moments.apps.internal
10.254.40.148
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
DNS? moments.apps.internal
A 10.254.40.148
A 10.254.40.156
Cloud Foundry Service Discovery
How to setup CF container network
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 29
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Cloud Foundry Route Services
Taking care of ingress traffic
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 30
Cloud Foundry
CF
Router
App
Load
Balancr
Client
Route
Service
Service
Broker
• Security
• Rate Limiting
• Caching
• Tracing
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Cloud Foundry Dynamic App Config
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 31
CF SET-ENV CF RESTART
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 32
Kubernetes Istio
Photo by Bobby Burch on Unsplash
Kubernetes Service Discovery
Deployments and Services
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 33
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Environment
moments
172.10.40.156
media
172.10. 40.148
media
172.10.40.123
media
172.10.40.42
Cluster IP
10.254.40.156
moments
172.10.40.148
DNS? moments
A 10.254.40.148
Kind: k8s/DeploymentKind: k8s/Service
moments.my-namespace.svc.cluster.local
10.98.61.186
Kubernetes Service Discovery
Exposing a service
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 34
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
new RestTemplate().exchange(„http://moments/api/v1/timeline“, …)
Pod 1 moments-pod172.10.40.148
Pod 2 moments-pod172.10.40.156
Istio Architecture
Control Plane and Data Plane
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 35
Control Plane
Data Plane
Pilot Citadel Mixer
Pod 1
Envoy
App 1
Pod 2
Envoy
App 2
Istio VirtualService
Adding a VirtualService layer to intelligently route traffic
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 36
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Kind: k8s/DeploymentKind: k8s/Service
moments-v1
10.98.61.186
Pod 1 moments-v1-pod
Pod 2 moments-v1-pod
Kind: istio/VirtualService
moments
Match routing rules:
/api/v1 à moments-v1
/api/v2 à moments-v2
Kind: k8s/Deployment
Pod 1 moments-v2-pod
Kind: k8s/Service
moments-v2
10.98.61.193
Istio Destination Rules
Destination rules apply after routing rules are evaluated
Apply various policies to traffic:
• Load Balancer Policy (RR, Random)
• Client TLS
• Circuit Breaker
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 37
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
K8s/Istio Dynamic App Config
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 38
VIM KUBE-APP.YAML KUBECTL APPLY
Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
Istio Additional Features
This was just the beginning…
• Automatic Retries
• Rate Limiting
• mTLS
• Policy Enforcement
• Observability & Monitoring
• Distributed Tracing
• Fault Injection
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 39
Platform Support
Service Discovery Eureka Container Networking Kubernetes Services
Load Balancing Ribbon Container Networking Kubernetes Services
Circuit Breaker Hystrix / Turbine – Istio Destination Rule
API Gateway Zuul
Route Services
Canary Deployments
Istio Virtual Service
Istio Gateway
Dynamic Config Archaius
cf set-env
cf restart
vim kube-app.yaml
kubectl apply
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 40
Limitations
There is always a flipside
• We‘re now hiring for a full-time YAML engineer
• Sometimes infrastructure shouldn‘t take care (e.g. retries)
• Yet another markup language stack to learn
• People will start to write microservices in other languages
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 41
Thanks!
kubectl apply –f questions.yaml
Come visit our booth!
2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller
Photo by Ajeet Mestry on Unsplash

Quo Vadis Netflix Stack?

  • 1.
    Quo Vadis Netflix Stack? //Baris Cubukcuoglu & Fabian Keller Photo by Ajeet Mestry on Unsplash
  • 2.
    Baris Cubukcuoglu Software Engineer Photographer @bariscubuk__ 2019-07-04/ Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 2 Fabian Keller Software Engineer Woodworker @_fabiankeller
  • 4.
    Netflix OSS –Well known Projects 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 4 Zuul API Gateway Eureka Service Registry Archaius Centralized Config Microservice A Hystrix Ribbon Microservice B Hystrix Ribbon Feign Feign
  • 5.
    Eureka, Feign &Ribbon (with Spring Cloud) 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 5 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 6.
    Hystrix (with SpringCloud) 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 6 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 7.
    Zuul (with SpringCloud) 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 7 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 8.
    Archaius (with SpringCloud) 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 8 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 9.
    9 Maintenance Mode Photo byPandu Agus Wismoyo on Unsplash
  • 10.
    Archaius Centralized Config Zuul API Gateway Eureka ServiceRegistry Microservice A Hystrix Ribbon Microservice B Hystrix Ribbon Feign Feign Which Projects are affected? 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 10 Maintenance Mode Maintenance Mode
  • 11.
    Are there anyalternatives? TL;DR: yes! For Hystrix: Resilience4j, Sentinel, Spring Retry For Hystrix Dashboard / Turbine: Micrometer + Monitoring System (e.g. Prometheus etc.) For Archaius: Spring Cloud Config, HashiCorp Vault For Ribbon: Spring Cloud Load Balancer, gRPC 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 11
  • 12.
    Fallacies of DistributedComputing see https://bit.ly/1IEpFC0 The network is reliable Latency is zero Bandwidth is infinite The network is secure Topology doesn’t change There is one administrator Transport cost is zero The network is homogeneous 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 12
  • 13.
    Patterns • Stability • Capability •Transparency 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 13
  • 14.
    Photo by chuttersnapon Unsplash 15% Internet Traffic
  • 15.
    Service Discovery 2019-07-04 /Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 15 Client Registry Service A Service A Service A Service A Service A Service B Load balance Register Lookup Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 16.
    Load Balancing 2019-07-04 /Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 16 Client Service Service Availability Filtering Client Service Service Round Robin Client Service 0.7 Service 0.3 Weighted Response Time Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 17.
    Circuit Breaker 2019-07-04 /Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 17 Execute Command Run Fallback Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 18.
    Bulkhead 2019-07-04 / JavaForum Stuttgart / Baris Cubukcuoglu & Fabian Keller 18 Thread pool Service X Service Z Resource Call Resource Call Resource Call DB Y Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 19.
    Bulkhead 2019-07-04 / JavaForum Stuttgart / Baris Cubukcuoglu & Fabian Keller 19 Service X Service Z Resource Call Resource Call Resource Call DB Y Pool X Pool Y Pool Z Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 20.
    API Gateway 2019-07-04 /Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 20 Client Resource Resource Resource Resource Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 21.
    API Gateway 2019-07-04 /Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 21 Client Resource Resource Resource Resource API Gateway Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 22.
    2019-07-04 / JavaForum Stuttgart / Baris Cubukcuoglu & Fabian Keller 22 The Modern Cloud Stack Photo by Pero Kalimero on Unsplash
  • 23.
    Where do webegin with? A homogeneous microservice landscape, yeah right… 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 23 Netflix OSS Netflix OSS Netflix OSS Netflix OSS Netflix OSS Netflix OSS Netflix OSS Netflix OSS ?!
  • 24.
    So how dowe solve all these challenges? Using sidecars instead of libraries 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 24 Application Layer Cross-cutting concerns Infrastructure Layer Cross-cutting concerns Application Netflix OSS Application Egress Ingress
  • 25.
    Egress Ingress Egress Ingress Egress Ingress Egress Ingress Egress Ingress Egress Ingress Egress Ingress Egress Ingress Adding the sidecarsto all containers We can have the exact same architecture as before 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 25
  • 26.
    2019-07-04 / JavaForum Stuttgart / Baris Cubukcuoglu & Fabian Keller 26 Photo by Erdenebayar Bayansan on Pixabay
  • 27.
    Cloud Foundry What isCloud Foundry? 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 27 Open Source Faster to iterate Scalable platform cf push -p target/spring-music.jar
  • 28.
    Container Network Cloud FoundryService Discovery a.k.a. Container Networking. Also enables client-side load balancing via DNS 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 28 moments.apps.internal 10.254.40.156 media.apps.internal 10.254.40.148 media.apps.internal 10.254.40.123 media.apps.internal 10.254.40.42 myapp.com 10.254.40.156 moments.apps.internal 10.254.40.148 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config DNS? moments.apps.internal A 10.254.40.148 A 10.254.40.156
  • 29.
    Cloud Foundry ServiceDiscovery How to setup CF container network 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 29 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 30.
    Cloud Foundry RouteServices Taking care of ingress traffic 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 30 Cloud Foundry CF Router App Load Balancr Client Route Service Service Broker • Security • Rate Limiting • Caching • Tracing Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 31.
    Cloud Foundry DynamicApp Config 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 31 CF SET-ENV CF RESTART Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 32.
    2019-07-04 / JavaForum Stuttgart / Baris Cubukcuoglu & Fabian Keller 32 Kubernetes Istio Photo by Bobby Burch on Unsplash
  • 33.
    Kubernetes Service Discovery Deploymentsand Services 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 33 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config Environment moments 172.10.40.156 media 172.10. 40.148 media 172.10.40.123 media 172.10.40.42 Cluster IP 10.254.40.156 moments 172.10.40.148 DNS? moments A 10.254.40.148
  • 34.
    Kind: k8s/DeploymentKind: k8s/Service moments.my-namespace.svc.cluster.local 10.98.61.186 KubernetesService Discovery Exposing a service 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 34 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config new RestTemplate().exchange(„http://moments/api/v1/timeline“, …) Pod 1 moments-pod172.10.40.148 Pod 2 moments-pod172.10.40.156
  • 35.
    Istio Architecture Control Planeand Data Plane 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 35 Control Plane Data Plane Pilot Citadel Mixer Pod 1 Envoy App 1 Pod 2 Envoy App 2
  • 36.
    Istio VirtualService Adding aVirtualService layer to intelligently route traffic 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 36 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config Kind: k8s/DeploymentKind: k8s/Service moments-v1 10.98.61.186 Pod 1 moments-v1-pod Pod 2 moments-v1-pod Kind: istio/VirtualService moments Match routing rules: /api/v1 à moments-v1 /api/v2 à moments-v2 Kind: k8s/Deployment Pod 1 moments-v2-pod Kind: k8s/Service moments-v2 10.98.61.193
  • 37.
    Istio Destination Rules Destinationrules apply after routing rules are evaluated Apply various policies to traffic: • Load Balancer Policy (RR, Random) • Client TLS • Circuit Breaker 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 37 Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 38.
    K8s/Istio Dynamic AppConfig 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 38 VIM KUBE-APP.YAML KUBECTL APPLY Service Discovery Load Balancing Circuit Breaker API Gateway Dynamic Config
  • 39.
    Istio Additional Features Thiswas just the beginning… • Automatic Retries • Rate Limiting • mTLS • Policy Enforcement • Observability & Monitoring • Distributed Tracing • Fault Injection 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 39
  • 40.
    Platform Support Service DiscoveryEureka Container Networking Kubernetes Services Load Balancing Ribbon Container Networking Kubernetes Services Circuit Breaker Hystrix / Turbine – Istio Destination Rule API Gateway Zuul Route Services Canary Deployments Istio Virtual Service Istio Gateway Dynamic Config Archaius cf set-env cf restart vim kube-app.yaml kubectl apply 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 40
  • 41.
    Limitations There is alwaysa flipside • We‘re now hiring for a full-time YAML engineer • Sometimes infrastructure shouldn‘t take care (e.g. retries) • Yet another markup language stack to learn • People will start to write microservices in other languages 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller 41
  • 42.
    Thanks! kubectl apply –fquestions.yaml Come visit our booth! 2019-07-04 / Java Forum Stuttgart / Baris Cubukcuoglu & Fabian Keller Photo by Ajeet Mestry on Unsplash