分布式架构概述

本阶段规划

  • 分布式中间件 Redis
  • 分布式会话与单点登录
  • 分布式搜索引擎Elasticsearch
  • 分布式文件系统
  • 数据库的读写分离与分库分表
  • 数据库表全局唯一主键id设计
  • 分布式事务与数据一致性
  • 接口幂等性设计与分布式限流

什么是分布式架构

  • 不同的业务(功能模块)分散部署在不同的服务器
    • 购物车服务、订单服务、商品服务
  • 每个子系统负责一个或多个不同的业务模块
    • 购物车模块,专门负责购物车相关业务
    • 优惠券模块,专门负责优惠券相关业务
  • 服务之间可以相互交互与通信
    • 能发请求给到其他服务
    • 自身服务也能接受到其他服务发送的请求
  • 分布式系统设计对用户透明
  • 可以发展成为集群分布式系统架构

    • 购物车集群、订单集群

    单体架构
    一个人负责制造所有的汽车组件
    image.png

    分布式架构

    每个人单独负责对应的汽车组件
    image.png

分布式架构优点

  • 业务解耦
  • 系统模块化、可重用化
  • 提升系统并发量
  • 优化运维部署效率
  • 架构复杂
  • 部署多个子系统复杂
  • 系统之间耗时

分布式架构缺点

  • 新人融合团队缓慢
  • 调试复杂

设计原则

  • 异步解耦
  • 幂等一致性
  • 拆分原则
  • 融合分布式中间件
  • 容错高可用

Redis 安装

1、下载

https://redis.io/download/
选择文档版本进行下载
上传至 Linux 中
image.png

1、解压 redis
  1. tar -zxvf redis-5.0.5.tar.gz

2、安装gcc编译环境,如果已经安装过,则是nothing todo
  1. yum install gcc-c++

3、进入 redis 目录中,进行安装
  1. make && make install

4、在原 redis 文件中的 utils 目录下 拷贝 redis_init_script 到 /etc/init.d 目录,目的要把 redis 作为开机启动

拷贝到 /etc 目录后需要设置文件权限

  1. chmod redis_init_script 777
  1. #!/bin/sh
  2. #
  3. # Simple Redis init.d script conceived to work on Linux systems
  4. # as it does use of the /proc filesystem.
  5. ### BEGIN INIT INFO
  6. # Provides: redis_6379
  7. # Default-Start: 2 3 4 5
  8. # Default-Stop: 0 1 6
  9. # Short-Description: Redis data structure server
  10. # Description: Redis data structure server. See https://redis.io
  11. ### END INIT INFO
  12. #chkconfig: 22345 10 90
  13. #description: Start and Stop redis # 开机自启动
  14. REDISPORT=6379 # redis 端口
  15. EXEC=/usr/local/bin/redis-server # redis 服务器
  16. CLIEXEC=/usr/local/bin/redis-cli # redis 命令
  17. PIDFILE=/var/run/redis_${REDISPORT}.pid # pid
  18. CONF="/usr/local/redis/redis.conf" # 指定redis配置文件地址

设置开机自启动

  1. chkconfig redis_init_script on

2、redis相关命令

  1. redis-cli -a password shutdown :关闭redis
  2. ./redis_init_script stop :关闭redis start : 启动redis
  3. redis-cli :进入到redis客户端
  4. auth pwd :输入密码
  5. redis-cli -a password ping :查看是否存活

3、redis.conf 更改

  1. # By default Redis does not run as a daemon. Use 'yes' if you need it.
  2. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
  3. daemonize yes
  4. # 前台运行还是后台运行
  5. # The working directory.
  6. #
  7. # The DB will be written inside this directory, with the filename specified
  8. # above using the 'dbfilename' configuration directive.
  9. #
  10. # The Append Only File will also be created inside this directory.
  11. #
  12. # Note that you must specify a directory here, not a file name.
  13. dir /usr/local/redis/working
  14. # 工作空间
  15. #
  16. # IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
  17. # JUST COMMENT THE FOLLOWING LINE.
  18. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  19. #bind 127.0.0.1
  20. bind 0.0.0.0
  21. # 想要被外部进行访问 需要更改为0.0.0.0 上线后更改为127
  22. # Warning: since Redis is pretty fast an outside user can try up to
  23. # 150k passwords per second against a good box. This means that you should
  24. # use a very strong password otherwise it will be very easy to break.
  25. #
  26. # redis 链接密码
  27. requirepass 123456

image.png


为何引 Redis

现有架构弊端

请求都是直接访问到数据库中,请求量一大,数据库压力倍增,因此需要引入 redis 作为缓存
image.png

举例

动物与管理员
需要知道动物园有多少个动物,只需要通过已经记录好的笔记查看,不需要一头一头去数
image.png

什么是 NoSQL

  • Not Only Sql
  • 传统项目使用纯数据库
  • 为互联网和大数据而生
  • 水平(横向)扩展方便高效
  • 高性能
  • 高可用
  • 存数据,做缓存

NoSql的常见分类

键值对数据库 Redis、Memcache
列存储数据库 Hbase、Cassandra
文档型数据库 MongoDB、CouchDB
图形数据库 Neo4J、FlockDB

什么是分布式缓存

  • 提升读取速度性能
  • 分布式计算领域
  • 为数据库降低查询压力
  • 跨服务器缓存
  • 内存式缓存

    什么是Redis

    提供海量数据存储访问
    数据存储在内存里、读取快
    非关系型、分布式、开源、水平扩展

Redis的发布与订阅

可以理解为微信和微信公众号之间的关系,使用较少

Redis的持久化机制

1、RDB

每隔一段时间,把内存中的数据写入磁盘的临时文件,作为快照,恢复的时候把快照文件读进内存。如果宕机重启,那么内存里的数据肯定会没有的,那 redis 重启后,则会恢复。

2、备份与恢复

内存备份 —> 磁盘临时文件
临时文件 —> 恢复到内存

3、RDB优劣势

优势

  • 每隔一段时间备份,全量备份
  • 灾备简单,可以远程传输
  • 子进程备份的时候,主进程不会有任何io操作(不会有写入修改或删除),保证备份数据的的完整性
  • 相对AOF来说,当有更大文件的时候可以快速重启恢复

劣势

  • 发生故障是,有可能会丢失最后一次的备份数据
  • 子进程所占用的内存比会和父进程一模一样,如会造成CPU负担
  • 由于定时全量备份是重量级操作,所以对于实时备份,就无法处理了。
    4、RDB配置
    1. 保存位置,可以在redis.conf自定义:
    /user/local/redis/working/dump.rdb
    2. 保存机制:
    1. save 900 1
    2. save 300 10
    3. save 60 10000
    4. save 10 3
    ```shell
  • 如果1个缓存更新,则15分钟后备份
  • 如果10个缓存更新,则5分钟后备份
  • 如果10000个缓存更新,则1分钟后备份
  • 演示:更新3个缓存,10秒后备份
  • 演示:备份dump.rdb,删除重启 ```

1. stop-writes-on-bgsave-error

yes:如果save过程出错,则停止写操作
no:可能造成数据不一致

2. rdbcompression

yes:开启rdb压缩模式
no:关闭,会节约cpu损耗,但是文件会大,道理同nginx

3. rdbchecksum

AOF

引子

RDB会丢失最后一次备份的rdb文件,但是其实也无所谓,其实也可以忽略不计,毕竟是缓存,丢了就丢了,但是如果追求数据的完整性,那就的考虑使用AOF了

AOF特点
  • 以日志的形式来记录用户请求的写操作。读操作不会记录,因为写操作才会存存储。
  • 文件以追加的形式而不是修改的形式。
  • redis的aof恢复其实就是把追加的文件从开始到结尾读取执行写操作。

    优势
  • AOF更加耐用,可以以秒级别为单位备份,如果发生问题,也只会丢失最后一秒的数据,大大增加了可靠性和数据完整性。所以AOF可

  • 一次,使用fsync操作。
  • 以log日志形式追加,如果磁盘满了,会执行 redis-check-aof 工具
  • 当数据太大的时候,redis可以在后台自动重写aof。当redis继续把日志追加到老的文件中去时,重写也是非常安全的,不会影响客户端作。
  • AOF 日志包含的所有写操作,会更加便于redis的解析恢复。

    劣势
  • 相同的数据,同一份数据,AOF比RDB大

  • 针对不同的同步机制,AOF会比RDB慢,因为AOF每秒都会备份做写操作,这样相对与RDB来说就略低。 每秒备份fsync没毛病,但是xx的每次写入就做一次备份fsync的话,那么redis的性能就会下降。
  • AOF发生过bug,就是数据恢复的时候数据不完整,这样显得AOF会比较脆弱,容易出现bug,因AOF没有RDB那么简单,但是呢为能防止错误的的产生,AOF就不会根据旧的指令去重构,而是根据当时缓存中存在的数据指令去做重构,这样就更加健壮和可靠了。
    AOF的配置
    ```shell

    AOF 默认关闭,yes可以开启

    appendonly no

AOF 的文件名

appendfilename “appendonly.aof”

no:不同步

everysec:每秒备份,推荐使用

always:每次操作都会备份,安全并且数据完整,但是慢性能差

appendfsync everysec

重写的时候是否要同步,no可以保证数据安全

no-appendfsync-on-rewrite no

重写机制:避免文件越来越大,自动优化压缩指令,会fork一个新的进程去完成重写动作,新进程里的内存数据会被重写,此时

当前AOF文件的大小是上次AOF大小的100% 并且文件体积达到64m,满足两者则触发重写

auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb

  1. <a name="Ijrp1"></a>
  2. ##### 到底采用RDB还是AOF呢?
  3. 1. 如果你能接受一段时间的缓存丢失,那么可以使用RDB <br />2. 如果你对实时性的数据比较care,那么就用AOF
  4. ---
  5. <a name="UzaJI"></a>
  6. ### **Redis 缓存过期处理与内存淘汰机制**
  7. <a name="gWxts"></a>
  8. #### 引子
  9. 计算机内存有限,越大越贵,Redis的高并发高性能都是基于内存的,用硬盘的话GG。
  10. <a name="XOCFA"></a>
  11. #### 已过期的key如何处理?
  12. 设置了expire的key缓存过期了,但是服务器的内存还是会被占用,这是因为redis所基于的两种删除策略 <br />redis有两种策略: <br />1、(主动)定时删除 <br />定时随机的检查过期的key,如果过期则清理删除。(每秒检查次数在redis.conf中的hz配置) <br />2、(被动)惰性删除 <br />当客户端请求一个已经过期的key的时候,那么redis会检查这个key是否过期,如果过期了,则删除,然后返回一个nil。这种策略 友好,不会有太多的损耗,但是内存占用会比较高。 所以,虽然key过期了,但是只要没有被redis清理,那么其实内存还是会被占用着的。
  13. <a name="sqWvy"></a>
  14. #### 那么如果内存被Redis缓存占用慢了咋办?
  15. 内存占满了,可以使用硬盘,来保存,但是没意义,因为硬盘没有内存快,会影响redis性能。 <br />所以,当内存占用满了以后,redis提供了一套缓存淘汰机制:MEMORY MANAGEMENT <br />maxmemory :当内存已使用率到达,则开始清理缓存
  16. ```shell
  17. * noeviction:旧缓存永不过期,新缓存设置不了,返回错误
  18. * allkeys-lru:清除最少用的旧缓存,然后保存新的缓存(推荐使用)
  19. * allkeys-random:在所有的缓存中随机删除(不推荐)
  20. * volatile-lru:在那些设置了expire过期时间的缓存中,清除最少用的旧缓存,然后保存新的缓存
  21. * volatile-random:在那些设置了expire过期时间的缓存中,随机删除缓存
  22. * volatile-ttl:在那些设置了expire过期时间的缓存中,删除即将过期的

主从架构原理

一主一从
一主多从

搭建Redis主从复制

1、准备三台带有redis环境的主机(redis版本一致

2、 更改Redis.conf

  1. ################################# REPLICATION #################################
  2. # 主从复制
  3. # Master-Replica replication. Use replicaof to make a Redis instance a copy of
  4. # another Redis server. A few things to understand ASAP about Redis replication.
  5. #
  6. # +------------------+ +---------------+
  7. # | Master | ---> | Replica |
  8. # | (receive writes) | | (exact copy) |
  9. # +------------------+ +---------------+
  10. #
  11. # 1) Redis replication is asynchronous, but you can configure a master to
  12. # stop accepting writes if it appears to be not connected with at least
  13. # a given number of replicas.
  14. # 2) Redis replicas are able to perform a partial resynchronization with the
  15. # master if the replication link is lost for a relatively small amount of
  16. # time. You may want to configure the replication backlog size (see the next
  17. # sections of this file) with a sensible value depending on your needs.
  18. # 3) Replication is automatic and does not need user intervention. After a
  19. # network partition replicas automatically try to reconnect to masters
  20. # and resynchronize with them.
  21. #
  22. # replicaof <masterip> <masterport>
  23. # 配置主节点 ip 以及端口
  24. # replicaof 129.168.128.128 6379
  25. # If the master is password protected (using the "requirepass" configuration
  26. # directive below) it is possible to tell the replica to authenticate before
  27. # starting the replication synchronization process, otherwise the master will
  28. # refuse the replica request.
  29. #
  30. # masterauth <master-password>
  31. # master 主节点密码
  32. # When a replica loses its connection with the master, or when the replication
  33. # is still in progress, the replica can act in two different ways:
  34. #
  35. # 1) if replica-serve-stale-data is set to 'yes' (the default) the replica will
  36. # still reply to client requests, possibly with out of date data, or the
  37. # data set may just be empty if this is the first synchronization.
  38. #
  39. # 2) if replica-serve-stale-data is set to 'no' the replica will reply with
  40. # an error "SYNC with master in progress" to all the kind of commands
  41. # but to INFO, replicaOF, AUTH, PING, SHUTDOWN, REPLCONF, ROLE, CONFIG,
  42. # SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB,
  43. # COMMAND, POST, HOST: and LATENCY.
  44. #
  45. replica-serve-stale-data yes

相关命令

  1. info replication # 查看redis主从信息
  2. # Replication
  3. role:master # 当前是主节点
  4. connected_slaves:0 # 从节点数量
  5. master_replid:5b6ff656b828c42428e7ec3f777d13055d55e495 # master节点id,用于区分节点
  6. master_replid2:0000000000000000000000000000000000000000
  7. master_repl_offset:0
  8. second_repl_offset:-1
  9. repl_backlog_active:0
  10. repl_backlog_size:1048576
  11. repl_backlog_first_byte_offset:0
  12. repl_backlog_histlen:0

无磁盘复制原理解析

从内存中写入另一个内存,基于网络
默认是关闭
缺点:
机械硬盘读取满

开启

  1. # 无磁盘复制
  2. # Replication SYNC strategy: disk or socket.
  3. #
  4. # -------------------------------------------------------
  5. # WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY
  6. # -------------------------------------------------------
  7. #
  8. # New replicas and reconnecting replicas that are not able to continue the replication
  9. # process just receiving differences, need to do what is called a "full
  10. # synchronization". An RDB file is transmitted from the master to the replicas.
  11. # The transmission can happen in two different ways:
  12. # #
  13. # 1) Disk-backed: The Redis master creates a new process that writes the RDB
  14. # file on disk. Later the file is transferred by the parent
  15. # process to the replicas incrementally.
  16. # 2) Diskless: The Redis master creates a new process that directly writes the
  17. # RDB file to replica sockets, without touching the disk at all.
  18. #
  19. # With disk-backed replication, while the RDB file is generated, more replicas
  20. # can be queued and served with the RDB file as soon as the current child producing
  21. # the RDB file finishes its work. With diskless replication instead once
  22. # the transfer starts, new replicas arriving will be queued and a new transfer
  23. # will start when the current one terminates.
  24. #
  25. # When diskless replication is used, the master waits a configurable amount of
  26. # time (in seconds) before starting the transfer in the hope that multiple replicas
  27. # will arrive and the transfer can be parallelized.
  28. #
  29. # With slow disks and fast (large bandwidth) networks, diskless replication
  30. # works better.
  31. repl-diskless-sync no
  32. # 默认是关闭的 磁盘较慢不建议使用
  33. # When diskless replication is enabled, it is possible to configure the delay
  34. # the server waits in order to spawn the child that transfers the RDB via socket
  35. # to the replicas.
  36. #
  37. # This is important since once the transfer starts, it is not possible to serve
  38. # new replicas arriving, that will be queued for the next RDB transfer, so the server
  39. # waits a delay in order to let more replicas arrive.
  40. #
  41. # The delay is specified in seconds, and by default is 5 seconds. To disable
  42. # it entirely just set it to 0 seconds and the transfer will start ASAP.
  43. repl-diskless-sync-delay 5
  44. # 等待时间
  45. #
  46. # Replicas send PINGs to server in a predefined interval. It's possible to change
  47. # this interval with the repl_ping_replica_period option. The default value is 10
  48. # seconds.
  49. #
  50. # repl-ping-replica-period 10
  51. # When diskless replication is enabled, it is possible to configure the delay
  52. # the server waits in order to spawn the child that transfers the RDB via socket
  53. # to the replicas.
  54. #
  55. # This is important since once the transfer starts, it is not possible to serve
  56. # new replicas arriving, that will be queued for the next RDB transfer, so the server
  57. # waits a delay in order to let more replicas arrive.
  58. #
  59. # The delay is specified in seconds, and by default is 5 seconds. To disable
  60. # it entirely just set it to 0 seconds and the transfer will start ASAP.
  61. repl-diskless-sync-delay 5
  62. # 等待时间
  63. #

Redis缓存过期机制

定期删除-主动

惰性删除-被动

内存淘汰管理机制

MEMORY MANAGEMENT

MAX_MEMORY

  1. ############################## MEMORY MANAGEMENT ################################
  2. # Set a memory usage limit to the specified amount of bytes.
  3. # When the memory limit is reached Redis will try to remove keys
  4. # according to the eviction policy selected (see maxmemory-policy).
  5. #
  6. # If Redis can't remove keys according to the policy, or if the policy is
  7. # set to 'noeviction', Redis will start to reply with errors to commands
  8. # that would use more memory, like SET, LPUSH, and so on, and will continue
  9. # to reply to read-only commands like GET.
  10. #
  11. # This option is usually useful when using Redis as an LRU or LFU cache, or to
  12. # set a hard memory limit for an instance (using the 'noeviction' policy).
  13. #
  14. # WARNING: If you have replicas attached to an instance with maxmemory on,
  15. # the size of the output buffers needed to feed the replicas are subtracted
  16. # from the used memory count, so that network problems / resyncs will
  17. # not trigger a loop where keys are evicted, and in turn the output
  18. # buffer of replicas is full with DELs of keys evicted triggering the deletion
  19. # of more keys, and so forth until the database is completely emptied.
  20. #
  21. # In short... if you have replicas attached it is suggested that you set a lower
  22. # limit for maxmemory so that there is some free RAM on the system for replica
  23. # output buffers (but this is not needed if the policy is 'noeviction').
  24. #
  25. # maxmemory <bytes>
  26. # 最大内存
  27. # MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
  28. # is reached. You can select among five behaviors:
  29. #
  30. # 缓存过期机制
  31. # volatile-lru -> Evict using approximated LRU among the keys with an expire set.
  32. # allkeys-lru -> Evict any key using approximated LRU.
  33. # volatile-lfu -> Evict using approximated LFU among the keys with an expire set.
  34. # allkeys-lfu -> Evict any key using approximated LFU.
  35. # volatile-random -> Remove a random key among the ones with an expire set.
  36. # allkeys-random -> Remove a random key, any key.
  37. # volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
  38. # noeviction -> Don't evict anything, just return an error on write operations.
  39. #
  40. # LRU means Least Recently Used
  41. # LFU means Least Frequently Used
  42. #
  43. # Both LRU, LFU and volatile-ttl are implemented using approximated
  44. # randomized algorithms.
  45. #
  46. # Note: with any of the above policies, Redis will return an error on write
  47. # operations, when there are no suitable keys for eviction.
  48. #
  49. # At the date of writing these commands are: set setnx setex append
  50. # incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
  51. # sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
  52. # zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
  53. # getset mset msetnx exec sort
  54. #
  55. # The default is:
  56. #
  57. # maxmemory-policy noeviction
  58. # LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated
  59. # algorithms (in order to save memory), so you can tune it for speed or
  60. # accuracy. For default Redis will check five keys and pick the one that was
  61. # used less recently, you can change the sample size using the following
  62. # configuration directive.
  63. #
  64. # The default of 5 produces good enough results. 10 Approximates very closely
  65. # true LRU but costs more CPU. 3 is faster but not very accurate.
  66. #
  67. # maxmemory-samples 5
  68. # Starting from Redis 5, by default a replica will ignore its maxmemory setting
  69. # (unless it is promoted to master after a failover or manually). It means
  70. # that the eviction of keys will be just handled by the master, sending the
  71. # DEL commands to the replica as keys evict in the master side.
  72. #
  73. # This behavior ensures that masters and replicas stay consistent, and is usually
  74. # what you want, however if your replica is writable, or you want the replica to have
  75. # a different memory setting, and you are sure all the writes performed to the
  76. # replica are idempotent, then you may change this default (but be sure to understand
  77. # what you are doing).
  78. #
  79. # Note that since the replica by default does not evict, it may end using more
  80. # memory than the one set via maxmemory (there are certain buffers that may
  81. # be larger on the replica, or data structures may sometimes take more memory and so
  82. # forth). So make sure you monitor your replicas and make sure they have enough
  83. # memory to never hit a real out-of-memory condition before the master hits
  84. # the configured maxmemory setting.
  85. #
  86. # replica-ignore-maxmemory yes

哨兵机制

  • 未使用:在一主二从中,如果master节点挂了后咋办?因此需要引入哨兵机制
  • 使用后:master 节点宕机后,从节点会选出一个作为 master 节点,有一次组成主从模式

sentinel.conf

注意点:master名称要一模一样

  1. # Base
  2. # 端口号
  3. port 26379
  4. # pid 文件
  5. pidfile "/usr/local/redis/sentinel/redis-sentinel.pid"
  6. # 工作目录
  7. dir "/usr/local/redis/sentinel"
  8. # 守护进程
  9. daemonize yes
  10. # 保护模式
  11. protected-mode no
  12. # 日志文件
  13. logfile "/usr/local/redis/sentinel/redis-sentinel.log"
  14. # core
  15. # 配置哨兵
  16. sentinel monitor mymaster 127.0.0.1 6379 2
  17. # 密码
  18. sentinel auth-pass <master-name> <password>
  19. # mastersentinel认定为失效的间隔时间
  20. sentinel down-after-milliseconds mymaster 30000
  21. # 剩余的slaves重新和新的master做同步的并行个数
  22. sentinel parallel-syncs mymaster 1
  23. # 主备切换的超时时间,哨兵要去做故障转移,这个时候哨兵也是一个进程,如果他没有去执行,超过这个时间后,会由其他
  24. sentinel failover-timeout mymaster 180000

scp 远程拷贝

  1. scp sentinel.conf root@192.168.128.128:/usr/local/redis/
  2. 然后输入密码

将sentinel.conf 拷贝到对应服务器上

sentinel 启动

  1. redis-sentinel sentinel.conf
  2. # 第一次启动需要创建文件夹
  3. mkdir /usr/local/redis/sentinel -p

查看日志文件

  1. tail -f redis.sentinel.log

SpringBoot 配置Redis哨兵

Redis 集群

优点

  • 高可用

    前提条件:

  • 6个节点、6台服务器

image.png

搭建三主三从集群模式

工作中暂时用不到,待用到后,在进行学习,因此不做详细记录