MongoDB 6.0'dan 9.0'a ve C# Driver 2.x'ten 3.x'e: Sürüm Modeli, Yenilikler ve Geçiş Kontrol Listesi
MongoDB 6.0'dan 9.0'a doğrudan geçilemez; major sürümler sırayla kurulur ve her adımda feature compatibility version yükseltilir. C# driver 3.x'e geçişte asıl risk derleme hataları değil, 2.x'in string olarak yazdığı decimal'ler ve array olarak yazdığı DateTimeOffset'lerdir. Gerçek çıktılarla: 9.0'ın 6.0 verisiyle açılmaması, 7.0-8.0-9.0 adımları, aynı LINQ sorgusunun 2.30'da yanlış, 3.14'te sıfır sonuç vermesi ve veriyi taşıyan migration.
Sürüm notu: Bu yazıdaki örnekler MongoDB 6.0.30, 7.0.48, 8.0.38 ve 9.0.8 Community Server image'ları, .NET 10 ve MongoDB.Driver 2.30.0 ile 3.14.0 üzerinde çalıştırılmıştır. Driver örneği 9.0.8'e bağlanıyor; sunucunun sürümü driver davranışını değiştirmiyor.
Önce Tahmin Et
Bookstore'un (sitedeki serilerin ortak örnek uygulaması, bir online kitapçı) eski bir servisi yıllardır MongoDB.Driver 2.30 ile çalışıyor ve kitapları decimal fiyat ve DateTimeOffset tarih alanlarıyla yazmış. Repodaki samples/DriverUpgrade örneği aynı kodu iki driver'la derleyebiliyor: varsayılan 2.30.0, -p:MongoDriverVersion=3.14.0 ile 3.14. Üç kitap yazılıyor (390.50, 530.90 ve 1450.00) ve aynı LINQ (C#'ta sorguyu dilin içinde yazmayı sağlayan özellik) sorgusu iki driver'la çalışıyor:
IQueryable<PricedBook> cheap = books.AsQueryable().Where(b => b.ListPrice < 500m);
dotnet run --project samples/DriverUpgrade -- seed
dotnet run --project samples/DriverUpgrade -p:MongoDriverVersion=3.14.0
500 TL'nin altında tek kitap var, Dune. 2.30 kaç kitap döndürür, 3.14 kaç?
driver 2.30.0: bookstore.driver_upgrade.Aggregate([{ "$match" : { "ListPrice" : { "$lt" : "500" } } }])
driver 2.30.0: books under 500: Dune 390.50 (listed 2024-06-01 09:00 +03:00), The Art of Computer Programming 1450.00 (listed 2024-06-01 09:00 +03:00)
driver 2.30.0: stored types: ListPrice String, ListedAt Array
driver 3.14.0: bookstore.driver_upgrade.Aggregate([{ "$match" : { "ListPrice" : { "$lt" : { "$numberDecimal" : "500" } } } }])
driver 3.14.0: books under 500:
driver 3.14.0: stored types: ListPrice String, ListedAt Array
2.30 iki kitap döndürdü ve biri yanlış: 2.x decimal'i varsayılan olarak string yazıyordu, sorgu da "500" string'iyle karşılaştırdı; string sıralamasında "1450.00" "500"'den küçük. Bu hata yıllardır üretimde olabilir. 3.14 sıfır kitap döndürdü: artık 500m Decimal128 olarak gidiyor ve BSON'da (MongoDB'nin ikili document formatı) string ile sayı karşılaştırılmıyor. Driver'ı yükseltmek sorguyu "düzeltti", ama veri hâlâ eski biçimde olduğu için ekranda hiç kitap yok. Bu son yazıda iki yükseltmeyi birlikte ele alıyoruz: MongoDB'nin sürüm modeli ve 6.0'dan 9.0'a yükseltme yolu, ardından C# driver 2.x'ten 3.x'e geçiş ve bir kontrol listesi.
Sürüm Modeli: Major, Minor ve Feature Update
Sürüm numarası X.Y.Z: X major (geriye dönük uyumsuz değişiklikler ve eski sürümlerin okuyamadığı veri biçimleri getirebilir), Y minor, Z patch. Major sürümler yılda bir geliyor: 7.0 Ağustos 2023, 8.0 Ekim 2024, 9.0 Eylül 2026. Minor sürümlerin hikâyesi değişti. 8.2 ile minor sürümler self-managed Community ve Enterprise'a da açıldı; 9.0'dan itibaren minor sürümler yalnız Auto Upgrades açık Atlas cluster'larına geliyor. Self-managed kurulumlar için yılda bir x.5 numaralı Feature Update sürümü var; major sürümle aynı destek süresini taşıyor. Yani self-managed bir Bookstore 9.0 → 9.5 → 10.0 diye ilerleyecek. Destek takvimi de bunu izliyor: 6.0'ın desteği 31 Temmuz 2025'te bitti, 7.0'ınki 31 Ağustos 2027'de, 8.0'ınki 31 Ekim 2029'da, 9.0'ınki 31 Ekim 2031'de bitiyor. 6.0'da kalan bir sistem bugün güvenlik yaması almıyor.
6.0'dan 9.0'a Neler Değişti?
| Sürüm | Bu seride karşılığı olan değişiklikler |
|---|---|
| 7.0 | Queryable Encryption eşitlik sorguları GA (genel kullanıma açık), compound wildcard index |
| 8.0 | Release notes'a göre %36'ya varan okuma throughput artışı, client-level bulkWrite (10. yazı), Queryable Encryption range sorguları |
| 8.2 | Minor sürümlerin self-managed'a açılması, Queryable Encryption prefix/suffix/substring public preview |
| 9.0 | constraint validation level (5. yazı), sorgu başına bellek sınırı (8. yazı), açık transaction sınırı (12. yazı), varsayılan açık $queryStats (14. yazı), deprecation'ı kaldırılan server-side JavaScript (8. yazı), queryKnobs, prefix/suffix/substring GA ve mongocryptd'nin deprecated olması (14. yazı) |
9.0'da tabloya sığmayan bir değişiklik daha var: time series collection'lar artık sıkıştırılmış bucket'lardan oluşan tek bir namespace olarak saklanıyor, yazılabilir bir view değiller. 5. yazıdaki görüntülenme sayaçlarını time series collection'a taşımayı düşünüyorsan 9.0 ile başla. 9.0'ın bilinen sorunlar listesindeki SERVER-89953 kaydını (feature compatibility version 9.0'da listIndexes'in basit collation'lı index'ler için collation: { locale: "simple" } raporlaması ve bazı ODM'lerin (Object-Document Mapper; document'leri nesnelere eşleyen kütüphane) bu yüzden index'leri her açılışta yeniden kurması) 6. yazıdan beri izliyorum; 9.0.8'de, 6.0'dan yükseltilmiş bir index'te de, feature compatibility version 9.0'a çıktıktan sonra bu alanı göremedim (aşağıdaki çıktılarda title_1). Release notes onu hâlâ açık sorun olarak listeliyor; ODM kullanıyorsan yükseltme sonrasında index'lerin yeniden kurulup kurulmadığını log'dan kontrol et.
Yükseltme Yolu: Sırayla ve FCV ile
Bir major sürümden yalnız bir sonrakine geçilebiliyor; 9.0'ın yükseltme sayfası 8.0 ya da 8.3 şartı koyuyor, daha eskisi için önce 8.0'a kadar sırayla çıkmak gerekiyor. Binary'yi değiştirmek ile yeni sürümün veri biçimlerini açmak ayrı adımlar: ikincisi FCV (Feature Compatibility Version; sunucunun hangi sürümün veri biçimleriyle çalışacağını belirleyen ayar). FCV eski sürümde kaldıkça bir önceki binary'ye dönmek mümkün. Lab'da bir volume'u 6.0 ile kurdum, Bookstore'un kitaplarını ve bir index'i yükledim, sonra aynı volume'u doğrudan 9.0 ile açmayı denedim:
docker volume create bookstore-upgrade
docker run -d --name bookstore-upgrade -v bookstore-upgrade:/data/db -v "${PWD}\data:/lab/data:ro" -v "${PWD}\scripts:/lab/scripts:ro" mongodb/mongodb-community-server:6.0-ubuntu2204
docker exec bookstore-upgrade mongoimport --db bookstore --collection books --file /lab/data/books.json --quiet
docker exec bookstore-upgrade mongosh --quiet --eval "db.getSiblingDB('bookstore').books.createIndex({ title: 1 })"
docker exec bookstore-upgrade mongosh --quiet /lab/scripts/15-check.js
docker stop bookstore-upgrade
docker rm bookstore-upgrade
version 6.0.30 | FCV 6.0 | books 77 | title_1: {"v":2,"key":{"title":1},"name":"title_1"}
{"t":{"$date":"2026-11-14T15:00:59.731+00:00"},"s":"F", "c":"CONTROL", "id":20573, "ctx":"initandlisten","msg":"Wrong mongod version","attr":{"error":"UPGRADE PROBLEM: Found an invalid featureCompatibilityVersion document (ERROR: Location4926900: Invalid featureCompatibilityVersion document in admin.system.version: { _id: \"featureCompatibilityVersion\", version: \"6.0\" }. See https://docs.mongodb.com/master/release-notes/8.0-compatibility/#feature-compatibility. :: caused by :: Invalid feature compatibility version value '6.0'. Expected one of the following versions: ''9.0', '8.3', '8.0'. See https://docs.mongodb.com/master/release-notes/8.0-compatibility/#feature-compatibility.). If the current featureCompatibilityVersion is below 8.0, see the documentation on upgrading at https://docs.mongodb.com/master/release-notes/8.0/#upgrade-procedures."}}
9.0 açılmadı: veri dizinindeki FCV belgesi 6.0 diyor ve 9.0 yalnız 9.0, 8.3 ya da 8.0 kabul ediyor. Veri bozulmadı, container başlamadan durdu. Doğru yol aynı volume'la üç adım; her adımda önce yeni binary eski FCV'yle açılıyor, kontrol ediliyor, sonra FCV yükseltiliyor:
docker run -d --name bookstore-upgrade -v bookstore-upgrade:/data/db -v "${PWD}\data:/lab/data:ro" -v "${PWD}\scripts:/lab/scripts:ro" mongodb/mongodb-community-server:7.0-ubuntu2204
docker exec bookstore-upgrade mongosh --quiet /lab/scripts/15-check.js
docker exec bookstore-upgrade mongosh --quiet --eval "db.adminCommand({ setFeatureCompatibilityVersion: '7.0', confirm: true }).ok"
docker exec bookstore-upgrade mongosh --quiet /lab/scripts/15-check.js
version 7.0.48 | FCV 6.0 | books 77 | title_1: {"v":2,"key":{"title":1},"name":"title_1"}
1
version 7.0.48 | FCV 7.0 | books 77 | title_1: {"v":2,"key":{"title":1},"name":"title_1"}
version 8.0.38 | FCV 7.0 | books 77 | title_1: {"v":2,"key":{"title":1},"name":"title_1"}
1
version 8.0.38 | FCV 8.0 | books 77 | title_1: {"v":2,"key":{"title":1},"name":"title_1"}
version 9.0.8 | FCV 8.0 | books 77 | title_1: {"v":2,"key":{"title":1},"name":"title_1"}
1
version 9.0.8 | FCV 9.0 | books 77 | title_1: {"v":2,"key":{"title":1},"name":"title_1"}
(8.0 ve 9.0 adımları aynı komutlar, image etiketi ve FCV değeri değişiyor.) Her adımın ilk satırı yeni binary'nin eski FCV'yle çalıştığını gösteriyor; uygulamanı bu durumda bir süre çalıştırıp sorun yoksa FCV'yi yükseltmek doğru sıra. 7.0'dan beri setFeatureCompatibilityVersion confirm: true istiyor; dikkatsizce çalıştırılmasın diye. Dokümana göre 8.3'ten beri bir önceki minor ya da major sürüme geri dönmek destekleniyor, yani 9.0'dan 8.0'a; ama iki adım geriye, 7.0'a dönmek desteklenmiyor. Replica set'te aynı işi üyeleri tek tek yeniden başlatarak (önce secondary'ler, en son stepDown ile primary; 13. yazı) kesintisiz yapıyorsun.
C# Driver 2.x'ten 3.x'e: Önce Derleyici
Örneğin 2.x'e özgü ayarları bir #if DRIVER2 bloğunda. 2.30 bu satırlarda zaten CS0618 obsolete uyarısı veriyor; aynı satırları 3.14'e karşı derleyince uyarılar hataya dönüşüyor:
#if DRIVER2
// Birçok projede olduğu gibi driver 2.x ayarları
BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
MongoClientSettings settings = MongoClientSettings.FromConnectionString(connectionString);
settings.LinqProvider = LinqProvider.V3;
#else
// Driver 3.x: V3 Guid modu ve LINQ3 tek seçenek, ayarlar kalktı
MongoClientSettings settings = MongoClientSettings.FromConnectionString(connectionString);
#endif
dotnet build samples/DriverUpgrade -p:MongoDriverVersion=3.14.0 -p:DefineConstants=DRIVER2
samples/DriverUpgrade/Program.cs(14,14): error CS0117: 'BsonDefaults' does not contain a definition for 'GuidRepresentationMode'
samples/DriverUpgrade/Program.cs(14,39): error CS0103: The name 'GuidRepresentationMode' does not exist in the current context
samples/DriverUpgrade/Program.cs(16,10): error CS1061: 'MongoClientSettings' does not contain a definition for 'LinqProvider' and no accessible extension method 'LinqProvider' accepting a first argument of type 'MongoClientSettings' could be found (are you missing a using directive or an assembly reference?)
samples/DriverUpgrade/Program.cs(16,25): error CS0103: The name 'LinqProvider' does not exist in the current context
samples/DriverUpgrade/Program.cs(39,1): error CS0246: The type or namespace name 'IMongoQueryable<>' could not be found (are you missing a using directive or an assembly reference?)
Bu hataların hepsi upgrade rehberinde: LINQ2 (driver'ın eski LINQ çeviricisi) kaldırıldı ve LINQ3 (3.0'ın çeviricisi) tek seçenek, GuidRepresentationMode.V2 kaldırıldı ve 9. yazıdaki gibi GuidSerializer'ı açıkça kaydetmek gerekiyor, IMongoQueryable<T> yerine düz IQueryable<T> geldi. Rehberdeki diğer başlıklar: .NET Framework 4.7.2 ya da .NET Core 3.x minimum, AWS (Amazon'un bulut platformu) authentication ve in-use encryption ayrı paketlere (MongoDB.Driver.Authentication.AWS, MongoDB.Driver.Encryption) taşındı, TLS (bağlantıyı şifreleyen protokol) 1.0 ve 1.1 desteği bitti. 3.x içinde de sunucu tabanı yükseliyor: 3.5 MongoDB 4.0 ve öncesini, 3.10 4.2 ve öncesini bıraktı. 2.30'un build çıktısında bir neden daha vardı: geçişli bağımlılıklar SharpCompress 0.30.1 ve Snappier 1.0.0 için NuGet bilinen güvenlik açığı uyarıları (NU1902, NU1903) verdi.
Sonra Veri: decimal ve DateTimeOffset
Derleyici hataları görünür; asıl risk "Önce Tahmin Et"teki gibi sessiz olanlar. 3.0 iki serialization varsayılanını değiştirdi: decimal artık Decimal128, DateTimeOffset artık DateTime, Ticks, Offset alanlı bir document (9. yazıda gördüğümüz biçim). Eski veriyi okurken iki yol var: property'ye [BsonRepresentation(BsonType.String)] ve [BsonRepresentation(BsonType.Array)] koyup eski biçimi sürdürmek ya da veriyi bir kez yeni biçime taşımak. Fiyat üzerinde sayısal sorgu ve sıralama istediğimiz için ikincisi:
const prices = db.driver_upgrade.updateMany(
{ ListPrice: { $type: "string" } },
[{ $set: { ListPrice: { $toDecimal: "$ListPrice" } } }]
);
// 2.x array'i: [yerel ticks, dakika olarak offset]; 3.x document'i: { DateTime (UTC), Ticks, Offset }
// Array olan bir alana $set ile document atamak onu her element'e uygular; bu yüzden array önce kenara alınır
const dates = db.driver_upgrade.updateMany(
{ ListedAt: { $type: "array" } },
[
{ $set: { legacy: "$ListedAt" } },
{ $unset: "ListedAt" },
{ $set: { ListedAt: {
DateTime: { $toDate: { $subtract: [
{ $divide: [{ $subtract: [ticks, NumberLong("621355968000000000")] }, 10000] },
{ $multiply: [offset, 60000] }] } },
Ticks: ticks,
Offset: offset
} } },
{ $unset: "legacy" }
]
);
ListPrice converted: 3 | ListedAt converted: 3
driver 3.14.0: bookstore.driver_upgrade.Aggregate([{ "$match" : { "ListPrice" : { "$lt" : { "$numberDecimal" : "500" } } } }])
driver 3.14.0: books under 500: Dune 390.50 (listed 2024-06-01 09:00 +03:00)
driver 3.14.0: stored types: ListPrice Decimal128, ListedAt Document
Migration'dan sonra 3.14 doğru cevabı verdi: yalnız Dune, tarih ve offset korunarak. Script'in ilk sürümü öğretici bir hata yaptı: $set ile array olan bir alana document atadığımda MongoDB document'i array'in her element'ine uyguladı ve ListedAt iki elemanlı bir document array'ine dönüştü; 3.14 de onu FormatException ile okuyamadı. Bu yüzden eski array önce legacy alanına taşınıp silindi. Büyük bir collection'da aynı migration'ı 5. yazıdaki gibi küçük batch'lerle, ilerlemeyi kaydederek çalıştır; geçiş süresince hem eski hem yeni biçimi okuyabilen kod gerekirse iki biçimi de deserialize eden özel bir serializer yazmak bir seçenek.
Geçiş Kontrol Listesi
- Sunucu: hangi major'dasın, destek tarihi ne? 8.0'ın altındaysan 9.0'a giden ara adımları planla.
- Her adımda önce binary, sonra uygulamayı eski FCV'yle izle, en son
setFeatureCompatibilityVersionileconfirm: true. - Hedef sürümün compatibility ve known issues sayfalarını oku; 9.0 için sorgu başına bellek sınırı, açık transaction sınırı ve
SERVER-89953. - Driver: önce 2.30'a geç ve bütün
CS0618uyarılarını temizle, sonra 3.x'e geç. - Veride string
decimal, arrayDateTimeOffsetve subtype 3Guid(9. yazı) ara;$typesorgularıyla say. - Yükseltmeyi production verisinin restore edilmiş bir kopyasında prova et (14. yazının restore testi) ve sorgu sonuçlarını iki sürümde karşılaştır.
- Entity Framework Core (EF Core) provider'ını kullanıyorsan breaking change'lerin minor sürümlerde de gelebildiğini unutma (11. yazı).
Üretimde Dikkat
Driver ve sunucu yükseltmesini aynı deploy'a koyma. Önce sunucuyu eski FCV'yle yükselt ve uygulamayı aynı driver'la çalıştır; sonra driver'ı ayrı bir deploy'da yükselt. Bir şey bozulduğunda hangi değişikliğin bozduğunu bilmek ancak böyle mümkün.
Yükseltmeden önce ve sonra aynı sorguları ölç. 7. yazıdaki SBE (Slot-Based Execution; MongoDB'nin yeni sorgu yürütme motoru) farkı ve 8. yazıdaki bellek sınırı, sürüm değişince aynı pipeline'ın farklı plan ve farklı hata üretebileceğini gösterdi. En sık sorgularının explain çıktısını sakla ve yükseltmeden sonra karşılaştır.
Sık Düşülen Tuzaklar
FCV'yi hemen yükseltmek. Binary değişikliğinden hemen sonra FCV'yi yükseltirsen geri dönüş kapısını kapatırsın; sorun birkaç gün sonra çıkarsa eski sürüme dönemezsin. FCV'yi uygulama yeni binary'de bir süre sorunsuz çalıştıktan sonra yükselt.
Derleme geçti diye yükseltmeyi bitmiş saymak. "Önce Tahmin Et"teki sorgu iki driver'da da derlendi ve hata vermedi; biri yanlış, diğeri boş sonuç döndürdü. Yükseltmenin testi derleyici değil, gerçek veriye karşı çalışan integration testleri (10. yazı).
Küçük Bir Deneme
★☆☆ PricedBook.ListPrice'a [BsonRepresentation(BsonType.String)] ekleyip migration'sız veriyle 3.14'te sorguyu çalıştır. Kaç kitap dönüyor ve neden 2.30'daki yanlış sonuç geri geliyor?
★★☆ Yükseltme adımlarını 9.0'da durdur ve FCV 8.0'dayken volume'u yeniden 8.0 image'ıyla aç. Sonra FCV'yi 9.0 yapıp aynı denemeyi tekrarla; 8.0 bu sefer ne diyor?
★★★ Bookstore'un bütün collection'larında 2.x biçimindeki değerleri ($type: "string" fiyatlar, array tarihler, subtype 3 Guid'ler) sayan bir rapor script'i yaz ve 14. yazının restore edilmiş kopyası üzerinde çalıştır.
Seri burada bitiyor. Bookstore'un katalog, sipariş ve yorum tarafı artık MongoDB'de: document modeli ve schema pattern'leri, index ve aggregation, .NET driver ve EF Core provider, tutarlılık, replica set, sharding, güvenlik ve sürüm geçişi. Buradan sonrası için Veritabanı Performansı ve Scaling serisi genel ölçek yolculuğunu, Distributed Systems Temelleri serisi de bu yazılarda uyguladığımız teorinin ayrıntısını anlatıyor.