Skip to content

Commit

Permalink
Sharding Pattern (#1056)
Browse files Browse the repository at this point in the history
* Create sharding module

* Add Unit Tests

* Fix readme hyperlink

* Fix check-style issue
  • Loading branch information
Azureyjt authored and iluwatar committed Nov 8, 2019
1 parent 50986fa commit 1fa8a60
Show file tree
Hide file tree
Showing 16 changed files with 1,010 additions and 0 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
<module>subclass-sandbox</module>
<module>circuit-breaker</module>
<module>double-buffer</module>
<module>sharding</module>
</modules>

<repositories>
Expand Down
27 changes: 27 additions & 0 deletions sharding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

---
layout: pattern
title: Sharding
folder: sharding
permalink: /patterns/sharding/
categories: Other
tags:
- Java
- Difficulty-Beginner
---

## Intent
Sharding pattern means divide the data store into horizontal partitions or shards. Each shard has the same schema, but holds its own distinct subset of the data.
A shard is a data store in its own right (it can contain the data for many entities of different types), running on a server acting as a storage node.

## Applicability
This pattern offers the following benefits:

- You can scale the system out by adding further shards running on additional storage nodes.
- A system can use off the shelf commodity hardware rather than specialized (and expensive) computers for each storage node.
- You can reduce contention and improved performance by balancing the workload across shards.
- In the cloud, shards can be located physically close to the users that will access the data.

## Credits

* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications - Sharding Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589797(v=pandp.10)?redirectedfrom=MSDN)
45 changes: 45 additions & 0 deletions sharding/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright © 2014-2019 Ilkka Seppälä
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.22.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sharding</artifactId>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>

</project>
88 changes: 88 additions & 0 deletions sharding/src/main/java/com/iluwatar/sharding/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.iluwatar.sharding;

/**
* Sharding pattern means dividing a data store into a set of horizontal partitions
* or shards. This pattern can improve scalability when storing and accessing large
* volumes of data.
*/
public class App {

/**
* Program main entry point.
* @param args program runtime arguments
*/
public static void main(String[] args) {

var data1 = new Data(1, "data1", Data.DataType.type1);
var data2 = new Data(2, "data2", Data.DataType.type2);
var data3 = new Data(3, "data3", Data.DataType.type3);
var data4 = new Data(4, "data4", Data.DataType.type1);

var shard1 = new Shard(1);
var shard2 = new Shard(2);
var shard3 = new Shard(3);

ShardManager manager = new LookupShardManager();
manager.addNewShard(shard1);
manager.addNewShard(shard2);
manager.addNewShard(shard3);
manager.storeData(data1);
manager.storeData(data2);
manager.storeData(data3);
manager.storeData(data4);

shard1.clearData();
shard2.clearData();
shard3.clearData();

manager = new RangeShardManager();
manager.addNewShard(shard1);
manager.addNewShard(shard2);
manager.addNewShard(shard3);
manager.storeData(data1);
manager.storeData(data2);
manager.storeData(data3);
manager.storeData(data4);

shard1.clearData();
shard2.clearData();
shard3.clearData();

manager = new HashShardManager();
manager.addNewShard(shard1);
manager.addNewShard(shard2);
manager.addNewShard(shard3);
manager.storeData(data1);
manager.storeData(data2);
manager.storeData(data3);
manager.storeData(data4);

shard1.clearData();
shard2.clearData();
shard3.clearData();
}

}
84 changes: 84 additions & 0 deletions sharding/src/main/java/com/iluwatar/sharding/Data.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.iluwatar.sharding;

/**
* Basic data structure for each tuple stored in data shards.
*/
public class Data {

private int key;

private String value;

private DataType type;

/**
* Constructor of Data class.
* @param key data key
* @param value data vlue
* @param type data type
*/
public Data(final int key, final String value, final DataType type) {
this.key = key;
this.value = value;
this.type = type;
}

public int getKey() {
return key;
}

public void setKey(final int key) {
this.key = key;
}

public String getValue() {
return value;
}

public void setValue(final String value) {
this.value = value;
}

public DataType getType() {
return type;
}

public void setType(DataType type) {
this.type = type;
}

enum DataType {
type1, type2, type3
}

@Override
public String toString() {
return "Data {" + "key="
+ key + ", value='" + value
+ '\'' + ", type=" + type + '}';
}
}

55 changes: 55 additions & 0 deletions sharding/src/main/java/com/iluwatar/sharding/HashShardManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.iluwatar.sharding;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* ShardManager with hash strategy. The purpose of this strategy is to reduce the
* chance of hot-spots in the data. It aims to distribute the data across the shards
* in a way that achieves a balance between the size of each shard and the average
* load that each shard will encounter.
*/
public class HashShardManager extends ShardManager {

private static final Logger LOGGER = LoggerFactory.getLogger(HashShardManager.class);

@Override
public int storeData(Data data) {
var shardId = allocateShard(data);
var shard = shardMap.get(shardId);
shard.storeData(data);
LOGGER.info(data.toString() + " is stored in Shard " + shardId);
return shardId;
}

@Override
protected int allocateShard(Data data) {
var shardCount = shardMap.size();
var hash = data.getKey() % shardCount;
return hash == 0 ? hash + shardCount : hash;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.iluwatar.sharding;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* ShardManager with lookup strategy. In this strategy the sharding logic implements
* a map that routes a request for data to the shard that contains that data by using
* the shard key.
*/
public class LookupShardManager extends ShardManager {

private static final Logger LOGGER = LoggerFactory.getLogger(LookupShardManager.class);

private Map<Integer, Integer> lookupMap = new HashMap<>();

@Override
public int storeData(Data data) {
var shardId = allocateShard(data);
lookupMap.put(data.getKey(), shardId);
var shard = shardMap.get(shardId);
shard.storeData(data);
LOGGER.info(data.toString() + " is stored in Shard " + shardId);
return shardId;
}

@Override
protected int allocateShard(Data data) {
var key = data.getKey();
if (lookupMap.containsKey(key)) {
return lookupMap.get(key);
} else {
var shardCount = shardMap.size();
var allocatedShardId = new Random().nextInt(shardCount - 1) + 1;
return allocatedShardId;
}
}

}

0 comments on commit 1fa8a60

Please sign in to comment.