3 Ağustos 2021 Salı

Forgot Password Flow

Giriş
Akış şöyle
1. Users enter email in the UI
2. Creating password reset token and storing it in DB
3. Sending token to the user and verifying it when used

1. Users enter email in the UI
Açıklaması şöyle
This is how users will begin the process of updating their password. There's usually a simple form available that lets them enter the email address associated with their account.

When they submit the email address, this will trigger the back-end to check if that email exists in the database. Even if the email doesn't exist, we'll show a message that says the email has been sent successfully. That way we don't give attackers any indication that they should try a different email address.

If the email does exist in the database, then we create a new password reset token, store its hashed version in the database, and generate a password reset link that's sent to the user's email address.
2. Store the Token in the Database
Açıklaması şöyle
After the token has been created, it's hashed using SHA256 and stored in the database along with the user’s ID and it's assigned an expiration time. That way the token is only valid for a set amount of time, blocking attacks that could happen if the token never expired. 
Veri tabanı tablosu şöyledir
CREATE TABLE password_reset_tokens (    
    user_id VARCHAR(36) NOT NULL,    
    token VARCHAR(128) NOT NULL UNIQUE,    
    token_expiry BIGINT UNSIGNED NOT     NULL,    
    PRIMARY KEY (user_id, token),
); 
Açıklaması şöyle
If you notice, we allow multiple tokens to be stored per user. This is necessary since we only store the hashed version of the tokens in the DB. This means that if a user requests multiple tokens at the same time, we cannot send them the same previously generated token (which is not yet redeemed) since it’s stored in hashed form.

In the end, we want to generate a password reset link which points to a link on your website that displays the “enter new password” form and also contains the token.
Kullanıcıya e-posta ile gönderilen link şöyle
https://example.com/reset-password?token=<Token here>
3. Sending token to the user and verifying it when used
Burada token ve yeni şifre birlikte gönderiliyor.
1. Önce token var mı kontrolü
2. Token bayat mı kontrolü
3. Token silinir
4. Yeni şifre kaydedilir


Redis - RedisTimeSeries

Giriş
Açıklaması şöyle
RedisTimeSeries is a Redis Module that brings native Time Series data structure to Redis. Time Series solutions which were earlier built on top of Sorted Sets (or Redis Streams) can benefit from RedisTimeSeries features such as high volume inserts, low latency reads, flexible query language, down-sampling and much more!
TS.ADD
Örnek
Şöyle yaparız
# temperature for device 2 in location 3 along with labels
TS.ADD temp:3:2 * 20 LABELS metric temp location 3 device 2 # pressure for device 2 in location 3 TS.ADD pressure:3:2 * 60 LABELS metric pressure location 3 device 2`
TS.GET
Örnek
Şöyle yaparız
# pressure in device 5 for location 1
TS.GET pressure:1:5

# temperature in device 5 for location 4
TS.GET temp:4:5
TS.MRANGE
Ortalamayı gösterir
Örnek
Açıklaması şöyle
Extract temp and pressure for all devices in one or more locations within a specific time range:
Şöyle yaparız
TS.MRANGE - + WITHLABELS FILTER location=3
TS.MRANGE - + WITHLABELS FILTER location=(3,5)


2 Ağustos 2021 Pazartesi

Redis - Geospatial Indexes

Giriş
Açıklaması şöyle. Sorted Set Veri Yapısı yazısına bakabilirsiniz.
- Redis provides commands like GEOADD, GEORADIUS, GEORADIUSBYMEMBER, GEOSEARCH, and GEOSEARCHSTORE for geospatial indexing and searching.

- The spatial entities are stored in Sorted Sets using the coordinates to form 52-bit integers using the Geohash technique.
Açıklaması şöyle.
- Redis uses Haversine formula to calculate the distances as the model assumes that the Earth is a sphere. This can result in an error of up to 0.5%.

Valid longitudes range from -180 to 180 degrees, while valid latitudes range from -85.05112878 to 85.05112878 degrees.

GEOADD Komutu
Bir yeri eklemek için kullanılır
Örnek
Şöyle yaparız
> GEOADD places -122.419 37.774 “San Francisco”
> GEOADD places -122.143 37.441 “Palo Alto”
> GEOADD places -122.083 37.386 “Mountain View”
> GEOADD places -121.886 37.338 “San Jose”
GEORADIUS Komutu - Arama İçindir
Açıklaması şöyle
To perform a spatial search of entities GEORADIUS or GEORADIUSBYMEMBER can be used in Redis 3.2.0 (and above) and GEOSEARCH or GEOSEARCHSTORE can be used in Redis 6.2 (and above).

The time complexity for these commands is approximately O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius, and M is the number of items inside the index.
Örnek
Şöyle yaparız
> GEORADIUS places -122.228 37.484 50 mi COUNT 1 ASC WITHCOORD WITHDIST
1) 1) "Palo Alto" 2) "5.5294" 3) 1) "-122.14300006628036499" 2) "37.4410011922460555"
GEORADIUSBYMEMBER Komutu - Arama İçindir
Örnek
Şöyle yaparız
> GEORADIUSBYMEMBER places "Mountain View" 20 mi WITHDIST
1) 1) "Mountain View"
   2) "0.0000"
2) 1) "Palo Alto"
   2) "5.0297"
3) 1) "San Jose"
   2) "11.3186"
Örnek
Şöyle yaparız
> GEORADIUSBYMEMBER places "Mountain View" 50 mi WITHDIST
1) 1) "San Francisco" 2) "32.5234" 2) 1) "Mountain View" 2) "0.0000" 3) 1) "Palo Alto" 2) "5.0297" 4) 1) "San Jose" 2) "11.3186"
ZCARD Komutu
Açıklaması şöyle.
Since these entities are stored in a sorted set, the ZCARD command would return the total count of spatial entities.
Örnek
Şöyle yaparız
> ZCARD places
(integer) 4
ZRANGE Komutu 
Tüm elemanları gösterir
Örnek
Şöyle yaparız.
> ZRANGE places 0 -1
1) "San Francisco"
2) "Mountain View"
3) "Palo Alto"
4) "San Jose"

Redis Serializers

JSON Serializer
Veriyi JSON olarak saklamak iyi bir fikir değil. Açıklaması şöyle
Using JSON to store data in Redis will increase your latency and resource usage without bringing any real benefit.
Bazı sebepler şöyle
- JSON serialization/deserialization is incredibly inefficient and costly
- You end up using more space in storage (which is expensive in Redis since it’s an in-memory database)
- You increase your overall service latency without any real benefit
MsgPack

Sıkıştırma

Redis Sentinel Mode - Sadece Master Düğümün Replica'ları Var

Giriş
Sentinel ve Clustter mod farklı şeyler. Açıklaması şöyle. 
The sentinels are different concept than Redis cluster. If the primary dies then sentinels talk to each other to decide new primary.
Sentinel Nedir?
Açıklaması şöyle
It’s a solution that makes it easier to manage Redis instances. Since Redis 2.8, a stable release of Redis Sentinel has been available. Sentinel is a separate application that runs in the background. It will monitor your master and slave instances, alert you to any changes, manage automated failover in the event of a master failure, and perform as a configuration provider.
Şeklen şöyle

Sentinel'ler bir araya gelerek yeni Replica Set için Master'ı seçer. Açıklaması şöyle. 
Redis nodes can be interconnected by means of asynchronous replication. We’ll call such nodes a replica set. It is Redis Sentinel that manages the replica set. Redis Sentinel is one special process or several of them clustered, to monitor Redis nodes. They perform 4 primary tasks:

- Checking node status within the group - dead or alive.

- Notifying the system administrator if something goes wrong within the group.

- Automatic switching of the master.

- Config provider for external clients for them to know where to connect.
Yani 3 tane önemli görev var. Bunlar
1. Monitoring
2. Automatic failover
3. Configuration provider

Redis Primary-Secondary (Replica) Network with Sentinel without Sharding
Açıklaması şöyle. Bu modda veri dağıtılmıyor. Sadece master düğümün replica'ları var.
In scenarios where you don’t need sharding and one node is enough for your in-memory needs, you can avoid creating clusters and build primary-secondary replicas by specifying the replicaof in the replica configurations for the Redis node.

If we’re not using Redis clusters then we need sentinels to achieve failovers.
Master ve Replica şeklen şöyle
İyi ve kötü yanları şöyle
Redis Sentinel Pros:
- With three nodes, you can build up a fully functional Sentinel deployment. (Image 2)
- Simplicity - it’s usually simple to maintain and configure.
- Highly available, you can build a Redis Sentinel deployment that can survive certain failures without any need for human intervention.
- Work as long as a single master instance is available; it can survive the failure of all slave instances.
- Multiple slave nodes can replicate data from a master node.

Redis Sentinel Cons:
- Not scalable; writes must go to the master, cannot solve the problem of read-write separation.
- Slaves may serve reads, but because of asynchronous replication, outdated reads may result.
- It doesn’t shard data, so master and slave utilization will be imbalanced.
- The slave node is a waste of resources because it does not serve as a backup node.
- Redis-Sentinel must be supported by the client. The client holds half of the magic.

Sentinel Sayısı ve Quorum
Açıklaması şöyle. En az 3 sentinel kullanılır. Quorum sayısı sentinel sayısından az olabilir.
Sentinel documentation states that at least three sentinel instances are required for robust deployment. Although they can run as parallel processes in the same Redis instance, they should be placed into servers or VMs that are believed to fail independently.

Sentinel constantly checks the master for a failure. If enough sentinel agrees that the master is down then it acts as an authority and will start a failover process. As a result, it will promote a replica to be the master, configure other replicas to use new master until the master node is reachable again.

Sentinel agreement depends on the quorum value. Quorum value is the minimum number of the sentinels agree that the master is not reachable now. For 3 sentinel instances, the usual quorum value is 2.
Açıklaması şöyle
Quorum is configurable which only refers to the number of sentinels who must agree when a master is down. When in a failover scenario, sentinel instances attempt to reach a consensus, and at least three (odd number) sentinel instances will prevent most problems. These three Sentinel instances should also be placed on separate physical servers or Virtual Machines, as they are expected to fail in independent ways. 
Sentineller şeklen şöyle


Bağlantı
Açıklaması şöyle. Sentinel'ler kendi aralarında konuşmak için 26379 numaralı portu kullanır
The default port for Sentinel is 26379, so for sentinel instance to work, port 26379 of your servers must be open to receive connections from the IP addresses of the other sentinel instances. Otherwise, these instances can’t talk and agree about what to do, so failover will never be performed.
Bağlantı Timeout
Açıklaması şöyle.
You can configure the time required to check the master is down or not. Find down-after-milliseconds command which is the time in milliseconds to an instance should not be reachable for a Sentinel starting to think it is down. The default value is 30000 ms and you can change it as you like.

sentinel down-after-milliseconds mymaster 10000
Down Kavramı
Açıklaması şöyle.
Sentinel has two concepts of being down. Subjectively Down (SDOWN) condition is the local sentinel instance node thinks that Master is down. Objectively Down (ODOWN) condition is if enough instances (when quorum met) agree that the Master is not reachable.

Configure Sentinel to observe the Master with a specified quorum number.
# sentinel monitor <master-group-name> <ip> <port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2
Çalıştırma
Şöyle yaparız
redis-sentinel /path/to/redis-sentinel*.conf

1 Ağustos 2021 Pazar

HLA Engine

Giriş
Bu yazıda bir HLA Engine tasarımının özeti var. Tasarımı ben yapmadım. Sadece gördüklerimi not almak istedim.

Finite State Machine
Engine aslında bir Finite State Machine. Şu state'lerden oluşuyor.
1. BeginState
2. JoinSynchronizationState
3. LoadState
4. RunState
5. LeaveSynchronizationState
6. EndState
7. FailState

Eğer herhangi bir yerde hata olursa FailState'e geçilir.

Slave Engine İçin State Geçişi
BeginState -> otomatik olarak JoinSynchronizationState -> 
LoadState -> RunState -> LeaveSynchronizationState -> EndState

Commander Engine İçin State Geçişi
BeginState -> GUI'den loadScenario olunca JoinSynchronizationState -> 
LoadState -> RunState -> LeaveSynchronizationState -> EndState

Tüm engine'ler JoinSynchronizationState içindeki aynı noktaya gelince hep aynı anda başlar.

HLA Management Commands
Engine içinde bir kuyruk bulunur ve kuyruğa benim ismine Management Command dediğim nesneler eklenir. Amaç HLA thread'i ile Engine thread'ini birbirinden bağımsız hale getirmektir.

Örneğin HLA SaveFederation emri gelince HLA thread'i bloke olmadan Engine thread'i save işlemini yerine getirir.

Örneğin HLA RestoreFederation emri gelince HLA thread'i bloke olmadan Engine thread'i restore işlemini yerine getirir.

Tüm engine'ler belli bir frame içinde çeşitli işleri yapıp en son TimeAdvanceGrant komutunu beklerler.

Data Reconstruction Layer
HLA verisini saklamak ve bu verinin geldiğini üst katmanlara bildirmek gerekir. Bunun için belki adına Data Reconstruction Layer diyebileceğimiz bir katman bulunur. Bu katman gelen veriyi deserialize edip event'lere çevirir.

Bu katman da iki tane kuyruk bulunur
1. Engine Thread kuyruğu
2. HLA Thread Kuyruğu

Aslında daha kolay anlamak için iki tane federe düşünelim. Birinci federe viewer olsun. İkinci federe ise bir araba olsun. Her iki federe için time frame 0 olsun.

Birinci federe hemen time advance request yapar ve ben artık birinci frame'e geçmek istiyorum der.
İkinci federe arabanın yeni konumunu hesaplar ve birinci frame'de benim yeni konumum X der gönderir. Sonra time advance request yapar.

HLA her iki federeye de time advance granted gönderir ve birinci federeye X mesajını HLA thread'i üzerinden verir. Birinci federe bu mesajı HLA kuyruğuna ekler. Birinci federe Engine kuyruğu boş olduğu için hemen time advance request yapar.

İkinci federe yeni konumunu Y olarak hesaplar ve ikinci frame'deki konumum Y diye gönderir.

HLA her iki federeye de time advance granted gönderir ve birinci federeye Y mesajını HLA thread'i üzerinden verir. Birinci federe bu mesajı HLA kuyruğuna ekler. Birinci federe Engine kuyruğundaki  X mesajını işler hemen time advance request yapar.

Frame Başında
1. Her frame'in başında Engine Thread thread kuyruğunda bekleyen veri gerçek verinin üzerine yazılır. Daha sonra yeni veri hakkında ilgili observer'lara notificaiton gönderilir.

2. Kendi uygulamam tarafından veriyi değiştirmek üzere verilen asenkron komutlar işlenir ve yeni veri hakkında ilgili observer'lara notificaiton gönderilir.

Frame Sonunda
HLA kuyruğunda bekleyen nesneler Engine Thread kuyruğuna aktarılır. Örneğin benim frame sayım 1 olsun. İkinci frame'e geçmeden önce birinci frame'de HLA tarafından gönderilen tüm veriyi alır Engine kuyruğuna aktarırım. Bu nesneler ben ikinci frame'e başlarken işlenir.

Engine Tipleri
İki çeşit engine tipi var.
1. Commander Engine
2. Slave Engine

Commander engine synchronization point'leri yaratır ve tüm slave engine'lerin gelmesini bekler.

SynchronizationPoint
Basti bir CountDownLatch wrapper sınıfı yeterli. HLA tüm syncronization point'lere isim verdiği için wrapper sınıf isim bilgisi + CountDownLatch nesnesini saklar.

1. BeginState
Commander Engine şu çağrıları yapar.
1. rtiAmbassador.destroyFederationExecution()
 Tedbir amaçlı eğer eski federasyon varsa yok edilir.

2. rtiAmbassador.createFederationExecution()
 Yeni federasyon yaratılır

Bu state içinde Data Reconstruction Layer olaylarını işlemeye gerek yok.

2. JoinSynchronizationState

Yani bu state içinde belki Data Reconstruction Layer olaylarını işlemeye gerek olabilir.

Commander Engine şu çağrıları yapar.
2.1 rtiAmbassador.registerFederationSynchronizationPoint(pointName)
Burada 3 tane barrier kullanılır.
 - synchPointRegisteredBarrier
-  synchPointAnnouncedBarrier
- synchPointAchievedBarrier

 a. HLA synchronization point'i register etttim/yarattım deyinceya kadar synchPointRegisteredBarrier beklenir.
 b. HLA synchronization point'i anons ettim deyinceya kadar synchPointAnnouncedBarrier beklenir.
 c. rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır. HLA tüm katılımcıların bu çağrıyı yapmasını bekler. Tüm katılımcılar yaptıktan sonra HLA federateAmbassador.federationSynchronized() callback'ini çağırır. Bu çağrı da geldikten sonra synchPointAchievedBarrier barrier de indirilir ve LoadState'e geçilir.

Slave Engine şu çağrıları yapar.
Burada 3 tane barrier kullanılır.
-  synchPointAnnouncedBarrier
- synchPointAchievedBarrier

2.1

a. HLA synchronization point'i anons ettim deyinceye kadar synchPointAnnouncedBarrier beklenir.
b. rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır. HLA tüm katılımcıların bu çağrıyı yapmasını bekler. Tüm katılımcılar yaptıktan sonra HLA federateAmbassador.federationSynchronized() callback'ini çağırır. Bu çağrı da geldikten sonra synchPointAchievedBarrier barrier de indirilir ve LoadState'e geçilir.

3. LoadState
Bu state 3 frame boyunca çalışır.

Frame 1 
Commander engine paylaşmak istediği bilgileri paylaşır

Frame 2
Slave engine'ler bu bigileri okur ve işler

Frame 3
Tüm katılımcılar senaryoyu yüklerler. Senaryo ortak bir yerdeki dosya olabilir. Dosya okunur ve engine içinde her frame içinde çalışması gereken nesneler yaratılır.

Eğer senaryo bir engine tarafından dağıtılacaksa bu state içinde gelen HLA verisi deserialize edilir ve işlenir.

Yani bu state içinde belki Data Reconstruction Layer olaylarını işlemeye gerek olabilir.

4. RunState
Yani bu state içinde Data Reconstruction Layer olaylarını işlemeye gerek var.
Ayrıca bu state içinde HLA Management Commands olaylarını işlemeye gerek var.

rtiAmbassador.timeAdvanceRequest()
rtiAmbassador.setTimeToSent

Fixed Timestep Game Loop yazısına da bakılabilir.

5. LeaveSynchronizationState
Commander Engine şu çağrıları yapar.
rtiAmbassador.registerFederationSynchronizationPoint(pointName)
Burada
 1. HLA synchronization point'i yarattım deyinceya kadar beklenir.
 2. HLA synchronization point'i anons ettim deyinceya kadar beklenir.

3. rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır ve EndState'e geçilir.

Slave Engine şu çağrıları yapar.
1. HLA synchronization point'i anons ettim deyinceya kadar beklenir. Daha sonra
rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır ve EndState'e geçilir.

6. EndState
Her Engine şu çağrıları yapar.
rtiAmbassador.resignFederationExecution()
rtiAmbassador.destroyFederationExecution()

Redis Pub/Sub - Persistent Değildir Consumer Çalışmıyorsa Mesajı Alamaz

Giriş
Redis 5 ile geliyor. Redis Pub/Sub diğer broker'lardan - Kafka, RabbitMQ gibi - biraz daha farklı. Açıklaması şöyle
Redis is a bit different from the other message brokers. At its core, Redis is an in-memory data store that can be used as either a high-performance key-value store or as a message broker. Another difference is that Redis has no persistency but rather dumps its memory into a Disk/DB. It’s also perfect for real-time data processing.
No persistency şu demek. Yani consumer çalışmıyorsa mesajı alamaz. Her şey volatile.
... but note that there is no concept of message persistence i.e. if a consumer app is not up and running, it does not get those messages when it comes back on later
Pub/Sub Alternatifleri
1. Redis List Veri Yapısı kullanılabilir
2. Redis Streams kullanılabilir.