首页 文章 精选 留言 我的

精选列表

搜索[Rust构建],共10000篇文章
优秀的个人博客,低调大师

如何构建 Redis 高可用架构?

1 、题记 Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。 如今,互联网业务的数据正以更快的速度在增长,数据类型越来越丰富,这对数据处理的速度和能力提出了更高要求。Redis 是一种开源的内存非关系型数据库,给开发人员带来的体验是颠覆性的。在自始至终的设计过程中,都充分考虑高性能,这使得 Redis 成为当今速度最快的 NoSQL 数据库。 考虑高性能的同时,高可用也是很重要的考虑因素。互联网 7x24 无间断服务,在故障期间以最快的速度 Failover,能给企业带来最小的损失。 那么,在实际应用中,都有哪些高可用架构呢?架构之间有何优劣?我们应该怎么取舍?有哪些最佳实践? 二、Sentinel (哨兵)原理 在讲解 Redis 高可用方案之前,我们先来看看 Redis Sentinel 原理(https://redis.io/topics/sentinel)是怎么样的。 Sentinel 集群通过给定的配置文件发现 master,启动时会监控 master。通过向 master 发送 info 信息获得该服务器下面的所有从服务器。 Sentinel 集群通过命令连接向被监视的主从服务器发送 hello 信息 (每秒一次),该信息包括 Sentinel 本身的 IP、端口、id 等内容,以此来向其他 Sentinel 宣告自己的存在。 Sentinel 集群通过订阅连接接收其他 Sentinel 发送的 hello 信息,以此来发现监视同一个主服务器的其他 Sentinel;集群之间会互相创建命令连接用于通信,因为已经有主从服务器作为发送和接收 hello 信息的中介,Sentinel 之间不会创建订阅连接。 Sentinel 集群使用 ping 命令来检测实例的状态,如果在指定的时间内(down-after-milliseconds)没有回复或则返回错误的回复,那么该实例被判为下线。 当 failover 主备切换被触发后,failover 并不会马上进行,还需要 Sentinel 中的大多数 Sentinel 授权后才可以进行 failover,即进行 failover 的 Sentinel 会去获得指定 quorum 个的 Sentinel 的授权,成功后进入 ODOWN 状态。如在 5 个 Sentinel 中配置了 2 个 quorum,等到 2 个 Sentinel 认为 master 死了就执行 failover。 Sentinel 向选为 master 的 slave 发送 SLAVEOF NO ONE 命令,选择 slave 的条件是 Sentinel 首先会根据 slaves 的优先级来进行排序,优先级越小排名越靠前。如果优先级相同,则查看复制的下标,哪个从 master 接收的复制数据多,哪个就靠前。如果优先级和下标都相同,就选择进程 ID 较小的。 Sentinel 被授权后,它将会获得宕掉的 master 的一份最新配置版本号 (config-epoch),当 failover 执行结束以后,这个版本号将会被用于最新的配置,通过广播形式通知其它 Sentinel,其它的 Sentinel 则更新对应 master 的配置。 1 到 3 是自动发现机制: 以 10 秒一次的频率,向被监视的 master 发送 info 命令,根据回复获取 master 当前信息。 以 1 秒一次的频率,向所有 redis 服务器、包含 Sentinel 在内发送 PING 命令,通过回复判断服务器是否在线。 以 2 秒一次的频率,通过向所有被监视的 master,slave 服务器发送当前 Sentinel master 信息的消息。 4 是检测机制,5 和 6 是 failover 机制,7 是更新配置机制。[1] 三、Redis 高可用架构 讲解完 Redis Sentinel 原理之后,接下来讲解常用的 Redis高可用架构。 Redis Sentinel 集群 + 内网 DNS + 自定义脚本 Redis Sentinel 集群 + VIP + 自定义脚本 封装客户端直连 Redis Sentinel 端口 JedisSentinelPool,适合 Java PHP 基于 phpredis 自行封装 Redis Sentinel 集群 + Keepalived/Haproxy Redis M/S + Keepalived Redis Cluster Twemproxy Codis 接下来配合图文逐个讲解。 1、Redis Sentinel 集群 + 内网 DNS + 自定义脚本 Redis Sentinel 集群 + 内网 DNS + 自定义脚本 上图是已经在线上环境应用的方案。底层是 Redis Sentinel 集群,代理着 Redis 主从,Web 端连接内网 DNS 提供服务。内网 DNS 按照一定的规则分配,比如 xxxx.redis.cache/queue.port.xxx.xxx,第一个段表示业务简写,第二个段表示这是 Redis 内网域名,第三个段表示 Redis 类型,cache 表示缓存,queue 表示队列,第四个段表示 Redis 端口,第五、第六个段表示内网主域名。 当主节点发生故障,比如机器故障、Redis 节点故障或者网络不可达,Sentinel 集群会调用 client-reconfig-script 配置的脚本,修改对应端口的内网域名。对应端口的内网域名指向新的 Redis 主节点。 优点: 秒级切换,在 10s 内完成整个切换操作 脚本自定义,架构可控 对应用透明,前端不用担心后端发生什么变化 缺点: 维护成本略高,Redis Sentinel 集群建议投入 3 台机器以上 依赖 DNS,存在解析延时 Sentinel 模式存在短时间的服务不可用 服务通过外网访问不可采用此方案 2、Redis Sentinel 集群 + VIP + 自定义脚本 Redis Sentinel 集群 + VIP + 自定义脚本 此方案和上一个方案相比,略有不同。第一个方案使用了内网 DNS,第二个方案把内网 DNS 换成了虚拟 IP。底层是 Redis Sentinel 集群,代理着 Redis 主从,Web 端通过 VIP 提供服务。在部署 Redis 主从的时候,需要将虚拟 IP 绑定到当前的 Redis 主节点。当主节点发生故障,比如机器故障、Redis 节点故障或者网络不可达,Sentinel 集群会调用 client-reconfig-script 配置的脚本,将 VIP 漂移到新的主节点上。 优点: 秒级切换,在 5s 内完成整个切换操作 脚本自定义,架构可控 对应用透明,前端不用担心后端发生什么变化 缺点: 维护成本略高,Redis Sentinel 集群建议投入 3 台机器以上 使用 VIP 增加维护成本,存在 IP 混乱风险 Sentinel 模式存在短时间的服务不可用 3.3 封装客户端直连 Redis Sentinel 端口 3、封装客户端直连 Redis Sentinel 端口 部分业务只能通过外网访问 Redis,上述两种方案均不可用,于是衍生出了这种方案。Web 使用客户端连接其中一台 Redis Sentinel 集群中的一台机器的某个端口,然后通过这个端口获取到当前的主节点,然后再连接到真实的 Redis 主节点进行相应的业务员操作。需要注意的是,Redis Sentinel 端口和 Redis 主节点均需要开放访问权限。如果前端业务使用 Java,有 JedisSentinelPool 可以复用;如果前端业务使用 PHP,可以在 phpredis 的基础上做二次封装。 优点: 服务探测故障及时 DBA 维护成本低 缺点: 依赖客户端支持 Sentinel Sentinel 服务器和 Redis 节点需要开放访问权限 对应用有侵入性 4、Redis Sentinel 集群 + Keepalived/Haproxy Redis Sentinel 集群 + Keepalived/Haproxy 底层是 Redis Sentinel 集群,代理着 Redis 主从,Web 端通过 VIP 提供服务。当主节点发生故障,比如机器故障、Redis 节点故障或者网络不可达,Redis 之间的切换通过 Redis Sentinel 内部机制保障,VIP 切换通过 Keepalived 保障。 优点: 秒级切换 对应用透明 缺点: 维护成本高 存在脑裂 Sentinel 模式存在短时间的服务不可用 5、Redis M/S + Keepalived Redis M/S + Keepalived 此方案没有使用到 Redis Sentinel。此方案使用了原生的主从和 Keepalived,VIP 切换通过 Keepalived 保障,Redis 主从之间的切换需要自定义脚本实现。 优点: 秒级切换 对应用透明 部署简单,维护成本低 缺点: 需要脚本实现切换功能 存在脑裂 6、Redis Cluster Redis Cluster From: http://intro2libsys.com/focused-redis-topics/day-one/intro-redis-cluster Redis 3.0.0 在 2015 年 4 月 2 日正式发布,距今已有两年多的时间。Redis 集群采用 P2P 模式,无中心化。把 key 分成 16384 个 slot,每个实例负责一部分 slot。客户端请求对应的数据,若该实例 slot 没有对应的数据,该实例会转发给对应的实例。另外,Redis 集群通过 Gossip 协议同步节点信息。 优点: 组件 all-in-box,部署简单,节约机器资源 性能比 proxy 模式好 自动故障转移、Slot 迁移中数据可用 官方原生集群方案,更新与支持有保障 缺点: 架构比较新,最佳实践较少 多键操作支持有限(驱动可以曲线救国) 为了性能提升,客户端需要缓存路由表信息 节点发现、reshard 操作不够自动化 7、Twemproxy Twemproxy From: http://engineering.bloomreach.com/the-evolution-of-fault-tolerant-redis-cluster 多个同构 Twemproxy(配置相同)同时工作,接受客户端的请求,根据 hash 算法,转发给对应的 Redis。 Twemproxy 方案比较成熟了,之前我们团队长期使用此方案,但是效果并不是很理想。一方面是定位问题比较困难,另一方面是它对自动剔除节点的支持不是很友好。 优点: 开发简单,对应用几乎透明 历史悠久,方案成熟 缺点: 代理影响性能 LVS 和 Twemproxy 会有节点性能瓶颈 Redis 扩容非常麻烦 Twitter 内部已放弃使用该方案,新使用的架构未开源 8、Codis Codis From: https://github.com/CodisLabs/codis Codis 是由豌豆荚开源的产品,涉及组件众多,其中 ZooKeeper 存放路由表和代理节点元数据、分发 Codis-Config 的命令;Codis-Config 是集成管理工具,有 Web 界面供使用;Codis-Proxy 是一个兼容 Redis 协议的无状态代理;Codis-Redis 基于 Redis 2.8 版本二次开发,加入 slot 支持,方便迁移数据。 优点: 开发简单,对应用几乎透明 性能比 Twemproxy 好 有图形化界面,扩容容易,运维方便 缺点: 代理依旧影响性能 组件过多,需要很多机器资源 修改了 Redis 代码,导致和官方无法同步,新特性跟进缓慢 开发团队准备主推基于 Redis 改造的 reborndb 四、最佳实践 所谓的最佳实践,都是最适合具体场景的实践。 主推以下方案: Redis Sentinel 集群 + 内网 DNS + 自定义脚本 Redis Sentinel 集群 + VIP + 自定义脚本 以下是实战过程中总结出的最佳实践: Redis Sentinel 集群建议使用 >= 5 台机器 不同的大业务可以使用一套 Redis Sentinel 集群,代理该业务下的所有端口 根据不同的业务划分好 Redis 端口范围 自定义脚本建议采用 Python 实现,扩展便利 自定义脚本需要注意判断当前的 Sentinel 角色 自定义脚本传入参数:<service_name> <role> <comment> <from_ip> <from_port> <to_ip> <to_port> 自定义脚本需要远程 ssh 操作机器,建议使用 paramiko 库,避免重复建立 SSH 连接,消耗时间 加速 SSH 连接,建议关闭以下两个参数 UseDNS no GSSAPIAuthentication no 微信或者邮件告警,建议 fork 一个进程,避免主进程阻塞 自动切换和故障切换,所有操作建议在 15s 以内完成 欢迎工作一到五年的Java工程师朋友们加入Java填坑之路:860113481 群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

优秀的个人博客,低调大师

Phoenix 构建二级索引

都来自官网,请看官网 http://phoenix.apache.org/secondary_indexing.html 下边分析全局索引和本地索引 Global Indexing 全局索引 Global indexing targets read heavy,low write uses cases. With global indexes, all the performance penalties for indexes occur at write time. We intercept the data table updates on write (DELETE, UPSERT VALUES and UPSERT SELECT), build the index update and then sent any necessary updates to all interested index tables. At read time, Phoenix will select the index table to use that will produce the fastest query time and directly scan it just like any other HBase table. By default, unless hinted, an index will not be used for a query that references a column that isn’t part of the index. Global indexing适用于多读少写的业务场景。使用Global indexing的话在写数据的时候会消耗大量开销,因为所有对数据表的更新操作(DELETE, UPSERT VALUES and UPSERT SELECT),会引起索引表的更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。在默认情况下如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。 配置hbase-site.xml 使用Global Indexing的话需要配置hbase-site.xml,在HBase集群的每个regionserver节点的hbase-site.xml中加入如下配置并重启HBase集群。 <property> <name>hbase.regionserver.wal.codec</name> <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value> </property> 如果是CDH版本,要通过该cloudera manager配置 hbase-配置 修改这里 测试索引 -- 注意phoenix最好全大写字母,这里码字方便,我全小写了,请注意 -- 创建表 create table company(id varchar primary key, name varchar, address varchar); --- 查看索引 !indexes company; -- 创建索引 create index my_index on company(name); --删除索引表 drop index my_index on company -- 查看表就会发现多了一张索引表 !tables SELET * FROM MY_INDEX 该表中会有2个字段,其中:ID是自动创建的,其实就是HBase中的主键RowKey,0:NAME是我们刚刚手动创建的。 -- 插入数据 upsert into company(id, name, address) values('001', 'dimensoft', 'nanjing'); -- 查询数据 select name,address from company where name='dimensoft'; -- 查询索引表MY_INDEX SELECT * FROM MY_INDEX 或者 scan 'MY_INDEX' 高能预警 > select name,address from company where name='dimensoft'; 这样的查询语句是不会用到索引表的 Global mutable index will not be used unless all of the columns referenced in the query are contained in the index. name字段虽然是索引字段但是address字段并不是索引字段!也就是说需要查询出来的字段必须都是索引字段如: > select name from company where name='dimensoft'; 如果希望使用索引表进行查询的话可以使用以下三种方式来解决这个问题: 强制使用索引表 在进行查询的时候通过sql语句强制使用索引查询。 > SELECT /*+ INDEX(company my_index) */ name,address FROM company WHERE name = 'dimensoft'; This will cause each data row to be retrieved when the index is traversed to find the missing address column value. This hint should only be used if you know that the index has good selective (i.e. a small number of table rows have a value of ‘dimensoft’ in this example), as otherwise you’ll get better performance by the default behavior of doing a full table scan. 这样的查询语句会导致二次检索数据表,第一次检索是去索引表中查找符合name为dimensoft的数据,这时候发现address字段并不在索引字段中,会去company表中第二次扫描,因此只有当用户明确知道符合检索条件的数据较少的时候才适合使用,否则会造成全表扫描,对性能影响较大。 创建covered index 创建索引的时候指定一个covered字段,先删除my_index索引 > drop index my_index on company; 创建covered index > create index my_index on company(name) include(address); This will cause the address column value to be copied into the index and kept in synch as it changes. This will obviously increase the size of the index. 使用这种方式创建的所有会导致address字段的值被拷贝到索引中,缺点就是会导致索引表大小有一定的增加。 查询索引表my_index数据。 > select * from my_index; 这里写图片描述 这里的数据是自动同步过来的,可以发现address字段的值也被存储了。 从HBase的CLI中查看MY_INDEX表数据会发现比不使用include的时候多了一行数值,并且里面包含了address字段的值。 > scan 'MY_INDEX' 这里写图片描述 这个时候就再使用下面的查询语句就会使用到索引来进行查询了。 > select name,address from company where name='dimensoft'; 使用Local Indexing创建索引 与Global Indexing不同,当使用Local Indexing的时候即使查询的所有字段都不在索引字段中时也会用到索引进行查询(这是由Local Indexing自动完成的)。这部分内容会放到后一篇文章详细介绍。 Local Indexing 本地索引 Local indexing targets write heavy, space constrained use cases. Just like with global indexes, Phoenix will automatically select whether or not to use a local index at query-time. With local indexes, index data and table data co-reside on same server preventing any network overhead during writes. Local indexes can be used even when the query isn’t fully covered (i.e. Phoenix automatically retrieve the columns not in the index through point gets against the data table). Unlike global indexes, all local indexes of a table are stored in a single, separate shared table.At read time when the local index is used, every region must be examined for the data as the exact region location of index data cannot be predetermined.Thus some overhead occurs at read-time. Local indexing适用于写操作频繁的场景。与Global indexing一样,Phoenix会自动判定在进行查询的时候是否使用索引。使用Local indexing时,索引数据和数据表的数据是存放在相同的服务器中的避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。使用Local indexing的时候即使查询的字段不是索引字段索引表也会被使用,这会带来查询速度的提升,这点跟Global indexing不同。一个数据表的所有索引数据都存储在一个单一的独立的可共享的表中。在读取数据的时候,标红的那句话不会翻译大意就是在读数据的时候因为存储数据的region的位置无法预测导致性能有一定损耗。 配置hbase-site.xml 使用Local Indexing的话需要配置hbase-site.xml,在HBase集群的master节点的hbase-site.xml中添加如下配置并重启HBase集群。 Local indexing also requires special configurations in the master to ensure data table and local index regions co-location. 配置这个参数的目的是确保数据表与索引表协同定位。 <property> <name>hbase.master.loadbalancer.class</name> <value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value> </property> <property> <name>hbase.coprocessor.master.classes</name> <value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value> </property> 高能预警:如果使用的是Phoenix 4.3+的版本的话 还需要在HBase集群的每个regionserver节点的 hbase-site.xml中添加如下配置并重启HBase集群。 To support local index regions merge on data regions merge you will need to add the following parameter to hbase-site.xml in all the region servers and restart. (It’s applicable for Phoenix 4.3+ versions) 这个配置是为了支持在数据region合并之上进行 索引region合并(这句话感觉翻译的不太准确)。 <property> <name>hbase.coprocessor.regionserver.classes</name> <value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value> </property> 注意: 同理使用CDH版的要通过cloudera manager页面管理配置 测试二级索引 进入phoenix的CLI的界面创建company表。 > create table company(id varchar primary key, name varchar, address varchar); 这里写图片描述 查看company表索引 > !indexes company 这里写图片描述 2.3 创建索引 对company表的name字段创建索引,索引名为my_index。 > create local index my_index on company(name); 查看当前所有表会发现多一张MY_INDEX索引表,查询该表数据。 这里写图片描述 通过squirrel来查看company的索引字段。 这里写图片描述 从HBase的CLI界面查看当前所有表。 > list 这里写图片描述 高能预警:这里的索引表并不叫MY_INDEX,而是叫_LOCAL_IDX_COMPANY,但是在Phoenix的CLI中进行数据查询的时候仍然是使用MY_INDEX进行查询,应该是做了映射。 2.4 插入数据 在company表中添加测试数据。 > upsert into company(id, name, address) values('001', 'dimensoft', 'nanjing'); 2.5 查询数据 查看company表数据以及索引表my_index数据。 > select * from company; > select * from my_index; 这里写图片描述 从HBase的CLI界面查看索引表_LOCAL_IDX_COMPANY。 > scan '_LOCAL_IDX_COMPANY' 这里写图片描述 3个索引字段_INDEX_ID、NAME和ID的值被合并为索引表的rowKey,其中_INDEX_ID并没有值(\x000是十六进制表示,转换为字符串是空格)。 函数索引 Functional Indexes 函数索引从4.3版本就有,这种索引的内容不局限于列,还能在表达式上建立索引。如果你使用的表达式正好就是索引的话,数据也可以直接从这个索引获取,而不需要从数据库获取。比如说,在一个表达式上建立索引,这个表达式是UPPER(name) || '_test': <pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-family: "Courier New" !important; font-size: 12px !important;">CREATE INDEX index2_f ON hao1 (UPPER(name) || '_test');</pre> 同样的index2_f表会被建立,里面存储了表达式求值后的结果,和RowKey的关系。当然也可以添加INCLUDE作为覆盖索引,做了覆盖索引,就不需要再去原数据表中获取数据。但是数据会多很多。 image 在索引范围上,Phoenix的索引可以分为全局索引和本地索引,两种索引适合的场景不同。 创建异步索引 一般我们可以使用CREATE INDEX来创建一个索引,这是一种同步的方法。但是有时候我们创建索引的表非常大,我们需要等很长时间。Phoenix 4.5以后有一个异步创建索引的方式,使用关键字ASYNC来创建索引: CREATE INDEX index1_c ON hao1 (age) INCLUDE(name) ASYNC; 这时候创建的索引表中不会有数据。你还必须要单独的使用命令行工具来执行数据的创建。当语句给执行的时候,后端会启动一个map reduce任务,只有等到这个任务结束,数据都被生成在索引表中后,这个索引才能被使用。启动工具的方法: ${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool --schema MY_SCHEMA --data-table MY_TABLE --index-table ASYNC_IDX --output-path ASYNC_IDX_HFILES 这个任务不会因为客户端给关闭而结束,是在后台运行。你可以在指定的文件ASYNC_IDX_HFILES中找到最终实行的结果。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册