You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by az...@apache.org on 2023/03/09 06:48:07 UTC

[shardingsphere] branch master updated: Upload 2 more blogs (#24520)

This is an automated email from the ASF dual-hosted git repository.

azexin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 49d8e577ef6 Upload 2 more blogs (#24520)
49d8e577ef6 is described below

commit 49d8e577ef6ea08cb99f8e3f3eb2cd1b91683320
Author: FPokerFace <11...@users.noreply.github.com>
AuthorDate: Thu Mar 9 14:48:00 2023 +0800

    Upload 2 more blogs (#24520)
---
 ...idecar_for_a_true_cloud-native_experience.en.md |   2 +-
 ...is_released_new_features_and_improvements.en.md |   8 +-
 ...tion_to_create_ShardingSphere_HA_clusters.en.md | 333 +++++++++++++++++
 ...herColumn__ShardingSphere_5.3.0_Deep_Dive.en.md | 397 +++++++++++++++++++++
 ...ation_to_create_ShardingSphere_HA_clusters1.png | Bin 0 -> 57557 bytes
 ...ation_to_create_ShardingSphere_HA_clusters2.png | Bin 0 -> 44232 bytes
 ...ation_to_create_ShardingSphere_HA_clusters3.png | Bin 0 -> 41049 bytes
 ...ation_to_create_ShardingSphere_HA_clusters4.png | Bin 0 -> 52180 bytes
 ...ation_to_create_ShardingSphere_HA_clusters5.png | Bin 0 -> 61135 bytes
 ...pherColumn__ShardingSphere_5.3.0_Deep_Dive1.png | Bin 0 -> 220428 bytes
 ...pherColumn__ShardingSphere_5.3.0_Deep_Dive2.png | Bin 0 -> 83075 bytes
 ...pherColumn__ShardingSphere_5.3.0_Deep_Dive3.png | Bin 0 -> 32608 bytes
 ...pherColumn__ShardingSphere_5.3.0_Deep_Dive4.png | Bin 0 -> 11673 bytes
 ...pherColumn__ShardingSphere_5.3.0_Deep_Dive5.png | Bin 0 -> 6578 bytes
 ...pherColumn__ShardingSphere_5.3.0_Deep_Dive6.png | Bin 0 -> 6147 bytes
 15 files changed, 735 insertions(+), 5 deletions(-)

diff --git a/docs/blog/content/material/2022_11_24_ShardingSphere-on-Cloud_&_Pisanix_replace_Sidecar_for_a_true_cloud-native_experience.en.md b/docs/blog/content/material/2022_11_24_ShardingSphere-on-Cloud_&_Pisanix_replace_Sidecar_for_a_true_cloud-native_experience.en.md
index 44be1af11f7..b68bf8f75d2 100644
--- a/docs/blog/content/material/2022_11_24_ShardingSphere-on-Cloud_&_Pisanix_replace_Sidecar_for_a_true_cloud-native_experience.en.md
+++ b/docs/blog/content/material/2022_11_24_ShardingSphere-on-Cloud_&_Pisanix_replace_Sidecar_for_a_true_cloud-native_experience.en.md
@@ -44,7 +44,7 @@ Sidecar can indeed play a big role in certain scenarios, but it doesn't mean tha
 
 [ShardingSphere-on-Cloud](https://github.com/apache/shardingsphere-on-cloud) is capable of deploying and migrating ShardingSphere in a Kubernetes environment. With the help of [AWS CloudFormation](https://aws.amazon.com/cloudformation/), [Helm](https://helm.sh/), Operator, and Terraform (coming soon) and other tools, it provides best practices with quick deployment, higher observability, security and migration, and high availability deployment in a cloud native environment.
 
-> Please refer to [***Database Plus Embracing the Cloud: ShardingSphere-on-Cloud Solution Released***](https://medium.com/codex/database-plus-embracing-the-cloud-shardingsphere-on-cloud-solution-released-29916290ad06?source=your_stories_page-------------------------------------) for details.
+Please refer to [***Database Plus Embracing the Cloud: ShardingSphere-on-Cloud Solution Released***](https://medium.com/codex/database-plus-embracing-the-cloud-shardingsphere-on-cloud-solution-released-29916290ad06?source=your_stories_page-------------------------------------) for details.
 
 ## Achieving the vision of ShardingSphere-Sidecar through [Pisanix](https://www.pisanix.io/)
 
diff --git a/docs/blog/content/material/2022_12_08_ShardingSphere_5.3.0_is_released_new_features_and_improvements.en.md b/docs/blog/content/material/2022_12_08_ShardingSphere_5.3.0_is_released_new_features_and_improvements.en.md
index e303dc59e04..2c2ac110ef5 100644
--- a/docs/blog/content/material/2022_12_08_ShardingSphere_5.3.0_is_released_new_features_and_improvements.en.md
+++ b/docs/blog/content/material/2022_12_08_ShardingSphere_5.3.0_is_released_new_features_and_improvements.en.md
@@ -61,7 +61,7 @@ ShardingSphere 5.3.0 now supports checkpoint storage, which means data consisten
 
 For example, if data is being verified during data migration and the user stops the verification for some reason, with the verification progress `(finished_percentage)` being 5%, then:
 
-```
+```mysql
 mysql> STOP MIGRATION CHECK 'j0101395cd93b2cfc189f29958b8a0342e882';
 Query OK, 0 rows affected (0.12 sec)
 mysql> SHOW MIGRATION CHECK STATUS 'j0101395cd93b2cfc189f29958b8a0342e882';
@@ -75,7 +75,7 @@ mysql> SHOW MIGRATION CHECK STATUS 'j0101395cd93b2cfc189f29958b8a0342e882';
 
 In this case, the user restarts the data verification. But the work does not have to restart from the beginning. The verification progress `(finished_percentage)` remains at 5%.
 
-```
+```mysql
 mysql> START MIGRATION CHECK 'j0101395cd93b2cfc189f29958b8a0342e882';
 Query OK, 0 rows affected (0.35 sec)
 mysql> SHOW MIGRATION CHECK STATUS 'j0101395cd93b2cfc189f29958b8a0342e882';
@@ -95,7 +95,7 @@ Previously, even with XA and other distributed transactions configured, Sharding
 
 Take the following SQL as an example:
 
-```
+```sql
 insert into account(id, balance, transaction_id) values
 (1, 1, 1),(2, 2, 2),(3, 3, 3),(4, 4, 4),
 (5, 5, 5),(6, 6, 6),(7, 7, 7),(8, 8, 8);
@@ -103,7 +103,7 @@ insert into account(id, balance, transaction_id) values
 
 When this SQL is sharded according to `id mod 2`, the ShardingSphere kernel layer will automatically split it into the following two SQLs and route them to different shards respectively for execution:
 
-```
+```sql
 insert into account(id, balance, transaction_id) values
 (1, 1, 1),(3, 3, 3),(5, 5, 5),(7, 7, 7);
 insert into account(id, balance, transaction_id) values
diff --git a/docs/blog/content/material/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters.en.md b/docs/blog/content/material/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters.en.md
new file mode 100644
index 00000000000..8360ed9eefc
--- /dev/null
+++ b/docs/blog/content/material/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters.en.md
@@ -0,0 +1,333 @@
++++
+title = "Use AWS CloudFormation to create ShardingSphere HA clusters"
+weight = 83
+chapter = true 
+
++++
+
+# What's AWS CloudFormation?
+
+[AWS CloudFormation](https://aws.amazon.com/cloudformation/) is an infrastructure as code (IaC) service that allows you to easily model, provision, and manage all the cloud services provided by [AWS](https://aws.amazon.com/) by custom templates.
+
+Traditionally, when we create a new architecture, we need to manually configure it in AWS step by step which can cause some errors such forgetting some steps.
+
+Now with CloudFormation, we can use declarative configuration to define resources and then create and manage them without worrying about the dependency order of the resources.
+
+In real-world scenarios, we often need to create duplicate architectures. For example, we can build a set of MQ clusters in a pre-release environment whose architecture and production environment are consistent, and create an `AutoScalingGroup` with the same configuration in each availability zone (AZ).
+
+Through CloudFormation, those repeated architectures can then be expressed in the form of code and stored in the code repository for management. This way, they can be easily integrated into existing CI/CD pipelines to achieve the change of infrastructure, in accordance with the current DevOps process. As a result, the infrastructure change is more transparent, repeatable, testable and auditable, simplifying the management of cloud systems.
+
+# What's Apache ShardingSphere?
+
+[Apache ShardingSphere](https://shardingsphere.apache.org/) is a distributed database ecosystem that can transform any database into a distributed database system, and enhance it with sharding, elastic scaling, encryption features & more.
+
+Apache ShardingSphere follows the [Database Plus](https://medium.com/faun/whats-the-database-plus-concepand-what-challenges-can-it-solve-715920ba65aa?source=your_stories_page-------------------------------------) concept, designed to build an ecosystem on top of fragmented heterogeneous databases. It focuses on how to fully use the computing and storage capabilities of databases rather than creating a brand-new database.
+
+[ShardingSphere-Proxy](https://shardingsphere.apache.org/document/current/en/overview/) is a transparent database proxy that supports any client that uses [MySQL](https://www.mysql.com/), [PostgreSQL](https://www.postgresql.org/) and [openGauss](https://opengauss.org/en/).
+
+# Deploy with CloudFormation
+
+As an important part of the data infrastructure, the ShardingSphere Proxy cluster is significant for high availability. For these reasons, our community hopes that you can manage it through IaC to enjoy the benefits brought by IaC.
+
+In the following sections we'll use CloudFormation to create a ShardingSphere-Proxy cluster in multi-AZ. Before creating CloudFormation templates, we have to understand the architecture diagram of a ShardingSphere-Proxy cluster.
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters1.png)
+
+Please note that we use [Zookeeper](https://zookeeper.apache.org/) as the Governance Center.
+
+As you can see, ShardingSphere-Proxy itself is a stateless application. In production scenarios, it only needs to offer a LoadBalancer, which can flexibly distribute the traffic between instances.
+
+To ensure the HA of the ZooKeeper cluster and the ShardingSphere-Proxy cluster, we use the following architecture.
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters2.png)
+
+# Define CloudFormation Parameters
+
+[The CloudFormation template](https://aws.amazon.com/cloudformation/resources/templates/?nc1=h_ls) is a yaml or json file in which you can define all of the infrastructure. [The CloudFormation parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html) allows you to inject custom values into the templates. You can then [reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) these pa [...]
+
+We use [cfndsl](https://github.com/cfndsl/cfndsl) to write CloudFormation templates: cfndsl is a tool written in [ruby](https://www.ruby-lang.org/en/), allowing you to generate CloudFormation templates through DSL configuration.
+
+```ruby
+Parameter("ZookeeperInstanceType") {
+  String
+  Default "t2.nano"
+}
+
+Parameter("ShardingSphereInstanceType") {
+  String
+  Default "t2.micro"
+}
+
+Parameter("KeyName") {
+  String
+  Default "test-tf"
+  Description "The ssh keypair for remote connetcion"
+}
+
+Parameter("ImageId") {
+  Type "AWS::EC2::Image::Id"
+  Default "ami-094bbd9e922dc515d"
+}
+
+Parameter("VpcId") {
+  String
+  Default "vpc-0ef2b7440d3ade8d5"
+  Description "The id of your VPC"
+}
+
+....
+```
+
+For more parameters, please refer to this [link](https://github.com/apache/shardingsphere-on-cloud/blob/main/cloudformation/multi-az/cf.rb#L21).
+
+# Define CloudFormation Resources
+
+Note that AWS's region usually includes more than two AZs, so we created three instances.
+
+# Zookeeper Clusters
+
+First, we deploy a Zookeeper EC2 instance in each AZ to ensure the HA of the ZooKeeper cluster.
+
+Then we create an internal domain name for each Zookeeper instance, and ShardingSphere-Proxy uses these domain names.
+
+When the ZooKeeer instance starts, cloud-init is used to automatically deploy the Zookeeper service. You can view the cloud-init configuration [here](https://github.com/apache/shardingsphere-on-cloud/blob/main/cloudformation/multi-az/zookeeper-cloud-init.yml).
+
+```yaml
+(0..2).each do |i| 
+    name = "ZK#{i+1}"
+    EC2_Instance(name) {
+      AvailabilityZone FnSelect(i, FnGetAZs(Ref("AWS::Region")))
+      InstanceType Ref("ZookeeperInstanceType")
+      ImageId Ref("ImageId")
+      KeyName Ref("KeyName")
+      SubnetId FnSelect(i, Ref("Subnets"))
+      SecurityGroupIds Ref("SecurityGroupIds")
+      Tags [ 
+        Tag do 
+          Key "Name"
+          Value "ZK-#{i+1}"
+        end
+      ]
+
+      server = "server.%{idx}=zk-%{idx}.${HostedZoneName}:2888:3888"
+      UserData FnBase64(
+        FnSub(
+          IO.read("./zookeeper-cloud-init.yml"), 
+          :SERVERS => FnSub((0..2).map{|i| i == 0 ? server %{:idx => i+1} : ("#{server}" %{:idx => i+1}).insert(0, " " * 4)}.join("\n")), 
+          :VERSION => Ref("ZookeeperVersion"),
+          :ZK_HEAP => Ref("ZookeeperHeap"),
+          :INDEX => i+1,
+        )
+      )
+    }
+
+    domain = "zone#{name}"
+    Route53_RecordSet(domain) {
+      HostedZoneId Ref("HostedZoneId")
+      Name FnSub("zk-#{i+1}.${HostedZoneName}")
+      Type "A"
+      ResourceRecords [FnGetAtt(name, "PrivateIp")]
+      TTL "60"
+    }
+  end
+```
+
+# ShardingSphere-Proxy Clusters
+
+## LaunchTemplate
+
+Next, we deploy an AutoScalingGroup in each AZ to ensure the HA of a ShardingSphere-Proxy cluster.
+
+Before creating the AutoScalingGroup, we need to create a LaunchTemplate in each AZ for the ShardingSphere-Proxy instance.
+
+Similarly, when the instance starts, cloud-init is used to automatically deploy the ShardingSphere-Proxy service. You can view the cloud-init configuration [here](https://github.com/apache/shardingsphere-on-cloud/blob/main/cloudformation/multi-az/shardingsphere-cloud-init.yml).
+
+```yaml
+(0..2).each do |i| 
+    name = "launchtemplate#{i}"
+    EC2_LaunchTemplate(name) {
+      LaunchTemplateName FnSub("shardingsphere-${TMPL_NAME}", :TMPL_NAME => FnSelect(i, FnGetAZs(Ref('AWS::Region'))))
+      LaunchTemplateData do 
+        ImageId Ref("ImageId")
+        InstanceType Ref("ShardingSphereInstanceType")
+        KeyName Ref("KeyName")
+
+        MetadataOptions do
+          HttpEndpoint "enabled"
+          HttpTokens   "required"
+          InstanceMetadataTags "enabled"
+        end
+
+        Monitoring do
+          Enabled  true
+        end
+
+        NetworkInterfaces [
+          {
+            :DeleteOnTermination => false,
+            :DeviceIndex => 0,
+            :NetworkInterfaceId => FnGetAtt("networkiface#{i}", "Id")
+          }
+        ]
+        
+        TagSpecifications [
+          {
+            :ResourceType => "instance",
+            :Tags => [
+              {
+                :Key => "Name",
+                :Value => "shardingsphere-#{i+1}"
+              }
+            ]
+          }
+        ]
+
+        UserData FnBase64(
+          FnSub(
+            IO.read("./shardingsphere-cloud-init.yml"), 
+            :ZK_SERVERS => FnSub((0..2).map{|i| "zk-#{i+1}.${HostedZoneName}:2181" }.join(",")), 
+            :VERSION => Ref("ShardingSphereVersion"),
+            :JAVA_MEM_OPTS => Ref("ShardingSphereJavaMemOpts")
+          )
+        )
+      end
+    }
+  end
+```
+
+## TargetGroup
+
+As we use [ELB](https://aws.amazon.com/elasticloadbalancing/) to load traffic between each ShardingSphere-Proxy, ELB should be used in combination with [TargetGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html).
+
+Instances created by AutoScalingGroup are automatically registered to TargetGroup. ELB will then forward the traffic to TargetGroup.
+
+```yaml
+ElasticLoadBalancingV2_TargetGroup("sslbtg") {
+    Name "shardingsphere-lb-tg"
+    Port Ref("ShardingSpherePort")
+    Protocol "TCP"
+    VpcId Ref("VpcId")
+    TargetGroupAttributes [
+      TargetGroupAttribute do
+        Key "preserve_client_ip.enabled"
+        Value "false"
+      end
+    ]
+    Tags [
+      Tag do
+        Key "Name"
+        Value "shardingsphere"
+      end
+    ]
+  }
+```
+
+## AutoScalingGroup
+
+After creating the aforementioned resources, now we can create an AutoScalingGroup.
+
+```yaml
+(0..2).each do |i| 
+    name = "autoscaling#{i}"
+    AutoScaling_AutoScalingGroup(name) {
+      AutoScalingGroupName "shardingsphere-#{i}" 
+      AvailabilityZones [FnSelect(i, FnGetAZs(Ref("AWS::Region")))]
+      DesiredCapacity "1"
+      MaxSize "1"
+      MinSize "1"
+      HealthCheckGracePeriod  60
+      HealthCheckType "EC2"
+
+      TargetGroupARNs [ Ref("sslbtg")]
+
+      LaunchTemplate do
+        LaunchTemplateName  FnSub("shardingsphere-${TMPL_NAME}", :TMPL_NAME => FnSelect(i, FnGetAZs(Ref('AWS::Region'))))
+        Version FnGetAtt("launchtemplate#{i}", "LatestVersionNumber")
+      end
+    }
+  end
+```
+
+## LoadBalancer & Listener
+
+Create an internal LoadBalancer and Listener for the external service of the ShardingSphere-Proxy cluster.
+
+```yaml
+ElasticLoadBalancingV2_LoadBalancer("ssinternallb") {
+    Name "shardingsphere-internal-lb"
+    Scheme "internal"
+    Type "network"
+    
+    mappings = (0..2).map { |x| 
+        SubnetMapping do
+          SubnetId FnSelect(x, Ref("Subnets"))
+        end
+    }
+    SubnetMappings mappings
+    Tags [
+      Tag do
+        Key "Name"
+        Value "shardingsphere"
+      end
+    ]
+  }
+  
+  ElasticLoadBalancingV2_Listener("sslblistener") {
+    Port Ref("ShardingSpherePort")
+    LoadBalancerArn Ref("ssinternallb")
+    Protocol "TCP"
+    DefaultActions [
+      {
+        :Type => "forward",
+        :TargetGroupArn => Ref("sslbtg")
+      }
+    ]
+  }
+```
+
+## Internal Domain Names
+
+Finally, we create the internal domain names for the external service of the ShardingSphere-Prxoy cluster. Those domain names point to the internal LoadBalancer.
+
+```yaml
+Route53_RecordSet("ssinternaldomain") {
+    HostedZoneId Ref("HostedZoneId")
+    Name FnSub("proxy.${HostedZoneName}")
+    Type "A"
+    AliasTarget do 
+      HostedZoneId FnGetAtt("ssinternallb", "CanonicalHostedZoneID")
+      DNSName FnGetAtt("ssinternallb", "DNSName")
+      EvaluateTargetHealth true
+    end
+  }
+```
+
+# Deployment
+
+Use the command `cfndsl cf.rb -o cf.json --pretty` to generate the final [configuration](https://github.com/apache/shardingsphere-on-cloud/blob/main/cloudformation/multi-az/cf.json).
+
+Create Stack on the UI page and select the config file we generated.
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters3.png)
+
+After a few minutes, you will find that all the resources have been created.
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters4.png)
+
+You can find the complete code [here](https://github.com/apache/shardingsphere-on-cloud/tree/main/cloudformation/multi-az), or visit our [website](https://shardingsphere.apache.org/oncloud/current/en/operation-guide/cloudformation-multi-az/) for more information.
+
+# Test
+
+The test is designed to ensure that the clusters we created are workable. A simple case is illustrated below.
+
+Use DistSQL (Distributed SQL) to add two data sources and create a simple sharding rule, and then insert data. We can see that the query returns correct results.
+
+By default, when we use CloudFormation, an internal domain name `proxy.shardingsphere.org` will be created. The username and password of the ShardingSphere-Proxy cluster are both `root`.
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters5.png)
+
+**Note:** [DistSQL (Distributed SQL)](https://shardingsphere.apache.org/document/current/en/user-manual/shardingsphere-proxy/distsql/) is ShardingSphere's SQL-like operating language. It's used the same way as standard SQL, and is designed to provide incremental SQL operation capability.
+
+# Conclusion
+
+AWS CloudFormation is an incredibly powerful service that is really helpful for the iteration of ShardingSphere-Proxy clusters. With this new addition, it is now easier than ever to get started with Apache ShardingSphere.
diff --git a/docs/blog/content/material/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive.en.md b/docs/blog/content/material/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive.en.md
new file mode 100644
index 00000000000..0d6976c54de
--- /dev/null
+++ b/docs/blog/content/material/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive.en.md
@@ -0,0 +1,397 @@
++++
+title = "Fuzzy query for CipherColumn | ShardingSphere 5.3.0 Deep Dive"
+weight = 84
+chapter = true 
+
++++
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive1.png)
+
+# 1. Background
+
+[Apache ShardingSphere](https://shardingsphere.apache.org/) supports data encryption. By parsing users' SQL input and rewriting the SQL according to the users' encryption rules, the original data is encrypted and stored with ciphertext data in the underlying database at the same time.
+
+When a user queries the data, it only fetches the ciphertext data from the database, decrypts it, and finally returns the decrypted original data to the user. However, because the encryption algorithm encrypts the whole string, fuzzy queries cannot be achieved.
+
+Nevertheless, many businesses still need fuzzy queries after the data is encrypted. [In version 5.3.0](https://medium.com/faun/shardingsphere-5-3-0-is-released-new-features-and-improvements-bf4d1c43b09b?source=your_stories_page-------------------------------------), Apache ShardingSphere provides users with a default fuzzy query algorithm, supporting the fuzzy query for encrypted fields. The algorithm also supports hot plugging, which can be customized by users, and the fuzzy query can b [...]
+
+# **2. How to achieve fuzzy query in encrypted scenarios?**
+
+## 2.1 Load data to the in-memory database (IMDB)
+
+Load all the data into the IMDB to decrypt it; then it'll be like querying the original data. This method can achieve fuzzy queries. If the amount of data is small, this method will prove to be simple and cost-effective, while on the other hand, if the amount of data is large, it'll turn out to be a disaster.
+
+## 2.2 Implement encryption & decryption functions consistent with database programs
+
+The second method is to modify fuzzy query conditions and use the database decryption function to decrypt data first and then implement fuzzy query. This method's advantage is the low implementation & development cost, as well as use cost.
+
+Users only need to slightly modify the previous fuzzy query conditions. However, the ciphertext and encryption functions are stored together in the database, which cannot cope with the problem of account data leaks.
+
+```sql
+Native SQL: select * from user where name like "%xxx%" 
+After implementing the decryption function: ѕеlесt * frоm uѕеr whеrе dесоdе(namе) lіkе "%ххх%"
+```
+
+## 2.3 Store after data masking
+
+Implement data masking on ciphertext and then store it in a fuzzy query column. This method could lack in terms of precision.
+
+```markdown
+For example, mobile number 13012345678 becomes 130****5678 after the masking algorithm is performed.
+```
+
+## 2.4 Perform encrypted storage after tokenization and combination
+
+This method performs tokenization and combination on ciphertext data and then encrypts the resultset by grouping characters with fixed length and splitting a field into multiple ones. For example, we take four English characters and two Chinese characters as a query condition:
+
+`ningyu1` uses the 4-character as a group to encrypt, so the first group is `ning`, the second group `ingy`, the third group `ngyu`, the fourth group `gyu1`, and so on. All the characters are encrypted and stored in the fuzzy query column. If you want to retrieve all data that contains four characters, such as `ingy`, encrypt the characters and use a key `like"%partial%"` to query.
+
+**Shortcomings:**
+
+1. Increased storage costs: free grouping will increase the amount of data and the data length will increase after being encrypted.
+2. Limited length in fuzzy query: due to security issues, the length of free grouping cannot be too short, otherwise it will be easily cracked by the [rainbow table](https://www.techtarget.com/whatis/definition/rainbow-table). Like the example I mentioned above, the length of fuzzy query characters must be greater than or equal to 4 letters/digits, or 2 Chinese characters.
+
+## 2.5 Single-character digest algorithm (default fuzzy query algorithm provided in ShardingSphere [version 5.3.0](https://medium.com/faun/shardingsphere-5-3-0-is-released-new-features-and-improvements-bf4d1c43b09b?source=your_stories_page-------------------------------------))
+
+Although the above methods are all viable, it's only natural to wonder if there's a better alternative out there. In our community, we find that single-character encryption and storage can balance both performance and query, but fails to meet security requirements.
+
+Then what's the ideal solution? Inspired by masking algorithms and cryptographic hash functions, we find that data loss and one-way functions can be used.
+
+The cryptographic hash function should have the following four features:
+
+1. For any given message, it should be easy to calculate the hash value.
+2. It should be difficult to infer the original message from a known hash value.
+3. It should not be feasible to modify the message without changing the hash value.
+4. There should only be a very low chance that two different messages produce the same hash value.
+
+**Security:** because of the one-way function, it's not possible to infer the original message. In order to improve the accuracy of the fuzzy query, we want to encrypt a single character, but it will be cracked by the rainbow table.
+
+So we take a one-way function (to make sure every character is the same after encryption) and increase the frequency of collisions (to make sure every string is 1: N backward), which greatly enhances security.
+
+# 3. Fuzzy query algorithm
+
+Apache ShardingSphere implements a universal fuzzy query algorithm by using the below single-character digest algorithm `org.apache.shardingsphere.encrypt.algorithm.like.CharDigestLikeEncryptAlgorithm`.
+
+```java
+public final class CharDigestLikeEncryptAlgorithm implements LikeEncryptAlgorithm<Object, String> {
+  
+    private static final String DELTA = "delta";
+  
+    private static final String MASK = "mask";
+  
+    private static final String START = "start";
+  
+    private static final String DICT = "dict";
+  
+    private static final int DEFAULT_DELTA = 1;
+  
+    private static final int DEFAULT_MASK = 0b1111_0111_1101;
+  
+    private static final int DEFAULT_START = 0x4e00;
+  
+    private static final int MAX_NUMERIC_LETTER_CHAR = 255;
+  
+    @Getter
+    private Properties props;
+  
+    private int delta;
+  
+    private int mask;
+  
+    private int start;
+  
+    private Map<Character, Integer> charIndexes;
+  
+    @Override
+    public void init(final Properties props) {
+        this.props = props;
+        delta = createDelta(props);
+        mask = createMask(props);
+        start = createStart(props);
+        charIndexes = createCharIndexes(props);
+    }
+  
+    private int createDelta(final Properties props) {
+        if (props.containsKey(DELTA)) {
+            String delta = props.getProperty(DELTA);
+            try {
+                return Integer.parseInt(delta);
+            } catch (NumberFormatException ex) {
+                throw new EncryptAlgorithmInitializationException("CHAR_DIGEST_LIKE", "delta can only be a decimal number");
+            }
+        }
+        return DEFAULT_DELTA;
+    }
+  
+    private int createMask(final Properties props) {
+        if (props.containsKey(MASK)) {
+            String mask = props.getProperty(MASK);
+            try {
+                return Integer.parseInt(mask);
+            } catch (NumberFormatException ex) {
+                throw new EncryptAlgorithmInitializationException("CHAR_DIGEST_LIKE", "mask can only be a decimal number");
+            }
+        }
+        return DEFAULT_MASK;
+    }
+  
+    private int createStart(final Properties props) {
+        if (props.containsKey(START)) {
+            String start = props.getProperty(START);
+            try {
+                return Integer.parseInt(start);
+            } catch (NumberFormatException ex) {
+                throw new EncryptAlgorithmInitializationException("CHAR_DIGEST_LIKE", "start can only be a decimal number");
+            }
+        }
+        return DEFAULT_START;
+    }
+  
+    private Map<Character, Integer> createCharIndexes(final Properties props) {
+        String dictContent = props.containsKey(DICT) && !Strings.isNullOrEmpty(props.getProperty(DICT)) ? props.getProperty(DICT) : initDefaultDict();
+        Map<Character, Integer> result = new HashMap<>(dictContent.length(), 1);
+        for (int index = 0; index < dictContent.length(); index++) {
+            result.put(dictContent.charAt(index), index);
+        }
+        return result;
+    }
+  
+    @SneakyThrows
+    private String initDefaultDict() {
+        InputStream inputStream = CharDigestLikeEncryptAlgorithm.class.getClassLoader().getResourceAsStream("algorithm/like/common_chinese_character.dict");
+        LineProcessor<String> lineProcessor = new LineProcessor<String>() {
+  
+            private final StringBuilder builder = new StringBuilder();
+  
+            @Override
+            public boolean processLine(final String line) {
+                if (line.startsWith("#") || 0 == line.length()) {
+                    return true;
+                } else {
+                    builder.append(line);
+                    return false;
+                }
+            }
+  
+            @Override
+            public String getResult() {
+                return builder.toString();
+            }
+        };
+        return CharStreams.readLines(new InputStreamReader(inputStream, Charsets.UTF_8), lineProcessor);
+    }
+  
+    @Override
+    public String encrypt(final Object plainValue, final EncryptContext encryptContext) {
+        return null == plainValue ? null : digest(String.valueOf(plainValue));
+    }
+  
+    private String digest(final String plainValue) {
+        StringBuilder result = new StringBuilder(plainValue.length());
+        for (char each : plainValue.toCharArray()) {
+            char maskedChar = getMaskedChar(each);
+            if ('%' == maskedChar) {
+                result.append(each);
+            } else {
+                result.append(maskedChar);
+            }
+        }
+        return result.toString();
+    }
+  
+    private char getMaskedChar(final char originalChar) {
+        if ('%' == originalChar) {
+            return originalChar;
+        }
+        if (originalChar <= MAX_NUMERIC_LETTER_CHAR) {
+            return (char) ((originalChar + delta) & mask);
+        }
+        if (charIndexes.containsKey(originalChar)) {
+            return (char) (((charIndexes.get(originalChar) + delta) & mask) + start);
+        }
+        return (char) (((originalChar + delta) & mask) + start);
+    }
+  
+    @Override
+    public String getType() {
+        return "CHAR_DIGEST_LIKE";
+    }
+}
+```
+
+- Define the binary `mask` code to lose precision `0b1111_0111_1101` (mask).
+- Save common Chinese characters with disrupted order like a `map` dictionary.
+- Obtain a single string of `Unicode` for digits, English, and Latin.
+- Obtain `index` for a Chinese character belonging to a dictionary.
+- Other characters fetch the `Unicode` of a single string.
+- Add `1 (delta)` to the digits obtained by different types above to prevent any original text from appearing in the database.
+- Then convert the offset `Unicode` into binary and perform the `AND` operation with `mask`, and carry out a 2-bit digit loss.
+- Directly output digits, English, and Latin after the loss of precision.
+- The remaining characters are converted to decimal and output with the common character `start` code after the loss of precision.
+
+# **4. The fuzzy algorithm development progress**
+
+## 4.1 The first edition
+
+Simply use `Unicode` and `mask` code of common characters to perform the `AND` operation.
+
+```yaml
+Mask: 0b11111111111001111101
+The original character: 0b1000101110101111讯
+After encryption: 0b1000101000101101設
+Assuming we know the key and encryption algorithm, the original string after a backward pass is:1.0b1000101100101101 謭
+2.0b1000101100101111 謯
+3.0b1000101110101101 训
+4.0b1000101110101111 讯
+5.0b1000101010101101 読
+6.0b1000101010101111 誯
+7.0b1000101000101111 訯
+8.0b1000101000101101 設
+```
+
+We find that based on the missing bits, each string can be derived `2^n` Chinese characters backward. When the `Unicode` of common Chinese characters is decimal, their intervals are very large. Notice that the Chinese characters inferred backward are not common characters, and it's more likely to infer the original characters.
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive2.png)
+
+## 4.2 The second edition
+
+Since the interval of common Chinese characters `Unicode` is irregular, we planned to leave the last few bits of Chinese characters `Unicode` and convert them into decimal as `index` to fetch some common Chinese characters. This way, when the algorithm is known, uncommon characters won't appear after a backward pass, and distractors are no longer easy to eliminate.
+
+If we leave the last few bits of Chinese characters `Unicode`, it has something to do with the relationship between the accuracy of fuzzy query and anti-decryption complexity. The higher the accuracy, the lower the decryption difficulty.
+
+Let's take a look at the collision degree of common Chinese characters under our algorithm:
+
+1. When `mask`=0b0011_1111_1111:
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive3.png)
+
+2. When `mask`=0b0001_1111_1111:
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive4.png)
+
+For the mantissa of Chinese characters, leave 10 and 9 digits. The 10-digit query is more accurate because its collision is much weaker. Nevertheless, if the algorithm and the key are known, the original text of the 1:1 character can be derived backward.
+
+The 9-digit query is less accurate because 9-digit collisions are relatively stronger, but there are fewer 1:1 characters. We find that although we change the collisions regardless of whether we leave 10 or 9 digits, the distribution is very unbalanced due to the irregular Unicode of Chinese characters, and the overall collision probability cannot be controlled.
+
+## 4.3 The third edition
+
+In response to the unevenly distributed problem found in the second edition, we take common characters with disrupted order as the dictionary table.
+
+1. The encrypted text first looks up the `index` in the out-of-order dictionary table. We use the `index` and subscript to replace the `Unicode` without rules.
+
+Use `Unicode` in case of uncommon characters. (Note: evenly distribute the code to be calculated as far as possible.)
+
+2. The next step is to perform the `AND` operation with `mask` and lose 2-bit precision to increase the frequency of collisions.
+
+Let's take a look at the collision degree of common Chinese characters under our algorithm:
+
+1. When `mask`=0b1111_1011_1101:
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive5.png)
+
+2. When `mask`=0b0111_1011_1101:
+
+![img](https://shardingsphere.apache.org/blog/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive6.png)
+
+When the `mask` leaves 11 bits, you can see that the collision distribution is concentrated at 1:4. When `mask` leaves 10 bits, the number becomes 1:8. At this time, we only need to adjust the number of precision losses to control whether the collision is 1:2, 1:4 or 1:8.
+
+If `mask` is selected as 1, and the algorithm and key are known, there will be a 1:1 Chinese character, because what we calculate at this time is the collision degree of common characters. If we add the missing 4 bits before the 16-bit binary of Chinese characters, the situation becomes `2^5=32` cases.
+
+Since we encrypted the whole text, even if the individual character is inferred backwards, there will be little impact on overall security, and it will not cause mass data leaks. At the same time, the premise of backward pass is to know the algorithm, key, `delta` and dictionary, so it's impossible to achieve from the data in the database.
+
+# **5. How to use fuzzy query**
+
+Fuzzy query requires the configuration of `encryptors`(encryption algorithm configuration), `likeQueryColumn` (fuzzy query column name), and `likeQueryEncryptorName`(encryption algorithm name of fuzzy query column ) in the encryption configuration.
+
+Please refer to the following configuration. Add your own sharding algorithm and data source.
+
+```yaml
+dataSources:
+  ds_0:
+    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
+    driverClassName: com.mysql.jdbc.Driver
+    jdbcUrl: jdbc:mysql://127.0.0.1:3306/test?allowPublicKeyRetrieval=true
+    username: root
+    password: root
+    
+rules:
+- !ENCRYPT
+  encryptors:
+    like_encryptor:
+      type: CHAR_DIGEST_LIKE
+    aes_encryptor:
+      type: AES
+      props:
+        aes-key-value: 123456abc
+  tables:
+    user:
+      columns:
+        name:
+          cipherColumn: name
+          encryptorName: aes_encryptor
+          assistedQueryColumn: name_ext
+          assistedQueryEncryptorName: aes_encryptor
+          likeQueryColumn: name_like
+          likeQueryEncryptorName: like_encryptor
+        phone:
+          cipherColumn: phone
+          encryptorName: aes_encryptor
+          likeQueryColumn: phone_like
+          likeQueryEncryptorName: like_encryptor
+  queryWithCipherColumn: true
+
+
+props:
+  sql-show: true
+```
+
+Insert
+
+```sql
+Logic SQL: insert into user ( id, name, phone, sex) values ( 1, '熊高祥', '13012345678', '男')
+Actual SQL: ds_0 ::: insert into user ( id, name, name_ext, name_like, phone, phone_like, sex) values (1, 'gyVPLyhIzDIZaWDwTl3n4g==', 'gyVPLyhIzDIZaWDwTl3n4g==', '佹堝偀', 'qEmE7xRzW0d7EotlOAt6ww==', '04101454589', '男')
+```
+
+Update
+
+```sql
+Logic SQL: update user set name = '熊高祥123', sex = '男1' where sex ='男' and phone like '130%'
+Actual SQL: ds_0 ::: update user set name = 'K22HjufsPPy4rrf4PD046A==', name_ext = 'K22HjufsPPy4rrf4PD046A==', name_like = '佹堝偀014', sex = '男1' where sex ='男' and phone_like like '041%'
+```
+
+Select
+
+```sql
+Logic SQL: select * from user where (id = 1 or phone = '13012345678') and name like '熊%'
+Actual SQL: ds_0 ::: select `user`.`id`, `user`.`name` AS `name`, `user`.`sex`, `user`.`phone` AS `phone`, `user`.`create_time` from user where (id = 1 or phone = 'qEmE7xRzW0d7EotlOAt6ww==') and name_like like '佹%'
+```
+
+Select: federated table sub-query
+
+```sql
+Logic SQL: select * from user LEFT JOIN user_ext on user.id=user_ext.id where user.id in (select id from user where sex = '男' and name like '熊%')
+Actual SQL: ds_0 ::: select `user`.`id`, `user`.`name` AS `name`, `user`.`sex`, `user`.`phone` AS `phone`, `user`.`create_time`, `user_ext`.`id`, `user_ext`.`address` from user LEFT JOIN user_ext on user.id=user_ext.id where user.id in (select id from user where sex = '男' and name_like like '佹%')
+```
+
+Delete
+
+```sql
+Logic SQL: delete from user where sex = '男' and name like '熊%'
+Actual SQL: ds_0 ::: delete from user where sex = '男' and name_like like '佹%'
+```
+
+The above example demonstrates how fuzzy query columns rewrite SQL in different SQL syntaxes to support fuzzy queries.
+
+This blog post introduced you to the working principles of fuzzy query and used specific examples to demonstrate how to use it. We hope that through this article, you will have gained a basic understanding of fuzzy queries.
+
+# Links
+
+🔗 [Download Link](https://shardingsphere.apache.org/document/current/en/downloads/)
+
+🔗 [Project Address](https://shardingsphere.apache.org/)
+
+🔗 [ShardingSphere-on-Cloud](https://github.com/apache/shardingsphere-on-cloud)
+
+# Author
+
+Xiong Gaoxiang, an engineer at [Iflytek](https://global.iflytek.com/) and a ShardingSphere Contributor, is responsible for the data encryption and data masking R&D.
diff --git a/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters1.png b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters1.png
new file mode 100644
index 00000000000..2f510d0671b
Binary files /dev/null and b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters1.png differ
diff --git a/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters2.png b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters2.png
new file mode 100644
index 00000000000..fb4f880a739
Binary files /dev/null and b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters2.png differ
diff --git a/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters3.png b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters3.png
new file mode 100644
index 00000000000..e7c604cc106
Binary files /dev/null and b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters3.png differ
diff --git a/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters4.png b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters4.png
new file mode 100644
index 00000000000..725d745c260
Binary files /dev/null and b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters4.png differ
diff --git a/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters5.png b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters5.png
new file mode 100644
index 00000000000..4c241945904
Binary files /dev/null and b/docs/blog/static/img/2022_12_13_Use_AWS_CloudFormation_to_create_ShardingSphere_HA_clusters5.png differ
diff --git a/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive1.png b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive1.png
new file mode 100644
index 00000000000..113220bec1a
Binary files /dev/null and b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive1.png differ
diff --git a/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive2.png b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive2.png
new file mode 100644
index 00000000000..a9c6bac5976
Binary files /dev/null and b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive2.png differ
diff --git a/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive3.png b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive3.png
new file mode 100644
index 00000000000..206aea96e6f
Binary files /dev/null and b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive3.png differ
diff --git a/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive4.png b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive4.png
new file mode 100644
index 00000000000..cdb227e4356
Binary files /dev/null and b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive4.png differ
diff --git a/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive5.png b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive5.png
new file mode 100644
index 00000000000..f65f30ddc2e
Binary files /dev/null and b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive5.png differ
diff --git a/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive6.png b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive6.png
new file mode 100644
index 00000000000..6c0c178f09b
Binary files /dev/null and b/docs/blog/static/img/2022_12_28_Fuzzy_query_for_CipherColumn__ShardingSphere_5.3.0_Deep_Dive6.png differ