当前位置: 首页 > news >正文

来年做那些网站致富大型新型网站

来年做那些网站致富,大型新型网站,开通域名后怎样建设网站,长沙生活网目录 集群 数据分片算法 哈希求余 一致性哈希算法 哈希槽分区算法 redis集群搭建 1.创建目录和配置. 2.将上述redis节点.构建成集群 3.使用客户端连接集群 集群模式下的故障转移流程 1.故障判定 2.故障迁移 集群扩容 集群 广义上的集群,只要是多个机器,构成了分布…目录 集群 数据分片算法 哈希求余 一致性哈希算法 哈希槽分区算法 redis集群搭建 1.创建目录和配置. 2.将上述redis节点.构建成集群 3.使用客户端连接集群 集群模式下的故障转移流程 1.故障判定 2.故障迁移 集群扩容 集群 广义上的集群,只要是多个机器,构成了分布式系统,都可以称为是一个集群.前面的主从模式和哨兵模式也可以称为是广义的集群. 狭义的集群,redis提供的集群模式,在这个集群模式之下,主要是姐姐,存储空间不足的问题. redis集群基本概念 上述的哨兵模式,虽然提高了系统的可用性,但是真正用来存储数据的还是master和slave节点,所有的数据都需要存储在单个的master和slave节点中. 如果数据量很大,超出了master/slave所在机器的物理内存,就可能出现严重问题了. 那么如何获得更大的空间,加机器即可!!! redis集群就是在上述思路下,引入多组master/slave存储数据全集的一部分,从而构成一个更大的整体,称为是redis集群. 假定整个数据全集是1TB,此时就可以引入三组master/slave,每一组master/slave只需要存储整个数据全集的三分之一即可. 其中每一组主从节点保存的是同样的数据,占数据全集的三分之一. 每个从节点都是对应主节点的备份,当主节点挂了,对应的slave会补位成主节点. 每组主从节点都可以称为是一个分片(sharding). 如果全量数据进一步增加,只要在增加更多的分片即可. 数据分片算法 Redis cluster的核⼼思路是⽤多组机器来存数据的每个部分.那么接下来的核⼼问题就是,给定⼀个数据(⼀个具体的key),那么这个数据应该存储在哪个分⽚上?读取的时候⼜应该去哪个分⽚读取? 围绕这个问题,业界有三种⽐较主流的实现⽅式. 哈希求余 借助了哈希表的基本思想,借助hash函数,把一个key映射到整数,在针对数组的长度,求余,就可以得到一个数组的下标. 比如有三个分片,编号为0,1,2. 此时就可以针对要插入的数据key计算hash值(比如使用MD5计算hash值),在把这个hash值余上分片的个数,就得到了一个编号,此时就可以把这个数据放到对应的下标对应分片中了. md5是一个计算hash值的算法.它能够针对一个字符串里面的内容进行一系列的数学演算,最终得到一个整数. 它是一个非常广泛使用的hash算法.特点: 1.md5计算结果是定长的,无论输入的原字符串有多长,最终算出的结果就是固定长度.2.md5计算结果是分散的,两个源字符串,哪怕只有一个地方不同,算出来的md5值也会差别很大.3.md5计算结果是不可逆的.字符串-md5值是很容易得到,而根据md5值还原出原始字符串是很困难的,理论上是不可行的. 如果计算出hash(key)%30,此时这个key就要存储在0号分片中,后续查询key的时候,也是同样的算法. 数据搬运 一旦服务器集群需要扩容,就需要更高的成本了.分片的主要目的是为了提高存储能力,分片越多,能存的数据也就越多,但是成本也就更高. 如果随着业务的增长,原先的三个分片已经不够用了,那么此时就要扩容,引入更多的分片. 引入新的分片的后,hash(key)%N中的N就变了,加入这里新引入一个分片,N就从3变为了4. 当hash函数和key都不变的情况下,如果N变了,整体的分片结果仍然会改变. 如果发现某个数据,在扩容之后,不应该存储在当前的分片中了,就需要重新进行分配这个数据,这个过程就叫做数据搬运. 从上图可以看出,一共20个数据,经过扩容之后,只有3个数据不需要搬运,17个数据需要搬运!!! 由此我们知道采用哈希求余算法需要搬运的数据的比例是很高的.如果在生产环境上扩容,开销是极大的.所以我们往往不能直接在生产环境上操作上述过程,只能通过替换的方式来实现扩容.但是替换也就意味着依赖的机器更多了,成本更高,操作步骤也非常复杂!!! 一致性哈希算法 在hash求余这种操作下,当前的key属于哪个分片,是交替的. 102-0,103-1,104-2,105-0......,交替出现,就导致数据搬运的成本很大. 在一致性hash算法中,把交替出现,改进成了连续出现.降低了数据搬运的开销,能够高效扩容. 一致性hash算法过程 1.把0-2^31-1这个数据空间,映射到一个圆环上,数据按照顺时针方向增长. 2.假设当前存在三个分片,就把分片放到圆环的某个位置上. 3.假定有一个key,计算得到hash值H,就从H所在位置,顺时针往下找,找到的第一个分片,即为该key所从属的分片. 这就相当于,N个分片的位置,把整个圆环分成了N个管辖空间,key的hash值落在某个区间内,就归对应的区间管理. 在这种情况下,如果扩容一个分片,原有分片在环上的位置不动,只要在环上新安排一个分片位置即可. 此时,只要把0号分片上的部分数据,搬运到3号分片上即可,1号分片和2号分片管理的区间上的数据都是不变的. 虽然搬运的成本低了,但是这几个分片上的数据量,就可能步均匀了,就造成了数据倾斜的问题!!! 哈希槽分区算法 此种算法是redis真正采用的分片算法. 为了解决搬运成本高和数据分配不均匀的问题,reids cluster引入了哈希槽算法. hash_slot crc16(key) % 16384 其中crc也是一种hash算法. 相当于把整个哈希值,映射到16384个槽位上,也就是[0,16384]. 然后把这些槽位均匀的分配给每个分片,每个分片的节点都需要记录自己持有哪些分片. 这种算法,本质就是把一致性hash和哈希求余两种方式结合一下. 假设现在有三个分片,一种可能的分配方式: 0号分片:[0,5461],共5462个槽位; 1号分片:[5462,10923],共5462个槽位. 2号分片:[10924,16383],共5460个槽位. 虽然不是严格意义的均匀,但是差异非常小,此时这三个分片上的数据就是比较均匀的了. 上述只是一种可能的分片方式,实际上分片是非常灵活的,每个分片持有的槽位号,可以是连续的,也可以是不连续的. 此处,每个分片都会使用位图这样的数据结构,来表示出当前持有的槽位.16384个bit位(2KB),用每一位的0或者1来区分这个分片是否持有这个槽位. 如果需要扩容,比如新增一个3号分片,就可以针对原有的槽位进行重新分配. 比如可以把之前每个分片持有的槽位,各拿出一点,分给新的分片. • 0号分⽚:[0,4095],共4096个槽位 • 1号分⽚:[5462,9557],共4096个槽位 • 2号分⽚:[10924,15019],共4096个槽位 • 3号分⽚:[4096,5461][9558,10923][15019,16383],共4096个槽位. 注意,我们在使用redis集群分片的时候,不需要手动指定哪些槽位分配给某个分片,只需要告诉redis某个分片应该持有多少个槽位即可,redis会自动完成后续的槽位分配,以及key对应的搬运工作. 关于哈希槽分区算法的两个问题 redis集群是最多有16384个分片吗??? 其实不然,如果一个分片上只有一个槽位,这对于集群的数据均匀是难以保证的.而且16384个分片这么大规模的集群,本身的可用性是一个大问题. 实际上redis的作者建议分片的数目不应该超过1000. 为什么是16384个槽位??? 节点之间通过⼼跳包通信.⼼跳包中包含了该节点持有哪些slots.这个是使⽤位图这样的数据结构 表⽰的.表⽰16384(16k)个slots,需要的位图⼤⼩是2KB.如果给定的slots数更多了,⽐如65536个了,此时就需要消耗更多的空间,8KB位图表⽰了.8KB,对于内存来说不算什么,但是在频繁的⽹络⼼跳包中,还是⼀个不⼩的开销的. 另⼀⽅⾯,Redis集群⼀般不建议超过1000个分⽚.所以16k对于最⼤1000个分⽚来说是⾜够⽤ 的,同时也会使对应的槽位配置位图体积不⾄于很⼤. 总结来说,就是这些个槽位基本上是够用的,同时占用的网络带宽也不是很大. redis集群搭建 在这里由于只有一台云服务器,所以也是基于docker搭建. 实际工作中,一般是通过主机的方式,来搭建集群. 在搭建之前,一定要把之前启动的redis容器,给停止掉!!!在redis-data目录和redis-sentinel目录下分别执行docker-compose down命令. 在这里我们创建出11个redis节点,其中9个用于集群的搭建,2个用于集群的扩容. 1.创建目录和配置. 创建redis-cluster目录,内部创建两个文件. 在linux上以.sh为后缀结尾的文件,称为是shell脚本.shell脚本里可以批量化执行命令,并且还能加入条件,循环,函数等机制,来完成更加复杂的工作. generate.sh内容 for port in $(seq 1 9); \ do \ mkdir -p redis${port}/ touch redis${port}/redis.conf cat EOF redis${port}/redis.conf port 6379 bind 0.0.0.0 protected-mode no appendonly yes cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.30.0.10${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 EOF done # 注意 cluster-announce-ip 的值有变化. for port in $(seq 10 11); \ do \ mkdir -p redis${port}/ touch redis${port}/redis.conf cat EOF redis${port}/redis.conf port 6379 bind 0.0.0.0 protected-mode no appendonly yes cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.30.0.1${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 EOF done for port in $(seq 1 9);表明这是一个基于范围的循环.类似于java的for each. seq也是一个命令,seq 1 9表示生成1-9闭区间内的数据. \是续行符,把下一行的内容和当前行,合并成一行.shell默认情况下,要求把所有的代码都写到一行里,使用续行符来换行. 对于for来说,用do和done表示代码块的开始和结束,shell中{}用来表示变量了,不表示代码块. shell中拼接字符是直接写到一起,而不需要使用. 因此上述第一个循环就表示,创建9个目录,在这些目录下创建一个文件,将内容写到文件中去. 这些内容只有在配置集群的ip的时候是不一致的, cluster-announce-ip 172.30.0.10${port},会生成101-109的ip. 经过上述两个循环,就会得到11个目录,每个目录里都有一个配置文件,配置文件中ip地址各不相同. cluster-enabled yes表示开启集群 cluster-config-file nodes.conf//不需要手动写,redis自动生成,后续启动节点之后,会配置一些redis集群信息,写入到此文件中. cluster-node-timeout 5000//多个节点保持联络的心跳包的超时时间 cluster-announce-ip 172.30.0.10${port}//该redis节点所在主机的ip,当前是使用docker容器模拟的主机,此处写的应该是docker容器的ip. cluster-announce-port 6379//redis节点自身绑定的端口(容器内的端口),属于是业务端口. cluster-announce-bus-port 16379//该redis节点的管理端口. 一个服务器,可以绑定多个端口号. 业务端口是用来完成业务数据通信的,响应redis客户端的请求. 管理端口:为了完成一些管理上的任务来进行通信的端口,如果某个分片的redis主节点挂了,就需要从节点成为主节点,此过程就需要管理端口来完成对应的操作. 完成上述操作之后,使用bash命令执行shell脚本. docker-compose.yml的编写 version: 3.7 networks:   mynet:     ipam:       config:         - subnet: 172.30.0.0/24 services:   redis1:     image: redis:5.0.9     container_name: redis1     restart: always     volumes:       - ./redis1/:/etc/redis/     ports:       - 6371:6379       - 16371:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.101   redis2:     image: redis:5.0.9     container_name: redis2     restart: always     volumes:       - ./redis2/:/etc/redis/     ports:       - 6372:6379       - 16372:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.102   redis3:     image: redis:5.0.9     container_name: redis3     restart: always     volumes:       - ./redis3/:/etc/redis/     ports:       - 6373:6379       - 16373:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.103   redis4:     image: redis:5.0.9     container_name: redis4     restart: always     volumes:       - ./redis4/:/etc/redis/     ports:       - 6374:6379       - 16374:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.104   redis5:     image: redis:5.0.9     container_name: redis5     restart: always     volumes:       - ./redis5/:/etc/redis/     ports:       - 6375:6379       - 16375:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.105   redis6:     image: redis:5.0.9     container_name: redis6     restart: always     volumes:       - ./redis6/:/etc/redis/     ports:       - 6376:6379       - 16376:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.106   redis7:     image: redis:5.0.9     container_name: redis7     restart: always     volumes:       - ./redis7/:/etc/redis/     ports:       - 6377:6379       - 16377:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.107   redis8:     image: redis:5.0.9     container_name: redis8     restart: always     volumes:       - ./redis8/:/etc/redis/     ports:       - 6378:6379       - 16378:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.108   redis9:     image: redis:5.0.9     container_name: redis9     restart: always     volumes:       - ./redis9/:/etc/redis/     ports:       - 6379:6379       - 16379:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.109   redis10:     image: redis:5.0.9     container_name: redis10     restart: always     volumes:       - ./redis10/:/etc/redis/     ports:       - 6380:6379       - 16380:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.110   redis11     image: redis:5.0.9     container_name: redis11     restart: always     volumes:       - ./redis11:/etc/redis/     ports:       - 6381:6379       - 16381:16379     command:       redis-server /etc/redis/redis.conf     networks:       mynet:         ipv4_address: 172.30.0.111 此处为了后续创建静态ip,要先手动创建出网络,同时给这个网络也分配ip. 创建完配置文件之后,启动容器. 2.将上述redis节点.构建成集群 redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379 172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379 172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379 --cluster-replicas 2 --cluster create表示建立集群,后面填写每个节点的ip和端口. --cluster-replicas 2表示每个主节点需要2个从节点备份. redis在构建集群的时候,谁是主节点谁是从节点,哪些节点是一个分片不是固定的. 执行命令. 输入yes. 集群构造完毕. 3.使用客户端连接集群 从101-109九个节点,现在是一个整体,使用客户都安连上任意一个节点,都是在操作整个集群,本质上都是等价的. 使用cluster nodes命令查看当前集群的信息. 使用集群来存储数据. 设置成集群模式之后,当前数据就要分片存储了,k1这个key通过hash计算之后,得到slot为12706,属于103这个分片,所以就报错了. 我们可以在启动redis客户端的时候,加上-c选项,此时客户端如果发现当前的key的操作不在当前分片上,就能够自动的重定向到对应的分片主机. 请求转发给了103这个节点,进一步完成了数据存储的操作. 使用集群之后,之前学过的操作多个key的命令有时候就不能正常使用了,此时如果key分布在多个分片上,就有可能出现问题. 如果集群中,有节点挂了怎么办? 如果挂了的是从节点,没有多大影响. 如果挂了的是主节点,因为只有主节点才能处理写操作(如果在从节点上尝试写操作,此时就会自动的被重定向到指定的主节点上),此时集群做的工作就和哨兵做的类似了,集群会自动的把该主节点旗下的从节点,选拔一个出来,晋升为主节点. 我们先使用docker stop redis1命令停掉redis1. 在连上一个客户端查看集群信息. 可以看出,106成了新的主节点,并且105成了106的从节点. 然后我们在使用docker start redis1恢复redis1节点. 再次查看集群信息. 101成了从节点,从属于106. 通过上述过程,我们可以看出,集群机制具有故障转移的机制. 集群模式下的故障转移流程 1.故障判定 集群中的所有节点, 都会周期性的使⽤⼼跳包进⾏通信. 1. 节点 A 给 节点 B 发送 ping 包, B 就会给 A 返回⼀个 pong 包. ping 和 pong 除了 message type 属性之外, 其他部分都是⼀样的. 这⾥包含了集群的配置信息(该节点的id, 该节点从属于哪个分⽚, 是主节点还是从节点, 从属于谁, 持有哪些 slots 的位图...). 2. 每个节点, 每秒钟, 都会给⼀些随机的节点发起 ping 包, ⽽不是全发⼀遍. 这样设定是为了避免在节点很多的时候, ⼼跳包也⾮常多(⽐如有 9 个节点, 如果全发, 就是 9 * 8 有 72 组⼼跳了, ⽽且这是按照 N^2 这样的级别增⻓的). 3. 当节点 A 给节点 B 发起 ping 包, B 不能如期回应的时候, 此时 A 就会尝试重置和 B 的 tcp 连接, 看能否连接成功. 如果仍然连接失败, A 就会把 B 设为 PFAIL 状态(相当于主观下线). 4. A 判定 B 为 PFAIL 之后, 会通过 redis 内置的 Gossip 协议, 和其他节点进⾏沟通, 向其他节点确认 B 的状态. (每个节点都会维护⼀个⾃⼰的 下线列表, 由于视⻆不同, 每个节点的下线列表也不⼀定相同). 5. 此时 A 发现其他很多节点, 也认为 B 为 PFAIL, 并且数⽬超过总集群个数的⼀半, 那么 A 就会把 B 标记成 FAIL (相当于客观下线), 并且把这个消息同步给其他节点(其他节点收到之后, 也会把 B 标记成FAIL). ⾄此, B 就彻底被判定为故障节点了. 2.故障迁移 上述例⼦中, B 故障, 并且 A 把 B FAIL 的消息告知集群中的其他节点. • 如果 B 是从节点, 那么不需要进⾏故障迁移. • 如果 B 是主节点, 那么就会由 B 的从节点 (⽐如 C 和 D) 触发故障迁移了. 所谓故障迁移, 就是指把从节点提拔成主节点, 继续给整个 redis 集群提供⽀持. 具体流程如下: 1. 从节点判定⾃⼰是否具有参选资格. 如果从节点和主节点已经太久没通信(此时认为从节点的数据和主节点差异太⼤了), 时间超过阈值, 就失去竞选资格. 2. 具有资格的节点, ⽐如 C 和 D, 就会先休眠⼀定时间. 休眠时间 500ms 基础时间 [0, 500ms] 随机时间 排名 * 1000ms. offset 的值越⼤, 则排名越靠前(越⼩). 3. ⽐如 C 的休眠时间到了, C 就会给其他所有集群中的节点, 进⾏拉票操作. 但是只有主节点才有投票资格. 4. 主节点就会把⾃⼰的票投给 C (每个主节点只有 1 票). 当 C 收到的票数超过主节点数⽬的⼀半, C 就会晋升成主节点. (C ⾃⼰负责执⾏ slaveof no one, 并且让 D 执⾏ slaveof C). 5. 同时, C 还会把⾃⼰成为主节点的消息, 同步给其他集群的节点. ⼤家也都会更新⾃⼰保存的集群结构信息. 上述选举的过程, 称为 Raft 算法, 是⼀种在分布式系统中⼴泛使⽤的算法. 在随机休眠时间的加持下, 基本上就是谁先唤醒, 谁就能竞选成功. 注意和哨兵的区别,哨兵实现出leader,leader负责找一个从节点升级成主节点.而集群是直接投票选出新的主节点. 集群扩容 101-109九个主机,构成了3主6从结构的集群. 现在将110和111两个节点也加入到集群当中,以110为主节点,111为从节点,同时数据分片从3变为4. 1.新的主节点110加入到集群中 redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379 add-node后的第一组地址是新节点的地址,第二组地址是集群中任意节点的地址,代表整个集群. 此时通过cluster nodes命令查看到110已经成为主节点了,但是还有槽位分配给它. 2.重新分配slots 把之前三组的master上面的槽位各自分出一些来,给到新的主节点. redis-cli --cluster reshard 172.30.0.101:6379 reshard后的地址是集群中任意节点的地址,reshard代表重新切分的意思. 执行此命令之后,会进入交互式操作,redis会提示用户输入以下内容: 1).多少个slots要进行reshard? 此处我们填写4096. 2).哪个节点接收这些slots? 此处我们填写172.30.0.110这个节点的集群节点的id,上方会有打印,直接粘贴即可. 3).这些slots从哪些节点搬运过来? 此处我们填写all,意思是每个主节点都分一些槽位过来. 也可以手动指定,从某一个或者某几个节点来移动slots,输入以done结尾. 当输入all之后,给出的搬运计划还没有真正开始,当输入yes之后,搬运才真正开始. 此时不仅仅是slots的重新划分,也会把slots上对应的数据,也搬运到新的主机上,这是比较重量的操作!!! 注意,在搬运key的过程中,对于哪些不需要搬运的key,客户端进行访问的时候是没有问题的,但是对于需要搬运的key,进行访问可能会出现短暂的访问错误(因为key的位置发生了变化),随着搬运完成,这样的错误也就自然恢复了. 搬运完成后,就可以看到它的槽位信息了. 3.给新的主节点添加从节点 光有主节点了,此时扩容的⽬标已经初步达成.但是为了保证集群可⽤性,还需要给这个新的主节点添加,从节点,保证该主节点宕机之后,有从节点能够顶上. redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave --cluster-master-id [172.30.0.110节点的nodeid] 从节点添加完毕!!!
http://www.zqtcl.cn/news/302146/

相关文章:

  • 做的新网站网上搜不到做的网站百度搜索不出来的
  • 电商网站后台报价公司如何建站
  • 查网站有没有做推广企业网站建设的目标
  • 北京网站维护公司专业外贸网站建设_诚信_青岛
  • 网站自己做还是用程序制作网站一般使用的软件有哪些
  • 晨雷文化传媒网站建设济南互联网品牌设计
  • 怎样给自己的网站做防红连接梵客装饰公司官网
  • 甘肃省城乡与住房建设厅网站纪检网站建设动态主题
  • 关于做好全国网站建设网站建设哪个好
  • 灵犀科技网站建设企业建设网站作用
  • 做网站架构图无版权图片网站
  • 赌场需要网站维护吗通过服务推广网站的案例
  • 阿里云网站空间网站建设犭金手指六六壹柒
  • 网站排名软件包年农业网站开发
  • 建设信用卡网银网站crm客户关系管理论文
  • 阿里巴巴网站的搜索引擎优化案例软件开发收费价目表
  • 企业网站建设之域名篇wordpress 文章居中
  • 萍乡网站建设行吗南康建设局官方网站
  • 一键部署wordpress爱站seo工具
  • 大连网站建设服务做进料加工在哪个网站上做
  • 南昌行业网站建设网站版权信息修改
  • 百度网站关键词排名助手低成本做网站 白之家
  • 怎么查询网站是谁做的部队网站建设报告
  • 租房网站开发专业网站建设品牌策划方案
  • 电子商务网站建设方案书软件开发工具图片
  • 案例建网站宿松网站建设公司
  • 秦皇岛网站开发wordpress免费国内主题
  • seo网站推广推荐阳江房管局查询房产信息网
  • php服装商城网站建设个人网站免费空间
  • 做内贸注册什么网站广州市建设交易中心网站