“This is the fifth day of my participation in the More Text Challenge. For details, see more text Challenge.”

preface

Redis install and boot from the integration of springBoot combat, install Redis.

Why create a Redis distributed cluster? Redis is deployed with a stand-alone version, one master and multiple slave + sentry. Stand-alone version of needless to say, the node hung directly unavailable. One Master, multiple Slave + sentry, usually used as read/write separation, and the existence of sentry can select another Slave as the new Master if the Master is not available so that the cluster can continue to provide services.

In a Master and Slave architecture, the Slave is just a copy of the Master, and a Key exists on the Master and all the slaves. In the case of many keys, there is not enough storage, of course, you can increase the memory of the machine.

Redis provides a Cluster mode, which can horizontally scale the storage of keys.

Server Planning

Server:

  • 192.168.79.120

  • 192.168.79.121

  • 192.168.79.122

  • 192.168.79.123

  • 192.168.79.124

  • 192.168.79.125

The configuration file

The modifications above the default are the same for each device

Bind 0.0.0.0 dir "/usr/local/redis/db" requirepass "root1234" cluster-enabled yes cluster-config-file nodes-6379.conf cluster-node-timeout 5000appendonly yesCopy the code

Create the cluster

Prior to Redis5, Redis clusters were created using A Ruby script, i.e. a Ruby environment, but after Redis5, Redis clusters can be created using the redis-CLI. The following command:

Redis -cli -a root1234 --cluster create 192.168.79.120:6379 192.168.79.121:6379 192.168.79.122:6379 192.168.79.122:6379 192.168.79.123:6379 192.168.79.125 192.168.79.124:6379:6379 - cluster - replicas of 1Copy the code

Enter yes to create a three-master and three-slave cluster. –cluster-replicas 1 indicates that each master has one slave. Six is just right.

>>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 192.168.79.124:6379 to 192.168.79.120:6379 Adding Replica 192.168.79.125:6379 to 192.168.79.121:6379 Adding replica 192.168.79.123:6379 to 192.168.79.122:6379 M: Fc45e8b102f1e3d689d1ca194593dc801689f28c 192.168.79.120:6379 slots: [0-5460] (5461 slots) master M: 6 e6c3a530610c2e319e531ed6ba14a8a42ba5fe8 192.168.79.121:6379 slots: [5461-10922] (5462 slots) master M: 3 cac41b0e8da1182f413ec2590430856fddab153 192.168.79.122:6379 slots: [10923-16383] (5461 slots) master S: B911d342eb181c2dee04f4bb49ead2246e58b070 192.168.79.123:6379 3 replicates cac41b0e8da1182f413ec2590430856fddab153 S: Be51a450c46fa33670f8a83e502ae5ead8d0e84b 192.168.79.124:6379 replicates fc45e8b102f1e3d689d1ca194593dc801689f28c S: 05724 a6a68f7f24ac74e07900db269c136410fd3 192.168.79.125:6379 6 replicates e6c3a530610c2e319e531ed6ba14a8a42ba5fe8 Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join .. >>> Performing Cluster Check (using node 192.168.79.120:6379) M: Fc45e8b102f1e3d689d1ca194593dc801689f28c 192.168.79.120:6379 slots: [0-5460] (5461 slots) master 1 additional up (s) S: b911d342eb181c2dee04f4bb49ead2246e58b070 192.168.79.123:6379 slots: (0 slots) slave replicates 3cac41b0e8da1182f413ec2590430856fddab153 S: 05724 a6a68f7f24ac74e07900db269c136410fd3 192.168.79.125:6379 slots: (0 slots) slave replicates 6e6c3a530610c2e319e531ed6ba14a8a42ba5fe8 M: 6 e6c3a530610c2e319e531ed6ba14a8a42ba5fe8 192.168.79.121:6379 slots: [5461-10922] (5462 slots) 1 additional master Up (s) s: be51a450c46fa33670f8a83e502ae5ead8d0e84b 192.168.79.124:6379 slots: (0 slots) slave replicates fc45e8b102f1e3d689d1ca194593dc801689f28c M: 3 cac41b0e8da1182f413ec2590430856fddab153 192.168.79.122:6379 slots: [10923-16383] (5461 slots) 1 additional master replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.Copy the code

As you can see from the output date above, it is possible to create three masters and three slaves, with a total of 16284 slots allocated. Master and Slave are assigned by Redis.

Run the following command to check any node:

Redis -cli -a root1234 --cluster check 192.168.79.120:6379 192.168.79.120:6379 (fc45e8b1...) - > 0 keys 5461 slots | | 1 slaves. 192.168.79.121:6379 (six e6c3a53...). - > 0 keys 5462 slots | | 1 slaves. 192.168.79.122:6379 (3 cac41b0...). 5461 slots - > 0 keys | | 1 slaves. [OK] 0 keys in 3 masters. 0.00 keys per slot on business.>>> Performing Cluster Check (using node 192.168.79.120:6379)M: Fc45e8b102f1e3d689d1ca194593dc801689f28c 192.168.79.120:6379 slots: [0-5460] (5461 slots) master 1 additional up (s) S: b911d342eb181c2dee04f4bb49ead2246e58b070 192.168.79.123:6379 slots: (0 slots) slave replicates 3cac41b0e8da1182f413ec2590430856fddab153 S: 05724 a6a68f7f24ac74e07900db269c136410fd3 192.168.79.125:6379 slots: (0 slots) slave replicates 6e6c3a530610c2e319e531ed6ba14a8a42ba5fe8 M: 6 e6c3a530610c2e319e531ed6ba14a8a42ba5fe8 192.168.79.121:6379 slots: [5461-10922] (5462 slots) 1 additional master Up (s) s: be51a450c46fa33670f8a83e502ae5ead8d0e84b 192.168.79.124:6379 slots: (0 slots) slave replicates fc45e8b102f1e3d689d1ca194593dc801689f28c M: 3 cac41b0e8da1182f413ec2590430856fddab153 192.168.79.122:6379 slots: [10923-16383] (5461 slots) 1 additional master replica(s) [OK] All nodes agree about slots configuration.>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
Copy the code

By checking, we can clearly know the relationship between the Redis instances in the Redis Cluster.

About slots in the Redis Cluster

For a key, the CRC algorithm in Redis is used to calculate which Slot a key belongs to. In the example above, a total of 16,384 slots are evenly allocated to three masters (slaves do not allocate slots), and only one of each Key will exist in the cluster.

When inserting a Key into A Redis Cluuster, use CRC16(Key) mod 16384 to mod it, if: run Redis command, SET test 123. It will execute crc16(test)=63534, then mod mod, 63534%16384=14382, resulting in 14382. Since 10923-16383 is on 192.168.79.122:6379, the test key will be stored on the Redis instance at 192.168.79.122:6379.

SpringBoot integration, connected to Redis Cluster

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
Copy the code

The configuration file

spring:
  redis:
    cluster:
      nodes: 192.16879.120.: 6379192168 79.121:6379192168 79.122:6379192168, 79.123, 6379192168, 79.124, 6379192168, 79.125, 6379
    password: root1234
Copy the code

Redis general utility class

@Component
public class RedisUtil {

    private final StringRedisTemplate redisTemplate;

    public RedisUtil(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // Key is a simple key-value operation

    /** * Implementation command: TTL key, in seconds, returns the TTL (time to live) of a given key. * *@param key
     * @return* /
    public long ttl(String key) {
        return redisTemplate.getExpire(key);
    }

    /** * Implementation command: expire sets the expiration time in seconds **@param key
     * @return* /
    public void expire(String key, long timeout) {
        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /** * implement command: INCR key, add key once **@param key
     * @return* /
    public long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /** * Implements the command: KEYS pattern to find all KEYS */ that match the given pattern
    public Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /** * implement command: DEL key, delete a key **@param key
     */
    public void del(String key) {
        redisTemplate.delete(key);
    }

    // String (String)

    /** * Implement command: SET key value, SET a key-value (string value associated with key) **@param key
     * @param value
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /** * Implement command: SET key value EX seconds, SET key-value and timeout (seconds) **@param key
     * @param value
     * @paramTimeout (in seconds) */
    public void set(String key, String value, long timeout) {
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /** * implement the command: GET key, return the string value associated with the key. * *@param key
     * @return value
     */
    public String get(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    /** * Batch query, corresponding to mget **@param keys
     * @return* /
    public List<String> mget(List<String> keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    /** * query, pipeline **@param keys
     * @return* /
    public List<Object> batchGet(List<String> keys) {

// nginx -> keepalive
// redis -> pipeline

        List<Object> result = redisTemplate.executePipelined(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                StringRedisConnection src = (StringRedisConnection) connection;

                for (String k : keys) {
                    src.get(k);
                }
                return null; }});return result;
    }


    // Hash table

    /** * implement command: HSET key field value; set the value of field in the hash table key to value **@param key
     * @param field
     * @param value
     */
    public void hset(String key, String field, Object value) {
        redisTemplate.opsForHash().put(key, field, value);
    }

    /** * implement command: HGET key field, return the value of the given field in the hash table key **@param key
     * @param field
     * @return* /
    public String hget(String key, String field) {
        return (String) redisTemplate.opsForHash().get(key, field);
    }

    /** * implement command: HDEL key field [field... , delete one or more specified fields in the key of the hash table. Non-existent fields are ignored. * *@param key
     * @param fields
     */
    public void hdel(String key, Object... fields) {
        redisTemplate.opsForHash().delete(key, fields);
    }

    /** * implement command: HGETALL key, return hash table key, all fields and values. * *@param key
     * @return* /
    public Map<Object, Object> hgetall(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    // List (List)

    /** * implement command: LPUSH key value, insert value into the list key header **@param key
     * @param value
     * @returnThe length of the list after the LPUSH command is executed. * /
    public long lpush(String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /** * implement command: LPOP key, remove and return the header element of list key. * *@param key
     * @returnThe header element of the list key. * /
    public String lpop(String key) {
        return (String) redisTemplate.opsForList().leftPop(key);
    }

    /** * implement command: RPUSH key value, insert a value to the end of the list key (rightmost). * *@param key
     * @param value
     * @returnThe length of the list after the LPUSH command is executed. * /
    public long rpush(String key, String value) {
        returnredisTemplate.opsForList().rightPush(key, value); }}Copy the code

Control layer for testing

@RestController
@RequestMapping("test")
public class TestRedisController {

    @Autowired
    private RedisUtil redisUtil;

    @GetMapping("add")
    public void add(@RequestParam("key") String key, @RequestParam("value") String value) {
        redisUtil.set(key, value);
    }

    @GetMapping("list")
    public Object listAllKeys(a) {
        Set<String> keys = redisUtil.keys("*");
        HashMap<String, Object> map = new HashMap<>();
        for (String key : keys) {
            String value = redisUtil.get(key);
            map.put(key, value);
        }
        returnmap; }}Copy the code

Start the class

@SpringBootApplication
public class RedisApplication {

    public static void main(String[] args) { SpringApplication.run(RedisApplication.class, args); }}Copy the code

test

Running the startup class

Send a GET request

http://localhost; 8080/test/add? key=age&value=18

http://localhost; 8080/test/add? key=name&value=tom

http://localhost; 8080/test/list