Redis
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> Redis

Di chuyển dữ liệu với Redis

Trang này chạy qua một ví dụ điển hình để cho thấy việc di chuyển dữ liệu điển hình dễ dàng như thế nào khi sử dụng Redis và các kho lưu trữ dữ liệu không có lược đồ NoSQL khác.

Tất cả các trang ứng dụng Redis Blog #

  • Thiết kế Cơ sở dữ liệu NoSQL bằng Redis
  • Di chuyển dữ liệu không đau đớn bằng Redis và các kho dữ liệu NoSQL ít giản đồ khác

Di chuyển dữ liệu dễ dàng với kho dữ liệu NoSQL ít lược đồ và Redis #

Đang phát triển mới hệ thống cơ sở dữ liệu greenfield sử dụng phần cuối RDBMS hầu hết là một trải nghiệm không gặp sự cố. Trước khi hệ thống hoạt động, bạn có thể dễ dàng sửa đổi giản đồ bằng cách đánh dấu vào toàn bộ cơ sở dữ liệu ứng dụng và tạo lại nó bằng các tập lệnh DDL tự động sẽ tạo và điền vào nó với dữ liệu thử nghiệm phù hợp với giản đồ mới của bạn.

Những rắc rối thực sự trong cuộc sống CNTT của bạn xảy ra sau lần triển khai đầu tiên và hệ thống của bạn đi vào hoạt động. Tại thời điểm đó, bạn không còn có tùy chọn xóa cơ sở dữ liệu và tạo lại từ đầu. Nếu may mắn, bạn có một tập lệnh có thể tự động suy ra các câu lệnh DDL cần thiết để chuyển từ giản đồ cũ sang lược đồ mới. Tuy nhiên, bất kỳ thay đổi quan trọng nào đối với giản đồ của bạn đều có khả năng liên quan đến đêm muộn, thời gian ngừng hoạt động và nỗ lực không nhỏ để đảm bảo chuyển đổi thành công sang giản đồ db mới.

Quá trình này ít đau hơn nhiều với các kho dữ liệu ít giản đồ hơn. Trên thực tế, trong hầu hết các trường hợp khi bạn chỉ thêm và xóa các trường, nó hoàn toàn không tồn tại. Bằng cách không để kho dữ liệu của bạn hiểu chi tiết nội tại của giản đồ của bạn, điều đó có nghĩa là nó không còn là vấn đề cấp cơ sở hạ tầng và có thể dễ dàng được xử lý bằng logic ứng dụng nếu cần.

Không cần bảo trì, ít lược đồ và không xâm nhập là những phẩm chất thiết kế cơ bản được đưa vào Redis và các hoạt động của nó. Ví dụ:truy vấn danh sách các BlogPosts gần đây trả lại cùng một kết quả cho danh sách trống như trong cơ sở dữ liệu Redis trống - 0 kết quả. Vì các giá trị trong Redis là các chuỗi an toàn nhị phân nên bạn có thể lưu trữ bất cứ thứ gì bạn muốn trong đó và quan trọng nhất là bằng cách mở rộng, điều này có nghĩa là tất cả các hoạt động của Redis có thể hỗ trợ tất cả các loại ứng dụng của bạn mà không cần 'ngôn ngữ trung gian' như DDL để cung cấp lược đồ cứng nhắc về những gì mong đợi. Không cần khởi tạo trước, mã của bạn có thể nói chuyện trực tiếp với kho dữ liệu Redis một cách tự nhiên như thể nó là một bộ sưu tập trong bộ nhớ.

Để minh họa những gì có thể đạt được trong thực tế, tôi sẽ chạy qua hai chiến lược khác nhau để xử lý các thay đổi lược đồ.

  • Phương pháp không cần làm gì - trong đó việc thêm, xóa trường và thay đổi loại trường không phá hủy được tự động xử lý.
  • Sử dụng bản dịch tùy chỉnh - sử dụng logic cấp ứng dụng để tùy chỉnh bản dịch giữa các loại cũ và mới.

Mã nguồn có thể chạy đầy đủ cho ví dụ này có sẵn tại đây.

Mã mẫu #

Để minh họa một tình huống di chuyển điển hình, tôi đang sử dụng BlogPost nhập được xác định trên trang trước để chiếu nó sang một New.BlogPost khác về cơ bản gõ phím. Định nghĩa đầy đủ về các loại cũ và mới được hiển thị bên dưới:

Lược đồ cũ #

public class BlogPost
{
    public BlogPost()
    {
        this.Categories = new List<string>();
        this.Tags = new List<string>();
        this.Comments = new List<BlogPostComment>();
    }

    public int Id { get; set; }
    public int BlogId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public List<string> Categories { get; set; }
    public List<string> Tags { get; set; }
    public List<BlogPostComment> Comments { get; set; }
}

public class BlogPostComment
{
    public string Content { get; set; }
    public DateTime CreatedDate { get; set; }
}

Giản đồ mới #

'Phiên bản mới' chứa hầu hết các thay đổi mà bạn có thể gặp phải trong quá trình phát triển ứng dụng bình thường:

  • Đã thêm, xóa và đổi tên các trường
  • Thay đổi không phá hủy của int thành longdouble lĩnh vực
  • Đã thay đổi loại tập hợp Thẻ từ List đến một HashSet
  • Đã thay đổi một BlogPostComment được đánh máy mạnh nhập vào một chuỗi được gõ lỏng lẻo Dictionary
  • Đã giới thiệu một enum mới loại
  • Đã thêm một trường tính toán có thể vô hiệu

Loại giản đồ mới #

public class BlogPost
{
    public BlogPost()
    {
        this.Labels = new List<string>();
        this.Tags = new HashSet<string>();
        this.Comments = new List<Dictionary<string, string>>();
    }

    //Changed int types to both a long and a double type
    public long Id { get; set; }
    public double BlogId { get; set; }

    //Added new field
    public BlogPostType PostType { get; set; }

    public string Title { get; set; }
    public string Content { get; set; }

    //Renamed from 'Categories' to 'Labels'
    public List<string> Labels { get; set; }

    //Changed from List to a HashSet
    public HashSet<string> Tags { get; set; }

    //Changed from List of strongly-typed 'BlogPostComment' to loosely-typed string map
    public List<Dictionary<string, string>> Comments { get; set; }

    //Added pointless calculated field
    public int? NoOfComments { get; set; }
}

public enum BlogPostType
{
    None,
    Article,
    Summary,
}

1. Phương pháp không làm gì - sử dụng dữ liệu cũ với các kiểu mới #

Mặc dù khó tin nhưng không cần nỗ lực thêm, bạn có thể giả vờ như không có thay đổi nào thực sự được thực hiện và tự do truy cập các loại mới nhìn vào dữ liệu cũ. Điều này có thể thực hiện được khi có những thay đổi không phá hủy (tức là không mất thông tin) với các loại trường mới. Ví dụ dưới đây sử dụng kho lưu trữ từ ví dụ trước để điền vào Redis dữ liệu thử nghiệm từ các loại cũ. Cũng như nếu không có gì xảy ra, bạn có thể đọc dữ liệu cũ bằng kiểu mới:

var repository = new BlogRepository(redisClient);

//Populate the datastore with the old schema from the 'BlogPostBestPractice'
BlogPostBestPractice.InsertTestData(repository);

//Create a typed-client based on the new schema
using (var redisBlogPosts = redisClient.GetTypedClient<New.BlogPost>())
{
    //Automatically retrieve blog posts
    IList<New.BlogPost> allBlogPosts = redisBlogPosts.GetAll();

    //Print out the data in the list of 'New.BlogPost' populated from old 'BlogPost' type
    Console.WriteLine(allBlogPosts.Dump());
    /*Output:
    [
        {
            Id: 3,
            BlogId: 2,
            PostType: None,
            Title: Redis,
            Labels: [],
            Tags: 
            [
                Redis,
                NoSQL,
                Scalability,
                Performance
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 2010-04-28T21:42:03.9484725Z
                }
            ]
        },
        {
            Id: 4,
            BlogId: 2,
            PostType: None,
            Title: Couch Db,
            Labels: [],
            Tags: 
            [
                CouchDb,
                NoSQL,
                JSON
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 2010-04-28T21:42:03.9484725Z
                }
            ]
        },
        {
            Id: 1,
            BlogId: 1,
            PostType: None,
            Title: RavenDB,
            Labels: [],
            Tags: 
            [
                Raven,
                NoSQL,
                JSON,
                .NET
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 2010-04-28T21:42:03.9004697Z
                },
                {
                    Content: Second Comment!,
                    CreatedDate: 2010-04-28T21:42:03.9004697Z
                }
            ]
        },
        {
            Id: 2,
            BlogId: 1,
            PostType: None,
            Title: Cassandra,
            Labels: [],
            Tags: 
            [
                Cassandra,
                NoSQL,
                Scalability,
                Hashing
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 2010-04-28T21:42:03.9004697Z
                }
            ]
        }
    ]

     */
}

2. Sử dụng bản dịch tùy chỉnh để di chuyển dữ liệu bằng logic ứng dụng #

Một số hạn chế với cách tiếp cận 'không làm gì' ở trên là bạn sẽ mất dữ liệu của 'các trường được đổi tên'. Cũng sẽ có lúc bạn muốn dữ liệu mới được di chuyển có các giá trị cụ thể khác với các giá trị mặc định được tích hợp sẵn .NET. Khi bạn muốn kiểm soát nhiều hơn việc di chuyển dữ liệu cũ của mình, việc thêm bản dịch tùy chỉnh là một bài tập nhỏ khi bạn có thể thực hiện điều đó một cách nguyên bản trong mã:

var repository = new BlogRepository(redisClient);

//Populate the datastore with the old schema from the 'BlogPostBestPractice'
BlogPostBestPractice.InsertTestData(repository);

//Create a typed-client based on the new schema
using (var redisBlogPosts = redisClient.GetTypedClient<BlogPost>())
using (var redisNewBlogPosts = redisClient.GetTypedClient<New.BlogPost>())
{
    //Automatically retrieve blog posts
    IList<BlogPost> oldBlogPosts = redisBlogPosts.GetAll();

    //Write a custom translation layer to migrate to the new schema
    var migratedBlogPosts = oldBlogPosts.ConvertAll(old => new New.BlogPost
    {
        Id = old.Id,
        BlogId = old.BlogId,
        Title = old.Title,
        Content = old.Content,
        Labels = old.Categories, //populate with data from renamed field
        PostType = New.BlogPostType.Article, //select non-default enum value
        Tags = old.Tags,
        Comments = old.Comments.ConvertAll(x => new Dictionary<string, string> 
            { { "Content", x.Content }, { "CreatedDate", x.CreatedDate.ToString() }, }),
        NoOfComments = old.Comments.Count, //populate using logic from old data
    });

    //Persist the new migrated blogposts 
    redisNewBlogPosts.StoreAll(migratedBlogPosts);

    //Read out the newly stored blogposts
    var refreshedNewBlogPosts = redisNewBlogPosts.GetAll();
    //Note: data renamed fields are successfully migrated to the new schema
    Console.WriteLine(refreshedNewBlogPosts.Dump());
    /*
    [
        {
            Id: 3,
            BlogId: 2,
            PostType: Article,
            Title: Redis,
            Labels: 
            [
                NoSQL,
                Cache
            ],
            Tags: 
            [
                Redis,
                NoSQL,
                Scalability,
                Performance
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 28/04/2010 22:58:35
                }
            ],
            NoOfComments: 1
        },
        {
            Id: 4,
            BlogId: 2,
            PostType: Article,
            Title: Couch Db,
            Labels: 
            [
                NoSQL,
                DocumentDB
            ],
            Tags: 
            [
                CouchDb,
                NoSQL,
                JSON
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 28/04/2010 22:58:35
                }
            ],
            NoOfComments: 1
        },
        {
            Id: 1,
            BlogId: 1,
            PostType: Article,
            Title: RavenDB,
            Labels: 
            [
                NoSQL,
                DocumentDB
            ],
            Tags: 
            [
                Raven,
                NoSQL,
                JSON,
                .NET
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 28/04/2010 22:58:35
                },
                {
                    Content: Second Comment!,
                    CreatedDate: 28/04/2010 22:58:35
                }
            ],
            NoOfComments: 2
        },
        {
            Id: 2,
            BlogId: 1,
            PostType: Article,
            Title: Cassandra,
            Labels: 
            [
                NoSQL,
                Cluster
            ],
            Tags: 
            [
                Cassandra,
                NoSQL,
                Scalability,
                Hashing
            ],
            Comments: 
            [
                {
                    Content: First Comment!,
                    CreatedDate: 28/04/2010 22:58:35
                }
            ],
            NoOfComments: 1
        }
    ]

     */
}

Kết quả cuối cùng là một kho dữ liệu chứa đầy dữ liệu mới được điền chính xác theo cách bạn muốn - sẵn sàng phục vụ các tính năng của ứng dụng mới của bạn. Ngược lại, cố gắng thực hiện những điều trên trong một giải pháp RDBMS điển hình mà không có bất kỳ thời gian ngừng hoạt động nào thực sự là một kỳ tích ma thuật đáng được khen thưởng bởi 999 điểm Stack Overflow và lời chia buồn cá nhân từ vị thủ tướng lớn của nó @JonSkeet 😃

Tôi hy vọng điều này minh họa rõ ràng sự khác biệt giữa hai công nghệ. Trong thực tế, bạn sẽ ngạc nhiên bởi năng suất đạt được khi bạn không phải lập mô hình ứng dụng của mình để phù hợp với ORM và RDBMS và có thể lưu các đối tượng giống như nó là bộ nhớ.

Luôn luôn là một ý tưởng hay để tiếp xúc với các công nghệ mới, vì vậy nếu bạn chưa làm như vậy, tôi mời bạn bắt đầu phát triển với Redis ngay hôm nay để thấy được những lợi ích cho bản thân. Để bắt đầu, tất cả những gì bạn cần là một phiên bản của máy chủ redis (không cần cấu hình, chỉ cần giải nén và chạy) và Máy khách C # Redis của ServiceStack không phụ thuộc và bạn đã sẵn sàng!


No
  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Làm cách nào để tìm kiếm chuỗi trong redis?

  2. Redis Sentinel

  3. So sánh số 64 bit đã ký bằng cách sử dụng các phép toán bit 32 bit trong Lua

  4. DB trong bộ nhớ quan hệ?

  5. API RedisClient LUA