NoSQL 1: memcached

Time:2021-5-10

1、 Introduction to NoSQL

NoSQL is not no SQL, but not only SQL. NoSQL is not used to replace relational database, but in some scenarios where relational database is not suitable, NoSQL database can be used for optimization, while relational database is still used for main and conventional data in the system.
The commonly used NoSQL databases include memcached, redis, mongodb, etc. the first two belong to the key value pair database, and the latter belongs to the document database. They all have their own advantages and disadvantages and use scenarios.

2、 Introduction and installation of memcached

Memcached is a special database for caching. The cached data is in memory. When the database is restarted, the data will be lost. It is equivalent to a dictionary key value pair set, and takes the value value according to the key value.

1. Memcached installation

Download the memcached-win64-1.4.4-14.zip installation package from the Internet. After decompression, you can install it as a service by executing the following command with administrator privileges:

G:\MemcachedAfterInstall>memcached.exe -d install

2. Memcached visualization tool

Treenms is a visual client tool for redis and memcached, which realizes the management and maintenance of redis and memcached databases based on Web. The following links are availablehttp://www.treesoft.cn/dms.htmlDownload.

The following figure shows the user interface of the tool


  3. Advantages and disadvantages of memcached

advantage:

    1) Multithreading can make full use of the processing performance of CPU multi-core;

2) It has high cache performance;

Disadvantages:

    1) Only the key value pair data can be saved, and the key value can only be a string. If there is object data, you can only serialize the JSON string yourself;

2) Data is only stored in memory and will be lost after restart;

3) The maximum length of key is 250 characters and the maximum length of value is 1m;

 

3、 Using in. Net core

  1. Installation and use of component package

In the.Net Core project, the resources of the Memcached database can be invoked, and the EnyimMemcachedCore client component package can be used.

There are three modes to store data to memcached database through this component, which are as follows:

1) Set: if it exists, it will be covered; if it does not exist, it will be added;

2) Replace: if it exists, it will override and return true; If it does not exist, it will not be processed and will return false;

3) Add: if it does not exist, add it and return true; If it exists, it will not be processed and will return false;

Therefore, according to the above, if there are no special requirements, set can be used generally.

Note: the maximum length of key in memcached database is 250 characters, and the maximum value is 1m.

  2. Case demonstration

For the convenience of demonstration, a WPF project based on. Net core version 3.1 is created. The interface is as follows:

 

 

 

 

 

 

 

 

 

     

    1) Store data, read data

public partial class MainWindow : Window
{
  private readonly MemcachedClient _memcachedClient;
  private static readonly ILoggerFactory _loggerFactory = new LoggerFactory();
  public MainWindow()
  {
    InitializeComponent();
    var options = new MemcachedClientOptions();
    options.AddServer("127.0.0.1", 11211);
    _memcachedClient = new MemcachedClient(_loggerFactory, new MemcachedClientConfiguration(_loggerFactory, options));
  }
}
private void btnStorage_Click(object sender, RoutedEventArgs e)
{
  var result = _memcachedClient.Store(StoreMode.Set, "supersnow", "yao");
  Message box. Show ($"saved successfully{ result}");
}

private void btnRead_Click(object sender, RoutedEventArgs e)
{
  var result = _memcachedClient.Get("supersnow");
  Message box. Show ($"read result: {result}");
}

  

     2) Storing class data and reading class data

private async void btnStorage_Class_Click(object sender, RoutedEventArgs e)
{
  var person = new Person
  {
    Name = "SuperSnow",
    Age = 25
  };
  var result = await _memcachedClient.StoreAsync(StoreMode.Set, "person_key", person, TimeSpan.FromSeconds(3600));
  Message box. Show ($"save person successfully{ result}");
}
private async void btnRead_Class_Click(object sender, RoutedEventArgs e)
{
  var result = await _memcachedClient.GetAsync("person_key");
  if (result.Value == null)
    Message box. Show ("the data is invalid");
  else
    Message box. Show ($"read person result: {result. Value. Name}: {result. Value. Age}");
}
public class Person
{
  public string Name { get; set; }
  public int Age { get; set; }
}

  

     3) Reading data exception

When reading data fails, the return result is false. However, we do not know the cause of the failure at this time. We can obtain the cause of the failure by the following methods:

private void btnRead_Exception_Click(object sender, RoutedEventArgs e)
 {
    var result = _memcachedClient.ExecuteRemove("abc");
    Message box. Show ($"result: {result. Success}, message: {result. Message}, exception: {result. Exception}, statuscode: {result. Statuscode}, innerresult: {result. Innerresult. Message}");
 }

  

     4) Memcached CAS operation

CAS operation is similar to “optimistic lock” in relational database. When querying, it will find out a CAS value, and when writing, it will carry this CAS value. If it is found that the CAS value has changed, it means that other operations have modified the corresponding value in advance. In essence, CAS is used to solve the concurrency problem. By reading a value, doing some processing or judgment, and then writing it back to the database, this operation may cause concurrency problems.

private CasResult casResult;
 private void btnA_Read_Click(object sender, RoutedEventArgs e)
 {
     casResult = _memcachedClient.GetWithCas("person_key");
     if (casResult.Result != null)
         Message box. Show ($"read person result: {casresult. Result. Name}: {casresult. Result. Age}");
     else
         Message box. Show ("no result");
 }

 private void btnB_Save_Click(object sender, RoutedEventArgs e)
 {
     var result = _memcachedClient.GetWithCas("person_key");
     if (result.Result.Age >= 25)
         result.Result.Age++;
     var tag = _memcachedClient.Cas(StoreMode.Set, "person_key", result.Result, result.Cas);
     if (tag.Result)
         Message box. Show ("modified successfully");
     else
         Message box. Show ("modification failed");
 }

 private void btnA_Save_Click(object sender, RoutedEventArgs e)
 {
     if (casResult.Result.Age >= 25)
         casResult.Result.Age++;
     else
         casResult.Result.Age++;
     var tag = _memcachedClient.Cas(StoreMode.Set, "person_key", casResult.Result, casResult.Cas);
     if (tag.Result)
         Message box. Show ("modified successfully");
     else
         Message box. Show ("modification failed");
 }

 

     5) Memcached cluster

After the restart of memcached, a large number of requests will flow into the database in a short time, causing great pressure on the database. The solution to this problem is to use cluster, that is, to use multiple memcached servers to provide services.

In addition, memcached may face an “avalanche” problem if all cache settings have the same expiration time, or the expiration time is within a short distance. Then every once in a while will cause a database access peak. The solution to this kind of problem is to set the cache expiration time of different caches to be different, such as adding a random number to the expiration time.

There is no need for communication and data synchronization between nodes in the memcached cluster, just start multiple memcached databases on multiple servers. The client decides to write data to different memcached instances instead of master-slave replication.

There are many kinds of node localization algorithms, the most commonly used is Ketama algorithm, which calculates a hash value according to the key, and then obtains the server according to the hash value. The example is as follows:

private readonly MemcachedClient _memcachedClient;
private static readonly ILoggerFactory _loggerFactory = new LoggerFactory();
public MainWindow()
{
    InitializeComponent();

    var options = new MemcachedClientOptions();
    options.AddServer("127.0.0.1", 11211);
    options.AddServer("127.0.0.1", 11212);
    options.NodeLocatorFactory = new DefaultNodeLocatorFactory(11211);
    _memcachedClient = new MemcachedClient(_loggerFactory, new MemcachedClientConfiguration(_loggerFactory, options));
}
private void btnA_Save_Cluster_Click(object sender, RoutedEventArgs e)
{
    var person = new Person
    {
        Name = Zhang San,
        Age = 25
    };
    var result =  _memcachedClient.Store(StoreMode.Set, "1", person);
    Message box. Show ($"save person successfully{ result}");
}

private void btnA_Read_Cluster_Click(object sender, RoutedEventArgs e)
{
    var result = _memcachedClient.Get("1");
    if (result == null)
        Message box. Show ("the data is invalid");
    else
        Message box. Show ($"read person result: {result. Name}: {result. Age}");
}

private void btnB_Save_Cluster_Click(object sender, RoutedEventArgs e)
{
    var person = new Person
    {
        Name = Li Si,
        Age = 23
    };
    var result = _memcachedClient.Store(StoreMode.Set, "2", person);
    Message box. Show ($"save person successfully{ result}");
}

private void btnB_Read_Cluster_Click(object sender, RoutedEventArgs e)
{
    var result = _memcachedClient.Get("2");
    if (result == null)
        Message box. Show ("the data is invalid");
    else
        Message box. Show ($"read person result: {result. Name}: {result. Age}");
}

 

Start two memcached instances through the following command:

G:\MemcachedAfterInstall>memcached.exe -p 11212
G:\MemcachedAfterInstall>memcached.exe -p 11211

Configure two database connections in treenms system

Because the hash values of key = 1 and key = 2 are different, the cache data exists in two memcached instances, as shown in the following figure:

 

 

 

 

Recommended Today

[rust] basic data type

This article introduces the built-in data types provided by rust. Boolean type Boolean typeLogical values representing yes and No. It has two values:trueandfalseGenerally used in logical expressions, and, or, and not operations can be performed: fn main() { let x = true; let y: bool = ! x; // False, inverse operation let z = […]