首页 文章 精选 留言 我的

精选列表

搜索[扩展更新],共10000篇文章
优秀的个人博客,低调大师

pika集群水平扩展——让性能容量不再受限

背景 Pika是一个可持久化的大容量redis存储服务,兼容string、hash、list、zset、set的绝大部分接口(兼容详情),解决redis由于存储数据量巨大而导致内存不够用的容量瓶颈。用户可以不修改任何代码从redis迁移到pika服务。具有良好的兼容性和稳定性,被360公司内部使用超过3000实例,github社区超过3.8K star。由于单机pika容量受限于单块硬盘容量的大小,360公司业务和社区对分布式pika集群的需求越来越强烈,因此我们推出了原生分布式pika集群,发布pika版本v3.4。与pika+codis集群方案相比,codis对pika创建和管理slot操作的支持并不友好,需要运维人员大量介入。而pika原生集群则不需要额外部署codis-proxy模块。 集群部署结构 以3个pika节点的集群为例,集群部署结构如上图所示: 部署Etcd集群作为pika manager的元信息存储。 3台物理机上分别部署pika manager,并配置好Etcd的服务端口。Pika manager会向etcd注册,并争抢成为leader。集群中有且只有一个pika manager能够成为leader并向etcd中写入集群数据。 3台物理机上分别部署pika节点,然后把pika节点的信息添加到pika manager中。 为了负载均衡,把pika的服务端口注册到LVS中。 数据分布 为了对数据按照业务进行隔离,Pika集群引入table的概念,不同的业务数据存储在不同的table中。业务数据按照key的hash值存储到对应的slot上面。每一个slot会有多个副本,从而形成一个replication group。replication group中的所有slot副本具有相同的slot ID,其中一个slot副本是leader,其他副本为follower。为了保证数据的一致性,只有leader提供读写服务。可以使用pika manager对slot进行调度迁移,使数据和读写压力均匀的分散到整个pika集群中,从而保证了整个集群资源的充分利用并且可以根据业务压力和存储容量的需要进行水平扩容和缩容。 pika使用rocksdb作为存储引擎,每个slot会创建对应的rocksdb。pika中的每个slot都支持读写redis 5种数据结构。因此数据迁移的时候会特别方便,只需迁移pika中的slot即可。但同时也存在资源占用过多的问题。目前的pika在创建slot的时候会默认创建5个rocksdb,分别来存储5种数据结构。在table中含有大量slot或者创建大量table的时候会使单个pika节点含有多个slot,进而创建过多的rocksdb实例,占用了过多系统资源。在后续版本中一方面会支持创建slot的时候根据业务需要创建一种或多种数据结构,另一方面会持续对pika中的blackwidow接口层进行优化,减少对rocksdb的使用。 数据处理 当pika节点接收到用户请求时,解析层处理解析redis协议,并把解析好的结果交给router层进行判断。 router根据key的hash结果找到key对应的slot,并判断slot是否在本地节点上。 如果key所在的slot在其他节点,则根据请求创建一个task放入队列中,并把请求转发给peer节点来处理。当task接收到请求的处理结果后把请求返回给客户端。 如果key所在的slot属于本地节点,就直接本地处理请求并返回给客户端。 对于需要本地处理的写请求,先通过replication manager模块写binlog,异步复制到其他slot副本。process layer根据一致性的要求,写入leader slot。其中blackwidow是对rocksdb的接口封装。 我们把proxy内嵌的pika中,不需要单独部署。与redis cluster相比,客户端不需要感知proxy的存在,只需像使用单机一样使用集群。可以把pika节点的服务端口挂载到LVS中,实现压力在整个集群的负载均衡。 日志复制 pika中replication manager模块负责日志的主从同步。为了兼容redis,pika支持非一致日志复制,leader slot直接在db中写入数据而无需等待从follower slot的ack应答。同时也支持raft一致性协议方式的日志复制,需要满足收到大多数副本的ack才写入db。 非一致日志复制 在非一致场景下处理流程如下: 处理线程接收到客户端的请求,直接加锁后写入binlog和并操作db。 处理线程返回客户端response。 辅助线程发送BinlogSync同步请求给follower slot,同步日志。 follower slot返回BinlogSyncAck报告同步情况。 一致性日志复制 在一致性日志复制场景下: 处理线程把客户端请求写入binlog文件 通过发送BinlogSync请求向从库同步 从库返回BinlogSyncAck报告同步状况 检查从库应答满足大多数后将相应的请求写入db 将response返回客户端 集群元数据处理 我们在codis-dashboard的基础上二次开发了pika manager(简称PM),作为整个集群的全局控制节点,用来部署和调度管理集群。PM里保存了整个集群的元数据及路由信息。 增加了集群创建多表的功能,方便业务根据表的不同来实现业务数据隔离。 支持创建表时指定slot数目和副本数目,方便运维根据业务的规模和故障容忍度创建table。 从逻辑上把group的概念改为replication group,使得原来的进程级别的数据和日志复制转变为slot级别的复制。 支持创建table时创建密码来隔离业务的使用。客户端只需要执行auth和select语句就可以认证并对指定的table进行操作。 支持slot迁移,方便根据业务需求进行扩容和缩容。 集成哨兵模块,PM会不断的向集群中的pika节点发送心跳,监测存活状态。当PM发现leader slot down时,会自动提升binlog偏移最大的slave slot为leader。 存储后端支持元数据写入etcd,保证元数据的高可用。 pika manager通过不断向etcd争抢锁来成为leader,来实现pika manager的高可用。 后记 pika原生集群的推出解决了单机pika受限于磁盘容量的限制,可以按照业务的需求进行水平扩容。但仍然有一些缺陷,如基于raft的内部自动选主功能的缺失,基于range的数据分布,及监控信息的展板等功能。后续版本我们会一一解决这些问题。

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

使用消息队列扩展异步执行的实现方式

背景 你可能在你的项目中用过Spring的@Async注解,以此来将部分方法转化为异步执行,从而提高请求的响应效率 但在服务架构不断的演进之中,这种丢入线程池处理的方式带来的缺陷也愈发明显: 不利于监控 如果意外停机,尚未处理的任务会尽数丢失 在集群中的某个节点要处理大量异步任务时,无法将压力分担到集群中其他节点 项目中若集成了使用ThreadLocal特性的模块或第三方组件,需要注意上下文丢失的问题 思路 使用消息队列作为异步任务的实现方式,这样我们就可以: 大量成熟的MQ中间件都提供了可视化管理平台,监控更加方便 可以用消息队列Header来保存上下文,如用户信息、token等 消息队列的发布-订阅模式可以最大程度利用集群的业务处理能力 更容易保证任务的顺序性 如果有服务节点宕机,可以利用消息确认、消息重试等机制保证任务执行的正确性 实现 为了保证业务代码和实现方案解耦,类似于@Aync方案,我们同样采用注解+拦截器的方式进行逻辑注入 @Around("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)") public Object cut(ProceedingJoinPoint pjp) throws Throwable { ... } 实现思路大同小异,就是读取注解中的队列声明确认发布-订阅关系,然后以丢入消息队列来替换丢入线程池 private String resolveKey(Queue[] queues) { String s = this.beanFactory.resolveEmbeddedValue(queues[0].value()); return (String) resolver.evaluate(s, evalContext); } rabbitTemplate.convertAndSend(resolveKey(queues), args[0]); 为消息队列注入Json转换器,方便对象传输 @Bean public Jackson2JsonMessageConverter producerJackson2MessageConverter() { return new Jackson2JsonMessageConverter(); } 如有需要,我们可以将上下文的用户信息、token等写入消息的Header中 private MessagePostProcessor beforePublishPostProcessor() { return message -> { // setting up context to message header return message; }; } 被异步调用的service代码: @Service @Slf4j public class DemoService { @RabbitListener(queuesToDeclare = @Queue("mytestqueue")) public void checkSome(List<String> tagTuple) { log.warn("check here {}", tagTuple); } } 调用service的controller: @RestController public class DemoController { @Autowired private DemoService demoService; @RequestMapping("check") public Integer checkSome() { ArrayList<String> tagTuple = new ArrayList<>(); tagTuple.add("bar"); tagTuple.add("foo"); demoService.checkSome(tagTuple); return 0; } } 执行查看效果 17:00:14.584TRACE[AbstractHandlerMapping.java:411]Mapped to org.smop.duplex.sample.DemoController#checkSome() 17:00:21.263WARN [DemoService.java:16]check here [bar, foo] 如有帮助或启发,还请点个👍 附代码仓库: https://github.com/s-mop/homer

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

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等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册