MVCC (Multi Version Concurrent Control), veri tabanına eşzamanlı erişim sağlamak için veritabanı yönetim sistemleri tarafından kullanılan eşzamanlılık kontrol yöntemidir, yani MVCC postgresql veri tabanında eş zamanlı olarak okuma ve yazma işlemlerinin sorunsuz yapılabilmesi adına geliştirilen bir modeldir. Aslında amaç basit veritabanında read yapanlar write yapanları engeleyemesin, yazma yapanlarda okuma yapanları engeleyemesin. Bu teknik Postgres’e özgü değildir Oracle, Berkeley DB, CouchDB vb veritabanları bir tür MVCC’yi uygularlar.
Eşzamanlılık kontrolü olmadan, bir transaction yazarken aynı anda başka bir transaction veriyi okursa, okuyucunun yarı yazılı veya tutarsız bir veri parçası görmesi mümkündür. Örneğin, iki banka hesabı arasında bir banka havalesi yaparken, bir okuyucu, para orijinal hesaptan çekildiğinde ve hedef hesaba yatırılmadan önce bankadaki total bakiyeyi okursa, paranın hesaptan kaybolduğunu düşünür.
İzolasyon, verilere eşzamanlı erişimlerde garantiler sağlayan özelliktir. İzolasyon, eşzamanlılık kontrol protokolü aracılığıyla gerçekleştirilir. İzolosyanu sağlamanın en basit yoluRead/Write locks, Two-Phase Locking gibi lock mekanizmalarıdır ancak lock contentiona(çekişme) neden olur ve contention ölçeklenebilirliği etkiler. Bu nedenle, veritabanı araştırmacıları, locklamayı minimuma indirmeye çalışan farklı bir Eşzamanlılık Kontrolü modeli geliştirdiler, böylece:
- Read yapanlar, write yapanları engellemez
- Write yapanlar read yapanları engellemez
NOT : Hala contention yaratabilecek tek kullanım durumu, iki eşzamanlı transactionın aynı kaydı değiştirmeye çalışmasıdır, çünkü bir kez değiştirildiğinde, bu kaydı değiştiren transaction commit edene veya rollback edene kadar bir satır her zaman locklanır.
MVCC, her veri öğesinin birden çok kopyasını tutarak sorunu çözmeyi amaçlamaktadır. Bu şekilde, veritabanına bağlı her kullanıcı belirli bir zamanda veritabanının anlık görüntüsünü görür. Bir insert tarafından yapılan herhangi bir değişiklik, değişiklikler tamamlanana kadar (commit olana kadar) veritabanının diğer kullanıcıları tarafından görülmeyecektir.
MVCC kullanılan veritabanında bir veri parçasının güncellemesi gerektiğinde, orijinal veri öğesinin üzerine yeni veriler yazmaz, bunun yerine veri öğesinin daha yeni bir sürümünü oluşturur. Bu nedenle saklanan birden fazla sürüm vardır. Her transactionın gördüğü sürüm, uygulanan izolasyon düzeyine bağlıdır. İzolasyon ile transaction, transactionın başladığı andaki gibi verilerin durumunu gözlemler. MVCC, zaman içinde tutarlı görünümler sağlar. MVCC altında, transactionlar DB’nin hangi durumunun okunacağını belirlemek ve verilerin bu sürümlerini okumak için bir zaman damgası veya transaction id’yi kullanır. Okuma ve yazma işlemleri böylece kilitlemeye gerek kalmadan birbirinden izole edilir. MVCC, eski hale gelen ve asla okunmayacak sürümlerin nasıl kaldırılacağına dair bir zorluk getiriyor. Bazı durumlarda, eski sürümleri periyodik olarak taramak ve silmek için bir işlem uygulanır. PostgreSQL, VACUUM süreciyle bu yaklaşımı benimser.
Yukarıdada yazdığım gibi Postgres MVCC’de kimin hangi sürümü göreceğini belirlemek için transaction id kullanır. Peki Transaction ID nedir dersek; Postgres’teki her transaction, TXID adlı bir transaction id değeri alır. Bir transaction başladığında, Postgres TXID’yi bir artırır ve bunu geçerli transactiona atar. TXID değeri postgres tarafından üretilen 32-bit integer özgün bir değerdir. Bilginin 32-bit olarak tutulmasından dolayı yaklaşık 4 milyar farklı değer üretilebilmektedir. Bu değer limitinin aşılması durumunda sistem 0’dan başlayarak yeniden ID üretmeye başlayacaktır, böyle olduğunda tüm satırların versiyonunun Transaction ID’den büyük olarak gözükmesi(in the future) tüm satırların görünürlülüğünü kaybettirir. Bu durum catastrophic veri kaybı olarak adlandırılır. Transaction ID maximum sayıya ulaşmadan önce vacuum çalıştırırsak sorun ortadan kalkmış olacaktır. Çünkü Transaction ID sıfırlanmış olup satırların versiyonları buna göre düzenlenmiş olacaktır.(Vacuumun sorunu çözmesinin nedeni, VACUUM’un satırları frozen olarak işaretlemesidir; bu, insert transactionın etkilerinin tüm mevcut ve gelecekteki transactionlarda görünür olacağının kesin olduğunu geçmişte commit edilmiş transaction tarafından eklendiğini belirtir.)
NOT : Transaction, tüm veritabanı sistemlerinin temel konseptidir. Bir transactionın temel noktası, birden çok adımı tek bir ya hep ya hiç işleminde bir araya getirmesidir
PostgreSQL tüm satır sürümlerini tablo veri yapısında depolar. Daha da ilginç olan, her satırda iki ek sütun olmasıdır; Yani Postgresql MVCC modeline göre her satır ekleme işlemi sırasında iki farklı bilgi daha kayıt altına alınmaktadır. Bu iki bilgi şu şekilde isimlendirilir;
- xmin — Insert Transaction ID bilgisi (kaydı ekleyen transaction id’yi tanımlar)
- xmax — Delete Transaction ID bilgisi (kaydı silen transaction id’yi tanımlar)
Bu bilgiler yapılan işleme ve işlem sırasında üretilen Transaction ID’sinin küçük veya büyük olması durumuna göre anlam kazanmaktadırlar. Örneğin, bir satır eklediğinizde postgres, TXID’yi satıra kaydeder ve ona xmin adını verir. Kaydedilmiş ve geçerli transactionın TXID’sinden daha küçük bir xmin değerine sahip her satır, transaction tarafından görülebilir. Bu transactionı başlatabileceğiniz ve bir satır ekleyebileceğiniz anlamına gelir ve bu COMMIT işlemine kadar bu satır diğer transactionlar tarafından görünmez. Commit ettikten ve diğer işlemler oluşturulduktan sonra, yeni satırı xmin <TXID koşulunu karşıladıkları ve satırı oluşturan transaction tamamlandığı için görüntüleyebilecekler.
DELETE and UPDATE için benzer bir mekanizma oluşur, yalnızca bu durumlarda Postgres görünürlüğü belirlemek için her satırda bir xmax değeri depolar.
Şimdi INSERT işlemi için aşağıdaki diyagrama bakacak olursak;
Session 1 | Session 2 |
select txid_current(); | select txid_current(); |
create table mvcc_demo(id int); | |
BEGIN WORK; INSERT INTO mvcc_demo VALUES (1); postgres=# SELECT xmin, xmax, * FROM mvcc_demo; xmin | xmax | id ——+——+—- 680 | 0 | 1 |
|
postgres=# SELECT xmin, xmax, * FROM mvcc_demo; xmin | xmax | id ——+——+—- (0 rows) |
|
COMMIT WORK; | |
postgres=# SELECT xmin, xmax, * FROM mvcc_demo; xmin | xmax | id ——+——+—- 680 | 0 | 1 (1 row) postgres=# select txid_current(); |
- Hem Alice hem de Bob yeni bir transaction başlatır ve txid_current () PostgreSQL fonksiyonunu çağırarak transaction id değerlerini görebiliriz.
- Alice’in post tablosuna yapmış olduğu insert işlemi ile beraber Alice’in Transaction ID’si satırın tmin bilgisine atanır.
- Varsayılan Read Committed izolasyon seviyesi altında, Bob, Alice işlemini gerçekleştirene kadar Alice’in yeni eklenen kaydını göremez.
- Alice’in işlemini commit etmesi ile beraber Bob kendi Transaction ID’sinin eklenen satırın tmin bilgisinden büyük olması sebebiyle bu satırı görebilecektir.
Şimdi DELETE işlemi için diyagrama bakacak olursak;
- Hem Alice hem de Bob yeni bir transaction başlatır ve txid_current () PostgreSQL fonksitonunu çağırarak txid lerini görebilirler.
- Bob bir satırını sildiğinde, x max sütun değeri Bob’ın txid değerine ayarlanır
- Varsayılan Read Committed izolasyon seviyesi altında, Bob kendi transactionını gerçekleştirene kadar Alice bob tarafından silinen kaydı görebilir.
- Bob commit verdikten sonra, Alice artık silinen satırı göremez
Son olarak UPDATE diyagramına bakalım;
- Hem Alice hem de Bob yeni bir transaction başlatır ve txid_current () PostgreSQL fonks,yonu çağırarak txid değerini görebiliriz.
- Bob bir kayıt kaydını güncellediğinde, iki işlemin gerçekleştiğini görebiliriz: bir DELETE ve bir INSERT.
- Önceki satır sürümü, x _max sütun değeri Bob’ın txid değerine ayarlanarak silinmiş olarak işaretlenir ve Bob’un x _min sütun değerinin ayarlandığı yeni bir satır sürümü oluşturulur.
- Varsayılan Read Committed izolasyon seviyesi altında, Bob transactionı gerçekleştirmeyi başarana kadar Alice önceki kayıt versiyonunu hala görebilir.
- Bob commit verdikten sonra, Alice artık Bob tarafından güncellenen yeni satır sürümünü görebilir
Mustafa Bektaş Tepe
İyi Çalışmalar
https://vladmihalcea.com/how-does-mvcc-multi-version-concurrency-control-work/
https://momjian.us/main/writings/pgsql/mvcc.pdf