Elasticsearch’ün Mimari Yapısı
“A world where everyone creates content gets confusing pretty quickly without a good search engine” — Ethan Zuckerman
Bir önceki yazımda Elastic Stack ürünlerini inceleyip hangi durumlar için avantajlı olduklarını açıklamıştım. ELK Stack teknolojilerinin verilerin saklanması, analiz edilmesi, bir sonucu ifade ederek görselleştirilmesi gibi durumlar için birçok şirket tarafından kullanıldığına değinmiştim. Peki Elastic Stack’ın bir parçası olan Elasticsearch tam olarak nedir? Dağıtık (distributed) ve kolay ölçeklenebilir (scalable) yapısı ne gibi avantajlar sağlar?
Herkese merhaba. Bu yazımda Elasticsearch’ün ne olduğuna ve nasıl kullanıldığına değineceğim. Keyifli okumalar :)
Konular
- Elasticsearch (Distributed Search and Analyze Engine)
- Elasticsearch & Search Experience
- Elasticsearch ve Uygulama Bağlantısı
- Elasticsearch Mimari Yapısı (Nodes, Cluster, Documents, Index, Shards and Sharding)
- Shard’lar İle Search
- Primary Shards, Replica Shards
- Replica Shards ve Search Performansı
Elasticsearch (Distributed Search and Analyze Engine)
Elasticsearch Java programlama dilinde yazılmış, dağıtık mimariye (distributed) sahip açık kaynak kodlu bir projedir. Shay Banon, Elasticsearch’ün ilk versiyonunu 2010 yılında piyasaya sürmüştür. Shay, Elasticsearch’ü oluştururken Lucene adlı Java tabanlı metin arama kütüphanesinden yararlanmış ve onu dağıtık ve ölçeklenebilir (scalable) bir arama ve analiz motoruna dönüştürmüştür.
Elasticsearch & Search Experience
Speed and Relevance of Search & Fast and Relevant Results
Elastic Stack ürünlerinin ve özellikle Elasticsearch’ün use case’lerinden bir önceki yazımda detaylı örneklerle bahsetmiştim. Hatırlatma amacıyla burada yine bir örnek üzerinden ilerlemek istiyorum. Mobil ve web tabanlı online market alışverişi uygulamasının geliştirildiği bir ekip içerisinde yer aldığımızı düşünelim. Böyle bir uygulama için markaya, kategoriye veya isme göre ürün arama işlemi çok sık kullanılacaktır. Bu durumda bussiness kapsamında müşteri memnuniyetinin sağlanabilmesi için search experience oldukça önemli hale gelir. Bunun için de search işlemi sırasında ilgili ürünler (relevance) kısa süre içerisinde (speed) getirilmeli. Ayrıca müşteri satın almak veya incelemek istediği ürünler için arama yaptığı sırada birkaç karakteri yanlış girebilir. Bu durumda ‘Sonuç Bulunamadı’ gibi uyarı gösterilmesi yerine yine aranan metin ile en ilgili olan ürünlerin hızlı şekilde kullanıcıya gösterilmesi gerekir.
Milyonlarca satırdan oluşan verileri, Elasticsearch’e JSON formatında atarak milisaniyeler içerisinde ulaşabiliriz.
Belli Document’lerin index’lenmesi ve aranabilmesini kolaylaştıran bir yapıda olan Elasticsearch’te, üzerinde tutulan her Document bir JSON nesnesidir. Elasticsearch, index’leme mantığı olduğu için hızlı arama yapar.
Şimdi ise Elasticsearch’ün çalışma mantığına ve mimari yapısına bakalım.
Elasticsearch ve Uygulama Bağlantısı
- Kullanıcı client’ta ürün, kategori, marka veya herhangi bir data için arama yapmak istediğinde search request client’tan server’a iletilir,
- Server, gelen search request’i Elasticsearch’e gönderir,
- Elasticsearch istenen data’yı bulur ve server’a döner,
- Server ise gelen sonucu client’a gönderir ve istenen data kullanıcıya gösterilir.
Elasticsearch Mimari Yapısı
Elasticsearch’ün en önemli özelliklerinden ikisi için hızlı (fast) ve kolay ölçeklenebilir (easy-scalable) olması diyebiliriz. Bu da sahip olduğu mimari yapıdan dolayıdır. Burada bu mimari yapı için Elasticsearch bileşenlerini açıklamak istiyorum.
Nodes: Distributed yapılar için Node bir makina anlamına gelir. Bir bilgisayarda Elasticsearch’ü ayağa kaldırdığımızda (up and running) Elasticsearch için bir instance’ımız oluşur ve buna da Node denir. Her bir Node’un unique ID’si ve ismi vardır ve tek bir Cluster’a aittir. Bir Node oluşturulduğunda Cluster da otomatik olarak oluşur.
Cluster: Elasticsearch’te Cluster, Node’ların bir araya gelmesiyle oluşan bir kümedir. Bir başka deyişle, eğer Node’lar birbirleriyle haberleşebilir durumda aynı kümedeyse, bu kümeye cluster deriz.
Not: Bir Cluster içerisinde birden fazla Node olma zorunluluğu yokur, yalnızca bir Node da olabilir.
Burada da gözüktüğü gibi Node’lar ayrı server’lar üzerinde dağıtılır ve aynı Cluster içerisinde bir arada çalışır. Bu konunun daha iyi anlaşılabilmesi için bir örnek üzerinden ilerlemek istiyorum. Elimizde 800.000 adet Documents’ten oluşan bir veriseti olduğunu varsayalım. Bu veriyi yatay olarak, farklı serverlar’daki 4 Node üzerinde bölebiliriz. Böylece her Node 200.000 adet Document tutar. Bu durumda 4 adet Elasticsearch Node’umuz olur. Elasticsearch’ün distributed yapısı ile iş yükünü birden fazla server’a dağıtacağımız için, bu özellik sistemde önemli anlamda performans sağlar.
Documents: İlişkisel veri tabanlarındaki rows, Elasticsearch’te documents olarak temsil edilir.
Elasticsearch Document-oriented bir search engine’dir. Verileri JSON objects şeklinde Document’lerde tutarız. Bir Document, belirli bir index içinde saklanan bilgileri ifade eder. Her Document’in unique ID’si vardır. Document’ler, Elasticsearch üzerinde index’lenir ve arama, sorgulama ve analiz gibi işlemler için kullanılır.
- JSON object içerisinde field’lar — key-value pairs belirtilir.
- Document’ler esnek yapıya sahiptir. Bir Document’te olan bir property diğer Document’te olmayabilir.
- Bir Document, bir veya daha fazla property (field) içerir ve belirli Index içinde tutulur.
Online market uygulamamızdaki 2 farklı ürün için Document’ler:
{
name: "Carrots",
category: "Vegetables",
brand: "365",
price: "$0.99"
}
{
name: "Yorkshire Tea Teabags",
category: "Tea",
brand: "Yorkshire",
price: "$6.99",
ingredients: "Black Tea"
}
Index: Elasticsearch’te Index, Document’lerin gruplandırıldığı ve saklandığı data-collection’ı ifade eder. Benzer özelliklere sahip, aynı gruba ait olması gereken Document’leri aynı Index içerisinde depolarız.
Produce Index:
{
name: "Carrots",
category: "Vegetables",
brand: "365",
price: "$0.99",
},
{
name: "Strawberries",
category: "Fruits",
brand: "Cuties",
price: "$4.29",
},
{
name: "Grapes",
category: "Fruits",
brand: "Cuties",
price: "$2.19",
}
Hot-Drinks Index
{
name: "Yorkshire Tea Teabags",
category: "Tea",
brand: "Yorkshire",
price: "$6.99",
ingredients: "Black Tea"
},
{
name: "Littles Rich Hazelnut Nespresso",
category: "Coffee",
brand: "Littles",
price: "$3.89",
ingredients: "Rich Hazelnut Flavouring"
},
{
name: "Galaxy Ultimate Frothy Hot Chocolate",
category: "Hot Chcocalate",
brand: "Galaxy",
price: "$2.50",
ingredients: "Lactose"
}
Shards — Sharding:
Elasticsearch’te Sharding aslında bir data partitioning yöntemidir. Data’yı yatayda parçalara ayırdığımızda her bir parçaya Shard deriz. Elasticsearch üzerinde 600.000 adet Document’ten oluşan verimiz olduğunu varsayalım. Bu datayı her biri 200.000 adet Document tutacak şekilde yatayda 3 parçaya böldüğümüzde 3 adet Shard’ımız olur.
Shard’lar, Elasticsearch Cluster’ındaki Node’lara atanır ve yükü dağıtmak için kullanılır. Bir Index oluşturulurken, kullanıcı tarafından belirtilen Shard sayısına göre Index, Shard’lara bölünür ve bu Shard’lar Node’lar arasında dağıtılır.
Burada yine bir örnek üzerinden ilerlemek istiyorum. 3 Node’dan oluşan Cluster’ımız olduğunu varsayalım.
Elasticsearch’te Shard, verilerin depolandığı ve arama işlemlerinin (search) gerçekleştirildiği birimdir.
Elasticsearch’te Index tam anlamıyla Document’lerin depolandığı birim değildir. Index yalnızca Document’lerin nerede depolandığını takip eden sanal bir yapıdır. Yani Index verileri bir dosya olarak doğrudan diskte saklanmaz, onun yerine veriler Shard’lara bölünerek diskte depolanır.
Buradaki resim örneği üzerinden ilerleyelim. Bu şekilde bir Cluster yapımız var. Produce Document’ler için “Produce Index” isimli index’imizi oluşturduk.
Shard’ların, Document’lerin parçalara bölünerek saklandığı birimler olduğunu ve bir Shard’ın tutabileceği Document sayısının Node’un kapasitesine bağlı olduğunu hatırlayalım.
Örneğin Produce Index içerisinde 600.000 adet Document’imiz mevcut. Fakat Shard’ın tutulduğu Node sadece 200.000 adet Document store edebilecek kapasiteye sahip. Bu durumda her biri 200.000 adet Document tutacak 2 ilave Shard oluşturup, Node’lar üzerinde dağıtabiliriz.
Bu durumda Produce Index için her biri 200.000 adet Document tutan 3 farklı shard oluşturduk (P0, P1 ve P2). Bu Shard’ları da Cluster içerisindeki 3 Node üzerinde dağıttık. Örnek resimde gözüktüğü gibi aynı yapıyı diğer Index’ler için de kurabiliriz.
Uygulama için yeni ürünler eklendikçe Produce Index’in içerdiği data büyüyecektir. Verimiz genişleyip Document’ler arttıkça, daha fazla Shard ekleyip ölçeklendirme yöntemiyle Shard’ları Node’lar üzerinde dağıtırız.
Shard’lar İle Search
Elasticsearch’te uygulama için yüksek trafik anında sisteme yeni makineler ekleyerek ölçeklendirme (scaling) işlemini gerçekleştiririz. Sharding yöntemi ile ayırdığımız veri parçalarını farklı Node’lar üzerinde dağıtarak sistem için hızı ve performansı arttırabiliriz.
Yani Shard’lar, Elasticsearch’in yüksek performans ve ölçeklenebilirlik sağlamasına, veri dağıtımının yönetilmesine ve yükün dengelenmesine yardımcı olur.
Burada ise Elasticsearch’te Sharding yöntemi ile search işleminin nasıl gerçekleştiğini açıklamak istiyorum.
Senaryo 1: Single Shard
Örneğin kullanıcı Carrots ürünü için search request’te bulundu. Uygulama için Produce Index’de 500.000 adet Document mevcut. Bütün datanın tek bir Shard ile bir Node üzerinde tutulduğu senaryoyu düşünelim.
Bu durumda search işlemi bütün Produce Index datası’nın bulunduğu tek Shard üzerinde gerçekleştirilir. 500.000 adet Document tek Shard üzerinde sırayla taranır. Bu senaryoda Index’in taranıp Carrots ürününün bulunması için geçen sürenin 10 saniye olduğunu varsayalım ve diğer senaryoyu inceleyelim.
Senaryo 2: Multiple Shards
Bir Index üzerinde yapılan sorgular, Shard’lar arasında paralel olarak dağıtılarak hızlı yanıtlar elde edilir.
Produce Index’te 500.000 adet Document’ten oluşan verimiz var. Bu Document’leri 10 Shard ile aynı Cluster içerisindeki 10 Node üzerinde dağıttığımızı varsayalım. Yani her bir Node, 50.000 Document’ten oluşan data’yı tutuyor.
Bir önceki senaryoda tek bir Shard üzerinde 500.000 adet Document’in taranıp istenilen ürünün bulunması için geçen sürenin 10 saniye olduğundan bahsetmiştik.
Burada ise search işlemi 500.000 adet Document’in bulunduğu tek bir Shard yerine, 50.000 adet Document’in tutulduğu 10 Shard üzerinde gerçekleştirilir. Yani her bir Shard’da yalnızca 50.000 adet’lik Document için tarama işlemi yapılacak.
Bu durumda 500.000 adet Document için 10 saniyede arama işlemi yapılırken, 50.000 adet Document için sadece 1 saniyede arama işlemi sağlanır. Ayrıca, Shard’lar üzerinde eş zamanlı olarak search işlemi yürütülebilir ve nihayetinde 500.000 adet Document için 10 değil yalnızca 1 saniyede arama işlemi gerçekleştirilir.
Primary Shards — Replica Shards
Bir önceki başlıkta ‘Single Shard’ ve ‘Multiple Shards’ ile searching senaryolarını inceledik.
Single Shard kullanılan durumda bütün data’nın tek Node üzerinde tutulup gelen search request’lerin tek server’da işlendiğini ve bu yöntemin zaman — performans açısından dezavantajlı olduğunu anladık.
Multiple Shards kullanılan durumda ise uygulama içindeki data’nın Shard’lar ile farklı Node’lar üzerinde dağıtılıp gelen search request’lerin paralel şekilde işlenerek daha kısa sürede çalışmasını gördük.
Burada da Primary Shards ve Replica Shards kavramlarını inceleyelim.
Online market uygulamamız için herhangi bir sebepten dolayı mevcut Node’lardan birinin çöktüğünü düşünelim. Bu senaryoda o Node’da tutulan data’yı tamamen kaybederiz ve bu durum ürün yönetimi ve müşteri memnuniyeti açısından çok kötü sonuçlara yol açabilir.
Bu problemin önüne geçmek için Primary Shards olarak bilinen Original Shards’ların kopyasını alırız ve o kopyaları farklı Node’lar üzerinde dağıtırız.
Buradaki örnekte Node’ları inceleyelim. Node-1 ve Node-2'de Primary Shard’lar(P0, P1 / P = Primary Shard) tutuluyor. P0 ve P1 Shard’larında tutulan data’yı yedeklemek için o Shard’ların kopyalarını alırız. Ardından o kopyaları da Node-3 ve Node-4 üzerinde (R0, R1 / R = Replica Shard) saklarız.
- R0 = P0 Shard’ının Replica’sı
- R1 = P1 Shard’ının Replica’sı
Bu durumda herhangi bir Node çökerse uygulamadaki veri akışı Replica Shard’lar ile başarılı şekilde sağlanmaya devam eder.
Replica Shards ve Search Performansı
Replica Shard’ların sağladığı bir diğer avantajı da şu şekilde açıklayabilirim:
Uygulama popüler hale geldikçe daha sık kullanılır ve gelen search request’ler artmaya başlar. Örneğin başlangıçta 2 Node üzerinde 2 Primary Shard’ımızın olduğunu varsayalım.
Mevcut durumda saniyede 2000 search request gerçekleşiyor. Fakat uygulama büyüdükçe gelen talepler de artmaya başlar ve saniyede örneğin 8000 search request’e ulaşabilir. Bu durumda 2 Primary Shards gelen talebi karşılamakta zorlanıp istenen data için response’u çok geç dönebilir. Bu sorunun önüne geçmek için Node’ları arttırıp Primary Shard’ların Replica’larını alırız.
Replica Shard’lar, Primary Shard’ların özdeşleridir, birebir kopyalarıdır. Search request’lerin arttığı durumda Replica Shard’lar eklenir ve yük dağıtılacağı için gelen arama sorguları Cluster içerisinde daha kolay ve hızlı şekilde işlenir.
Bu yazımda Elasticsearch kavramından bahsedip mimari yapısını açıkladım. Ayrıca distributed ve easy-scalable özelliği sayesinde search işlemlerinde doğru data’nın hızlı şekilde nasıl getirildiğine örnekler verdim. Bir sonraki yazımda ise Elasticsearch ve Kibana’nın local bilgisayarımızda kurulup çalıştırılması üzerinde duracağım. Görüşmek üzere :)