服务治理

“服务治理” https://coolshell.me/articles/talking-about-service-governance-microservices-and-service-mesh.html 服务治理,也称为SOA治理,是指用来管理SOA的采用和实现的过程。 服务定义 (服务的范围、接口和边界) 服务部署生命周期 (各个生命周期阶段) 服务版本治理 (包括兼容性) 服务迁移 (启用和退役) 服务注册中心 (依赖关系) 服务消息模型 (规范数据模型) 服务监视 (进行问题确定) 服务所有权 (企业组织) 服务测试 (重复测试) 服务安全 (包括可接受的保护范围) Dubbo开源 直到2011年10月27日,阿里巴巴开源了自己的SOA服务化治理方案的核心框架Dubbo,服务治理和SOA的设计理念开始逐渐在国内软件行业中落地,并被广泛应用。

2021-09-14 · 1 min · 25 words · -

分布式协调组件

“分布式协调组件” 常用的分布式协调组件有 全局功能数据存储/有功能的组件: K-V类: redis、memcache Zookeeper 消息队列 配置中心: Spring Cloud Config等 持久数据存储: MySQL MongoDB 分布式协调组件应用场景: (类比单机中多线程并发安全变量的操作) 分布式session 分布式计数器 分布式锁 分布式队列 先入先出队列 要等所有队列元素聚集之后才能统一安排执行的Barrier模型队列 分布式配置 分布式协调 / 通知 数据发布、订阅 软负载均衡: 域名 -> IP和端口号配置 命名服务: 在分布式环境中,上层应用需要一个全局唯一的名字,类似于数据库中的主键 集群管理: 集群监控 (进群运行时状态收集) 集群控制 (对集群进行操作和控制) Master选举 https://zhuanlan.zhihu.com/p/50901935

2021-09-12 · 1 min · 40 words · -

CR3控制寄存器

“CR3控制寄存器” CR3用来存放页目录表物理内存基地址,每当进程切换时,Linux 就会把下一个将要运行进程的页目录表物理内存基地址等信息存放到CR3寄存器中。 https://blog.csdn.net/SweeNeil/article/details/106171361

2021-09-08 · 1 min · 4 words · -

分布式事务 2PC, 3PC, TCC

“分布式事务 2PC, 3PC, TCC” 数据库事务的概念 在讲述分布式事务的概念之前,我们先来回顾下事务相关的一些概念。 事务的基本概念: 就是一个程序执行单元,里面的操作要么全部执行成功,要么全部执行失败,不允许只成功一半另外一半执行失败的事情发生。例如一段事务代码做了两次数据库更新操作,那么这两次数据库操作要么全部执行成功,要么全部回滚。 事务的基本特性: 我们知道事务有4个非常重要的特性,即我们常说的 (ACID) 。 Atomicity (原子性) :是说事务是一个不可分割的整体,所有操作要么全做,要么全不做;只要事务中有一个操作出错,回滚到事务开始前的状态的话,那么之前已经执行的所有操作都是无效的,都应该回滚到开始前的状态。 Consistency (一致性) : 是说事务执行前后,数据从一个状态到另一个状态必须是一致的,比如A向B转账 (A、B的总金额就是一个一致性状态) ,不可能出现A扣了钱,B却没收到的情况发生。 Isolation (隔离性) : 多个并发事务之间相互隔离,不能互相干扰。关于事务的隔离性,可能不是特别好理解,这里的并发事务是指两个事务操作了同一份数据的情况;而对于并发事务操作同一份数据的隔离性问题,则是要求不能出现脏读、幻读的情况,即事务A不能读取事务B还没有提交的数据,或者在事务A读取数据进行更新操作时,不允许事务B率先更新掉这条数据。而为了解决这个问题,常用的手段就是加锁了,对于数据库来说就是通过数据库的相关锁机制来保证。 Durablity (持久性) : 事务完成后,对数据库的更改是永久保存的,不能回滚。 关于数据库事务的基本概念大家可以去网上搜一下,这里只是给大家回顾下事务的基本概念及特性,诸如事务并发问题、事务隔离级别等大家如有遗忘可以去回顾下 (tips: 面试经常会问到的问题哦) 。 3 什么是分布式事务 以上内容我们回顾了下事务的基本概念,那么分布式事务又是个什么概念呢?它与数据库事务之间又有什么区别呢? 其实分布式事务从实质上看与数据库事务的概念是一致的,既然是事务也就需要满足事务的基本特性 (ACID) ,只是分布式事务相对于本地事务而言其表现形式有很大的不同。举个例子,在一个JVM进程中如果需要同时操作数据库的多条记录,而这些操作需要在一个事务中,那么我们可以通过数据库提供的事务机制 (一般是数据库锁) 来实现。 而随着这个JVM进程 (应用) 被拆分成了微服务架构,原本一个本地逻辑执行单元被拆分到了多个独立的微服务中,这些微服务又分别操作不同的数据库和表,服务之间通过网络调用。 举个例子: 服务A收到一笔购物下单请求后,需要调用服务B去支付,支付成功则处理购物订单为待发货状态,否则就需要将购物订单处理为失败状态。 (如图所示) 640?wx_fmt=png 在上面这个例子中会不会出现服务B支付成功了,但是由于网络调用的问题没有通知到服务A,导致用户付了钱,但是购物订单无法显示支付成功的状态呢? 答案是这种情况是普遍存在的,因为服务B在处理成功后需要向服务A发送网络请求,而这个过程是极有可能失败的。那么如何确保“服务A->服务B”这个过程能够组成一个事务,要么全部成功、要么全部失败呢?而这就是典型的需要通过分布式事务解决的问题。 分布式事务是为了解决微服务架构 (形式都是分布式系统) 中不同节点之间的数据一致性问题。这个一致性问题本质上解决的也是传统事务需要解决的问题,即一个请求在多个微服务调用链中,所有服务的数据处理要么全部成功,要么全部回滚。当然分布式事务问题的形式可能与传统事务会有比较大的差异,但是问题本质是一致的,都是要求解决数据的一致性问题。 而分布式事务的实现方式有很多种,最具有代表性的是由Oracle Tuxedo系统提出的XA分布式事务协议。XA协议包括两阶段提交 (2PC) 和三阶段提交 (3PC) 两种实现,接下来我们分别来介绍下这两种实现方式的原理。 两阶段提交 (2PC) 分布式事务的解决方案 两阶段提交/XA 两阶段提交,顾名思义就是要分两步提交。存在一个负责协调各个本地资源管理器的事务管理器,本地资源管理器一般是由数据库实现,事务管理器在第一阶段的时候询问各个资源管理器是否都就绪?如果收到每个资源的回复都是 yes,则在第二阶段提交事务,如果其中任意一个资源的回复是 no, 则回滚事务。 大致的流程: 第一阶段 (prepare) : 事务管理器向所有本地资源管理器发起请求,询问是否是 ready 状态,所有参与者都将本事务能否成功的信息反馈发给协调者; 第二阶段 (commit/rollback): 事务管理器根据所有本地资源管理器的反馈,通知所有本地资源管理器,步调一致地在所有分支上提交或者回滚。 ...

2021-09-07 · 2 min · 391 words · -

Pulsar

Pulsar Pulsar [ˈpʌlsɑːr] Apache Pulsar (孵化器项目)是一个企业级的发布订阅 (pub-sub)消息系统,最初由 Yahoo 开发,并于 2016 年底开源 https://www.infoq.cn/article/2017/11/apache-pulsar-brief-introduction

2021-09-01 · 1 min · 12 words · -

celery

celery https://github.com/celery/celery celery 是一个基于分布式消息传输的异步任务队列,它专注于实时处理,同时也支持任务调度。它的执行单元为任务(task),利用多线程, 如 Eventlet,gevent等,它们能被并发地执行在单个或多个职程服务器(worker servers)上。任务能异步执行(后台运行)或同步执行(等待任务完成)。 # install rabbitmq https://wangyue.dev/rabbitmq # install celery pip install celery # 添加用户跟密码, rabbitmqctl add_user test test123 rabbitmqctl add_user user0 password0 # 添加虚拟主机 rabbitmqctl add_vhost test_vhost rabbitmqctl add_vhost vhost0 # 为用户添加标签, rabbitmqctl set_user_tags test test_tag rabbitmqctl set_user_tags user0 tag0 # 设置用户权限, rabbitmqctl set_permissions -p test_vhost test ".*" ".*" ".*" rabbitmqctl set_permissions -p vhost0 user0 ".*" ".*" ".*" # run celery server celery -A tasks worker --loglevel=INFO ———————————————— 版权声明:本文为CSDN博主「吴秋霖」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qiulin_wu/article/details/106119757 ...

2021-08-16 · 2 min · 280 words · -

sasl

“sasl” SASL - 简单认证和安全层 身份验证是很多C/S模式应用协议的通用需求,为了避免每个协议都单独实现一套验证逻辑,SASL(Simple Authentication and Secure Layer)被提出了, 它定位成为基于可靠连接的应用协议提供身份验证和数据安全服务的通用框架。SASL定义了通用的身份验证信息交换的流程, 并且包含一系列验证机制。这些验证机制完成具体的身份验证逻辑。这样,SASL就成为了一个将应用协议和验证机制相连接的抽象层,如下图所示。 +----+ +----+ +----+ +-------------------+ |SMTP| |LDAP| |XMPP| |Other protocols ...| +--+-+ +--+-+ +--+-+ +--+----------------+ | | | | | | | | ------+--------+---------+--------+------------------ SASL abstraction layer ------+--------+---------+--------+------------------ | | | | | | | | +-----+--+ +--+---+ +--+--+ +--+-----------------+ |EXTERNAL| |GSSAPI| |PLAIN| |Other machanisms ...| +--------+ +------+ +-----+ +--------------------+ 任何应用协议都可以使用任何验证机制,而具体使用哪个机制则由应用协议的客户端和服务器进行协商。 分别以”C:”和”S:”代表客户端和服务端,SASL规定的验证信息交换的基本流程为: C: 请求验证交换 S: 最初的挑战码 C: 最初的响应消息 <额外的挑战码/响应消息> S: 身份验证结果 根据机制不同,流程略有差异。 ...

2021-08-13 · 4 min · 794 words · -

tesla

“tesla” 基础版辅助驾驶 (BAP/AP 增强版自动辅助驾驶 (EAP) EAP Enhanced Autopilot,增强型自动驾驶 和完全自动驾驶 (FSD) FSD Full Self-Driving 完全自动驾驶 EAP 自动辅助导航驾驶: 自动驶入和驶出高速公路匝道或立交桥岔路口,超过行驶缓慢的车辆。 自动辅助变道: 在高速公路上自动辅助变换车道。 自动泊车: 平行泊车与垂直泊车。 智能召唤: 在合适的场景下,停在车位的车辆会响应您的召唤,驶出车位并前往您所在的位置。 FSD NOA Navigate on Autopilot自动辅助导航驾驶 (简称NOA) 启动车辆即启动, 开启该选项后,在具备NOA使用条件的路段,Model 3将自动开启NOA功能。 根据速度变道 (即自动超车) 特斯拉官方称之为速控变道,在行驶中存在两种普遍情况,一种是本车道内行驶时前方有慢车阻挡,需要变道超车;另一种是正常行驶中,有慢车从前方进入到本车道,此时需要变道以保持车速。该功能有三种变道模式: 柔和、普通、极速。柔和可以理解为以最保守的变道方式,极速则最激进的变道模式。 要求变道确认 开启这一功能后,当NOA驾驶中,Model 3判断需要变线时,将提醒驾驶员打转向灯进行确认,然后才能执行变线操作。而选择“否”,关闭这一功能后,Model 3将自动变线,而不再要求打转向灯进行确认。 变道提醒 开启后,在自动变道时,Model 3会通过蜂鸣或振动方式提醒驾驶员即将进行变道操作。

2021-08-06 · 1 min · 43 words · -

中间件, Middleware

“中间件, Middleware” 中间件 中间件一词的由来中间件这个术语第一次出现是 1968 年在德国加尔米施帕滕基兴举办的 NATO 软件工程大会 结束后发表的一份报告中。这届大会正式确定了软件工程(Software Engineering)的概念,同时还探讨了软件设计、生产和分发等主题。 中间件的定义 中间件 (英语: Middleware) ,又译中间件、中介层,是一类提供系统软件和应用软件之间连接、便于软件各部件之间的沟通的软件,应用软件可以借助中间件在不同的技术架构之间共享信息与资源。中间件位于客户机服务器的操作系统之上,管理着计算资源和网络通信。 – 维基百科什么不是中间件我们按照类别来看一些经常会遇到的一些不是中间件的概念- 业务平台不是中间件,业务平台是从服务的视角抽象的能同时支撑多个业务,业务之间的信息能形成交互和增强的平台。- 营销工具不是中间件,营销工具是直接作用于最终消费者用户的软件或者插件服务。- 二方/三方工具包不是中间件,二方/三方工具包是在各种场景的程序开发过程中沉淀的一些常用工具类(功能)的集合,包含于软件代码本身。- SaaS 不是中间件,SaaS(Software as a Service) 更多的是一种软件交付模式,无需用户安装,通过网络在线访问的一种服务模式。- PaaS 不是中间件,PaaS(Platform as a Service) 将软件研发的平台做为一种服务,提供软件部署平台(强调的是屏蔽系统和软件细节的runtime平台)。评判关键从定义可以总结出评判的几个地方 性质: 中间件是软件。 作用层级: 系统软件和应用软件之间、软件各部件之间;管理客户机与系统软件之间的计算资源和网络通信。 服务对象: 中间件为应用软件服务,应用软件为最终用户服务,最终用户并不直接使用中间件。 中间件的好处 中间件能给客户带来什么?为上层应用软件的开发提供便捷的、开箱即用的服务交互和计算的能力,缩短开发周期;屏蔽底层runtime的差异;节省应用本身的系统资源,减少运行成本。 中间件分类 什么时候使用中间件 基于中间件的定义我们知道中间件是连接软件与系统之间的服务,那么我们什么时候使用了中间件,在哪些地方用到了中间件了。我们不妨假设一个http请求过程来窥视一番。当你在浏览器中输入一个网址时,它会通过 DNS 解析到目标服务注册的公网IP地址请求到达目标服务的 web 反向代理服务器 Tengine 之后,经过一定的过滤转发到目标服务A上服务A通过 RPC框架 Dubbo 请求服务B的结果做中间计算,并且从 Tair 缓存中读取计算因子,计算结果服务A接着使用 Druid 通过 TDDL 写入计算结果到 MySQL Master 节点然后返回结果异步过程中 Canal 通过模拟 Binlog 主从复制的原理,迅速将这条 Binlog 消费并下发到消息队列 RocketMQ服务C通过 RocketMQ 消费到事件之后,通过配置中心 ConfigServer 拉取到的策略进行对应策略的事件处理。这个过程中我们使用了一系列的中间件来协同各个微服务完成整个流程,如web反向代理服务器 Tengine、RPC框架 Dubbo、缓存 Tair、连接池 Driud、数据库代理层 TDDL、Binlog 同步工具 Canal、消息队列 RocketMQ、配置中心 ConfigServer。 ...

2021-07-29 · 1 min · 148 words · -

负载均衡

负载均衡 负载均衡 load balancing 何为负载均衡?顾名思义就是让系统的负载根据一定的规则均衡地分配在所有参与工作的服务器上,从而最大限度地提升系统整体的运行效率。 LVS、Nginx 当前大多数的互联网系统都使用了服务器集群技术,集群是将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是 Web 应用服务器集群,也可以是数据库服务器集群,还可以是分布式缓存服务器集群等等。 在实际应用中,在 Web 服务器集群之前总会有一台负载均衡服务器,负载均衡设备的任务就是作为 Web 服务器流量的入口,挑选最合适的一台 Web 服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。 最近几年很火的「云计算」以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的,是后端的集群。 LVS、Nginx、HAProxy 是目前使用最广泛的三种软件负载均衡软件。 一般对负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术。具体的应用需求还得具体分析,如果是中小型的 Web 应用,比如日 PV 小于1000万,用 Nginx 就完全可以了;如果机器不少,可以用 DNS 轮询,LVS 所耗费的机器还是比较多的;大型网站或重要的服务,且服务器比较多时,可以考虑用 LVS。 目前关于网站架构一般比较合理流行的架构方案: Web 前端采用 Nginx/HAProxy+Keepalived 作负载均衡器;后端采用 MySQ L数据库一主多从和读写分离,采用 LVS+Keepalived 的架构。 LVS LVS 是 Linux Virtual Server 的简称,也就是 Linux 虚拟服务器。现在 LVS 已经是 Linux 标准内核的一部分,从 Linux2.4 内核以后,已经完全内置了 LVS 的各个功能模块,无需给内核打任何补丁,可以直接使用 LVS 提供的各种功能。 LVS 自从1998年开始,发展到现在已经是一个比较成熟的技术项目了。 LVS 的体系结构 LVS 架设的服务器集群系统有三个部分组成: (1) 最前端的负载均衡层,用 Load Balancer 表示 (2) 中间的服务器集群层,用 Server Array 表示 ...

2021-07-26 · 2 min · 424 words · -

Java NIO Channel, buffer

“Java NIO Channel, buffer” Channel Channel Characteristics Java NIO Channel Classes buffer 什么是缓冲区? 缓冲区类型 缓冲区内部细节 NIO Buffer Characteristics How to Read from NIO Buffer How to Write to NIO Buffer Java NIO 读写文件实例程序 Channel Java NIO中,channel用于数据的传输。类似于传统IO中的流的概念。channel的两端是buffer和一个entity,不同于IO中的流,channel是双向的,既可以写入,也可以读取。而流则是单向的,所以channel更加灵活。我们在读取数据或者写入数据的时候,都必须经过channel和buffer,也就是说,我们在读取数据的时候,先利用channel将IO设备中的数据读取到buffer,然后从buffer中读取,我们在写入数据的时候,先将数据写入到buffer,然后buffer中的数据再通过channel传到IO设备中。 image.png 我们知道NIO的特点就是将IO操作更加类似于底层IO的流程。 我们可以通过底层IO的机制更好的理解channel。 所有的系统I/O都分为两个阶段: 等待就绪和操作。 等待就绪就是从IO设备将数据读取到内核中的过程。 操作就是将数据从内核复制到进程缓冲区的过程。 channel就可以看作是IO设备和内核区域的一个桥梁,凡是与IO设备交互都必须通过channel,而buffer就可以看作是内核缓冲区。这样整个过程就很好理解了。 我们看一下读取的过程 先从IO设备,网卡或者磁盘将内容读取到内核中,对应于NIO就是从网卡或磁盘利用channel将数据读到buffer中 然后就是内核中的数据复制到进程缓冲区,对应于就是从buffer中读取数据 写入的过程则是: 先从进程将数据写到内核中,对应于就是进程将数据写入到buffer中, 然后内核中的数据再写入到网卡或者磁盘中,对应于就是,buffer中的数据利用channel传输到IO设备中。 image.png 以上其实就是NIO基本的利用channel和buffer进行读取和写入的流程。 Channel Characteristics 与传统IO中的流不同,channel是双向的,可读可写 channel从buffer中读取数据,写入数据也是先写入到buffer channel可以实现异步读写操作 channel可以设置为阻塞和非阻塞的模式 非阻塞模式意味着,当读不到数据或者缓冲区已满无法写入的时候,不会把线程睡眠 只有socket的channel可以设置为非阻塞模式,文件的channel是无法设置的。文件的IO一定是阻塞的 如果是文件channel的话,channel可以在channel之间传输数据 Java NIO Channel Classes channel主要有两大类,四个具体的类 FileChannel 文件的读写是不可以设置为非阻塞模式 SocketChannel 根据tcp和udp,服务端和客户端,又可以分为, SocketChannel, ServerSocketChannel and DatagramChannel.它们是可以设置为非阻塞模式的 buffer 什么是缓冲区? Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。 在 NIO 中加入 Buffer 对象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接读到 Stream 对象中。 在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。 缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。 ...

2021-07-25 · 3 min · 481 words · -

Cuckoo filter, 布谷过滤器

“Cuckoo filter, 布谷过滤器” 过滤器系列 (二) —— Cuckoo filter 这一篇讲的是布谷过滤器(cuckoo fliter),这个名字来源于更早发表的布谷散列(cuckoo hash),尽管我也不知道为什么当初要给这种散列表起个鸟名=_= 由于布谷过滤器本身的思想就源自于布谷散列,那么我们就从布谷散列开始说它的设计思想。产生布谷散列表的一个重要背景是人们对于球盒问题的分析: 给定N个球,随机的放在N个盒子里,在装球最多的盒子里,球的个数的期望是多少?答案是Θ(logN/loglogN),这个问题其实就是散列表装填因子为1时的情况分析。后来有一天,人们发现: 每次放球的时候,如果随机选择两个盒子,将球放到当时较空的那个盒子里,那么这个期望就变成了Θ(loglogN),这个界小于之前的界,这给了布谷散列表作者启发。 一个布谷散列表通常有两张 (一般来说) 表,分别有一个对应的Hash函数,当有新的项插入的时候,它会计算出这个项在两张表中对应的两个位置,这个项一定会被存在这两个位置之一,而具体是哪一个却不确定。 下图是一个布谷散列表的初始化示意图: image 现在我们假设有一些项要存入散列表,其每个项都有其对应的两个位置,先插入第一项A image 由于插入A的时候其两个候选位置 (0,2) 都没有占用,所以选择第一张表或者是第二张表都可以,我们在这里默认先选择第一张表,然后插入第二项B image 我们看到原来的A的位置被B占用,而A被“踢”到它的备选位置表二的2号位置上了,这就是当发生位置冲突时,布谷散列表的处理逻辑,后来的数据项将会把之前占用的项踢到另一个位置上。我们接下来插入第三项C image 没有冲突,顺利搞定,接着插入D image D成功的把C踢走了,其实看到这里读者应该在猜想,会不会有一种情况,即被踢走的数据的另一个备选位置也被占用了,这样怎么办?答案是继续踢,一个踢一个,直到大家都找到自己合适的归宿为止。那么如果发现出现了循环怎么办?答案是GG,这代表布谷散列表走到了极限 image 插入E image 这里就发生了多次替换的情况,F代替了E,E代替了A,A代替了B,B找到了空余的位子 读者可以考虑一下,如果这个时候要想插入一个“G”,其备选位置是1,2,这样的话会出现什么情况? 好了,布谷散列表大概介绍完了,现在该布谷过滤器了。布谷过滤器的主要也是通过布谷散列来实现的,其主要变化是: 1.我们不将原来的数据完整的存进来,作为过滤器,当然要省点空间,选用的办法设计一个指纹,将比较大的原数据变成了一个个指纹串,这样就大大节省了空间。 2.由于第一点所说,存储的不是原数据,那么在替换位置的时候,我们需要再次计算原来的数据的备选位置,这样一来布谷散列表的方法就失效了。在这里,作者设计了一个方法,他将两个Hash函数变成了一个Hash函数,第一张表的备选位置是Hash(x),第二张表的备选位置是Hash(x)⊕hash(fingerprint(x)),即第一张表的位置与存储的指纹的Hash值做异或运算。这样做的优点就是不用再另外存储元素的备选位置,在替换时,可以直接用异或来计算出其另一个备选位置。 (读者可以想想如何通过表二的位置计算出元素在表一中的位置) 3.插入时,优先选择空位置,而不是尽可能的踢走其他元素。 插入伪代码如下: Copy Algorithm 1: Insert(x) f = fingerprint(x) i1 = hash(x) i2 = i1 xor hash(f) if bucket[i1] or bucket[i2] has an empty entry then //只要有空位就先插入空位里 add f to that bucket return Done i = randomly pick i1 or i2 for n=0;n<MaxNumKicks;++n randomly select an entry e from bucket[i]; swap f and the fingerprint stored in entry e; i = i xor hash(f) if bucket[i] has an empty entry then add f to bucket[i] return Done return Failure // 已经出现循环情况了 查找伪代码如下: ...

2021-07-24 · 1 min · 199 words · -

redis scan

“redis scan” redis用scan代替keys 众所周知,当redis中key数量越大,keys 命令执行越慢,而且最重要的会阻塞服务器,对单线程的redis来说,简直是灾难,且在生产环境,keys命令一般是被禁止的。scan可用来替换keys请求。 所以说官方的建议是: 生产环境屏蔽掉 keys 命令。 在对键进行增量式迭代的过程中, 键可能会被修改, 所以增量式迭代命令只能对被返回的元素提供有限的保证 。 scan用法 SCAN cursor [MATCH pattern] [COUNT count] scan 0 match *news* count 3 scan是一个增量迭代式的命令,这意味着每次调用这个命令都会返回一个游标cursor,该游标用于下次查询。查询开始时,cursor值为0;当查询结束时,cursor的值也回归到0。 举个例子: 开始查询,scan cursor为0,返回的cursor为17 redis 127.0.0.1:6379> scan 0 “17” “key:12” “key:8” “key:4” “key:14” “key:16” “key:17” “key:15” “key:10” “key:3” “key:7” “key:1” 下一次查询,以上一次查询返回的cursor为起始位置 redis 127.0.0.1:6379> scan 17 查询返回cursor为0,标志查询结束 “0” “key:5” “key:18” “key:0” “key:2” “key:19” “key:13” “key:6” “key:9” “key:11” count count可理解为迭代过程中的步长,指每次调用scan时应执行的工作量,该值默认为10。每次调用count的值可以随意指定,只要下一次传递cursor是上一次调用返回的cursor就行。 match 需要注意的是,match操作时在元素被检出后执行的。假设redis中只有少量元素符合pattern条件,那么很可能在多次调用中scan返回的数据为空,例如: 查找key中包含11的键,因为这里没有指定count,所以默认为10 redis 127.0.0.1:6379> scan 0 MATCH 11 ...

2021-07-21 · 2 min · 315 words · -

gcm cbc

“gcm cbc” 主要区别 AES-GCM可以并行加密解密,AES-CBC的模式决定了它只能串行地进行加密。因为加密是耗时较久的步骤,且加密的方式是相同的,所以并行地实现AES-GCM算法的时候,其效率是高于AES-CBC的; AES-GCM提供了GMAC信息校验码,用以校验密文的完整性。AES-CBC没有,无法有效地校验密文的完整性; AES-GCM是流加密的模式,不需要对明文进行填充。AES-CBC是块加密的模式,需要对明文进行填充。(AES-GCM中进行AES加密的是counter,AES-CBC中进行AES加密的是明文块); 由于AES-CBC中必须要用到padding,导致最后一个明文块与其他密文块不同,因此可能会受到padding Oracle attacks,从而可以直接通过初始向量IV和密码,即可得到明文。 https://blog.csdn.net/weixin_39680609/article/details/111159600

2021-07-17 · 1 min · 10 words · -

MESI

“MESI” CPU 在执行指令的时候需要从 memory 中获取指令和需要的数据,但是 CPU 的速度要比 memory 快很多,这就导致了 CPU 大部分时间都不是在做运算上而是用在了和 memory 进行数据的 I/O 过程中,这样性能是很低的。这就导致了 CPU cache 的产生,CPU 将数据从 memory 读取到 cache 中,在 cache 中对数据进行读写的速度是很快的,这样就提高了性能。CPU 执行运算时不可能需要某一个数据就去读取一次,这样就增加了 I/O 的频率,导致性能低下。所以会一次性读取一块内存的数据存放到 cache 中, 这个块称为 “cache line” , cache line 的大小是固定的, 通常是 2 的 N 次方,在 16 ~ 256 byte 不等。当某个数据首次被 CPU 访问时, cache 中不存在,这称为 “cache miss” (或 “startup” 或 “warmup” cache miss)。这意味着 CPU 必须要去 memory 中读取该数据,这时候 CPU 必须等待 (stalled)。当 cache 装满后,后续的 cache miss 需要置换 cache 中现有的数据,这样的 cache miss 被称为 “capacity miss” 。如果随后又访问了被替换的 cache line ,这时的 cache miss 被称为 “associativity miss” 。 ...

2021-07-10 · 3 min · 454 words · -

Store Buffer

“Store Buffer” 就像spinlock的进化史,软件工程师会对自己的代码做足够的优化以提高性能。同样,硬件工程也不甘示弱,尽最大的努力设计硬件以获取更好的性能。我们引入高速缓存的目的就是为了降低内存访问的延迟,谁知硬件工程师依然不满足于高速缓存带来的延迟,当然软件工程师或许也不满足。为了进一步加快内存访问速度,硬件引入了新的缓存 - store buffer。随着store buffer的引入,彻底刷新了软件工程师对代码执行流的认知。store buffer又是怎么刷新我们的认知呢? 文章测试代码已经开源,可以点击这里查看。 store buffer是什么 在之前的文章介绍中,我们了解到每个CPU都会有自己私有L1 Cache。从我了解的资料来说,L1 Cache命中的情况下,访问数据一般需要2个指令周期。而且当CPU遭遇写数据cache未命中时,内存访问延迟增加很多。硬件工程师为了追求极致的性能,在CPU和L1 Cache之间又加入一级缓存,我们称之为store buffer。store buffer和L1 Cache还有点区别,store buffer只缓存CPU的写操作。store buffer访问一般只需要1个指令周期,这在一定程度上降低了内存写延迟。不管cache是否命中,CPU都是将数据写入store buffer。store buffer负责后续以FIFO次序写入L1 Cache。store buffer大小一般只有几十个字节。大小和L1 Cache相比,确实是小巫见大巫了。 store buffer对程序的影响 我们现在知道,当存在store buffer的情况下。针对写操作,CPU直接把数据扔给store buffer。后续store buffer负责以FIFO次序写回L1 Cache。这会对我们的程序产生什么影响呢?我们来看个例子。 static int x = 0, y = 0; static int r1, r2; static void int thread_cpu0(void) { x = 1; /* 1) / r1 = y; / 2) */ } static void int thread_cpu1(void) { y = 1; /* 3) / r2 = x; / 4) */ } ...

2021-07-10 · 2 min · 322 words · -

编译器指令重排, Compiler Instruction Reordering

编译器指令重排, Compiler Instruction Reordering compiler的主要工作就是将对人们可读的源码转化成机器语言,机器语言就是对CPU可读的代码。因此,compiler可以在背后做些不为人知的事情。我们考虑下面的C语言代码: int a, b; void foo(void) { a = b + 1; b = 0; } 使用 aarch64-linux-gnu-gcc 在不优化代码的情况下编译上述代码,使用 objdump 工具查看 foo() 反汇编结果 : … ldr w0, [x0] // load b to w0 add w1, w0, #0x1 … str w1, [x0] // a = b + 1 … str wzr, [x0] // b = 0 我们应该知道 Linux 默认编译优化选项是-O2,因此我们采用-O2 优化选项编译上述代码,并反汇编得到如下汇编结果: : ldr w2, [x0] // load b to w2 str wzr, [x0] // b = 0 add w0, w2, #0x1 str w0, [x1] // a = b + 1 比较优化和不优化的结果,我们可以发现。在不优化的情况下,a 和 b 的写入内存顺序符合代码顺序 (program order)。但是-O2 优化后,a 和 b 的写入顺序和 program order 是相反的。-O2优化后的代码转换成C语言可以看作如下形式: ...

2021-07-09 · 3 min · 566 words · -

文件锁

“文件锁” 文件锁也被称为记录锁,文件锁如果深讲的话,内容不少 (比如文件锁最起码分为了建议锁和强制性锁) 这里不准备深纠,深纠没有任何意义 主要是为了对比学习各种的加锁机制,比如进程有进程信号量加锁机制,线程有线程互斥锁、线程信号量等 加锁机制,学习文件锁有助于我们对比理解,对于我们后续理解驱动课程中的内核锁,c++、java等库所提供的 资源保护的锁机制,都是很有意义的。 当然还有另一个目的,那就是练习fcntl函数的使用,因为文件锁也需要用到fcntl函数。 由于文件锁的知识点是刚才所讲的这样一种存在,所以对于文件锁内容的学习,理解>实际使用。 4.1 文件锁的作用 顾名思义,就是用来保护文件数据的。 当多个进程共享读写同一个文件时,为了不让进程们各自读写数据时相互干扰,我们可以使用进程信号量来 互斥实现,除了可以使用进程信号量以外,还可以使用我们这里的的“文件锁”来实现,而且功能更丰富, 使用起来相对还更容易些。 4.2 多进程读写文件 file_lock.png 多进程共享读写同一个文件时,如果数据很重要的话,为了防止数据相互修改,应该满足如下读写条件: (1) 写与写应该互斥 当某个进程正在写文件,而且在数据没有写完时,其它进程不能写,否者会相互打乱对方写的数据 (2) 读与写也应该是互斥的 分两种情况: 某个进程正在写数据,而且在数据没有写完时,其它进程不能读数据因为别人在没有写完之前,读到的数据是不完整的,所以读和写时互斥的 某个进程正在读数据,在数据没有读完之前,其它进程不能写数据因为可能会扰乱别人读到的数据 (3) 读与读共享 某个进程在读数时,就算数据没有读完,其它进程也可以共享读数据,并不需要互斥等别人读完后才能读。 因为读文件是不会修改文件的内容,所以不用担心数据相互干扰的问题 总结起来就是,多进程读写文件时,如果你想进行资源保护的话,完美的资源保护应该满足如下这样的。 写与写之间互斥 读与写之间互斥 读与读之间共享 如何实现以上读写要求? 如果使用信号量来实现保护的话,只能是一律互斥,包括读与读都是互斥的,不能够向上面描述的,能互斥又能共享,但是文件锁可以做到 4.3 文件锁 4.3.1 文件锁的读锁与写锁 对文件加锁时可以加两种锁,分别是“读文件锁”和“写文件锁”,我们这里简称为读锁和写锁。 读锁、写锁之间关系 (1) 读锁和读锁共享: 可以重复加读锁,别人加了读锁在没有解锁之前,我依然可以加读锁,这就是共享。 (2) 读锁与写锁互斥: 别人加了读锁没有解锁前,加写锁会失败,反过来也是如此。 加锁失败后两种处理方式, 阻塞,直到别人解锁然后加锁成功为止 出错返回,不阻塞 (3) 写锁与写锁互斥: 别人加了写锁在没有解锁前,不能加写锁,加写锁会失败。 加锁失败后两种处理方式, 阻塞,直到别人解锁然后加锁成功为止 出错返回,不阻塞 常用的是阻塞加锁,至于如何实现阻塞和非阻塞,后面详细讲 4.3.2 使用文件锁对文件进行保护 读文件时加读锁,写文件时就加写锁,然后就可以很容易的实现符合如下要求的资源保护。 写与写之间互斥 读与写之间互斥 读与读之间共享 4.4 文件锁的加锁方式 (1) 对整个文件内容加锁 对整个文件加锁是最常用的文件锁的加锁方式。 当你对整个文件加锁时,如果文件的长度因为写入新数据或者截短而发生了变化,加锁内容的长度会 自动变化,保证对内容变化着的整个文件加锁。 (2) 对文件某部分内容加锁 不过一般来说是,对多少内容加锁,就对多少内容解锁,如果你是对整个文件加锁,就将整个文件解锁。 但是实际上加锁和实际解锁的长度可以不相同,比如我对1000个字节的内容加了锁,但是可以只对其中的 100字节解锁,不过这种情况用的少,知道有这么回事即可 4.5 文件锁的实现 实现文件锁时,我们还是需要使用fcntl函数 4.5.1 再看看fcntl的函数原型 ...

2021-07-08 · 5 min · 890 words · -

拜占庭将军问题

“拜占庭将军问题” 接触区块链的同学,多少都听说过拜占庭将军问题,经常看到或听到某某区块链使用某某算法解决了拜占庭将军问题,那么究竟什么是拜占庭将军问题呢? 什么是拜占庭将军问题 也被称为“拜占庭容错”、“拜占庭将军问题”。 拜占庭将军问题是 Leslie Lamport (2013年的图灵讲得主) 用来为描述分布式系统一致性问题 (Distributed Consensus) 在论文中抽象出来一个著名的例子。 这个例子大意是这样的: 拜占庭帝国想要进攻一个强大的敌人,为此派出了10支军队去包围这个敌人。这个敌人虽不比拜占庭帝国,但也足以抵御5支常规拜占庭军队的同时袭击。这10支军队在分开的包围状态下同时攻击。他们任一支军队单独进攻都毫无胜算,除非有至少6支军队 (一半以上) 同时袭击才能攻下敌国。他们分散在敌国的四周,依靠通信兵骑马相互通信来协商进攻意向及进攻时间。困扰这些将军的问题是,他们不确定他们中是否有叛徒,叛徒可能擅自变更进攻意向或者进攻时间。在这种状态下,拜占庭将军们才能保证有多于6支军队在同一时间一起发起进攻,从而赢取战斗? 拜占庭将军问题中并不去考虑通信兵是否会被截获或无法传达信息等问题,即消息传递的信道绝无问题。Lamport已经证明了在消息可能丢失的不可靠信道上试图通过消息传递的方式达到一致性是不可能的。所以,在研究拜占庭将军问题的时候,已经假定了信道是没有问题的. 问题分析 单从上面的说明可能无法理解这个问题的复杂性,我们来简单分析一下: 先看在没有叛徒情况下,假如一个将军A提一个进攻提议 (如: 明日下午1点进攻,你愿意加入吗?) 由通信兵通信分别告诉其他的将军,如果幸运中的幸运,他收到了其他6位将军以上的同意,发起进攻。如果不幸,其他的将军也在此时发出不同的进攻提议 (如: 明日下午2点、3点进攻,你愿意加入吗?) ,由于时间上的差异,不同的将军收到 (并认可) 的进攻提议可能是不一样的,这是可能出现A提议有3个支持者,B提议有4个支持者,C提议有2个支持者等等。 再加一点复杂性,在有叛徒情况下,一个叛徒会向不同的将军发出不同的进攻提议 (通知A明日下午1点进攻, 通知B明日下午2点进攻等等) ,一个叛徒也会可能同意多个进攻提议 (即同意下午1点进攻又同意下午2点进攻) 。 叛徒发送前后不一致的进攻提议,被称为“拜占庭错误”,而能够处理拜占庭错误的这种容错性称为「Byzantine fault tolerance」,简称为BFT。 相信大家已经可以明白这个问题的复杂性了。 https://learnblockchain.cn/2018/02/05/bitcoin-byzantine/

2021-07-06 · 1 min · 39 words · -

Gossip

“Gossip” Gossip是什么 Gossip协议是一个通信协议,一种传播消息的方式,灵感来自于: 瘟疫、社交网络等。使用Gossip协议的有: Redis Cluster、Consul、Apache Cassandra等。 六度分隔理论 说到社交网络,就不得不提著名的六度分隔理论。1967年,哈佛大学的心理学教授Stanley Milgram想要描绘一个连结人与社区的人际连系网。做过一次连锁信实验,结果发现了“六度分隔”现象。简单地说: “你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过六个人你就能够认识任何一个陌生人。 数学解释该理论: 若每个人平均认识260人,其六度就是260↑6 =1,188,137,600,000。消除一些节点重复,那也几乎覆盖了整个地球人口若干多多倍,这也是Gossip协议的雏形。 原理 Gossip协议基本思想就是: 一个节点想要分享一些信息给网络中的其他的一些节点。于是,它周期性的随机选择一些节点,并把信息传递给这些节点。这些收到信息的节点接下来会做同样的事情,即把这些信息传递给其他一些随机选择的节点。一般而言,信息会周期性的传递给N个目标节点,而不只是一个。这个N被称为fanout (这个单词的本意是扇出) 。 用途 Gossip协议的主要用途就是信息传播和扩散: 即把一些发生的事件传播到全世界。它们也被用于数据库复制,信息扩散,集群成员身份确认,故障探测等。 基于Gossip协议的一些有名的系统: Apache Cassandra,Redis (Cluster模式) ,Consul等。 图解 接下来通过多张图片剖析Gossip协议是如何运行的。如下图所示,Gossip协议是周期循环执行的。图中的公式表示Gossip协议把信息传播到每一个节点需要多少次循环动作,需要说明的是,公式中的20表示整个集群有20个节点,4表示某个节点会向4个目标节点传播消息: Gossip Protocol 如下图所示,红色的节点表示其已经“受到感染”,即接下来要传播信息的源头,连线表示这个初始化感染的节点能正常连接的节点 (其不能连接的节点只能靠接下来感染的节点向其传播消息) 。并且N等于4,我们假设4根较粗的线路,就是它第一次传播消息的线路: first infected node 第一次消息完成传播后,新增了4个节点会被“感染”,即这4个节点也收到了消息。这时候,总计有5个节点变成红色: infected nodes 那么在下一次传播周期时,总计有5个节点,且这5个节点每个节点都会向4个节点传播消息。最后,经过3次循环,20个节点全部被感染 (都变成红色节点) ,即说明需要传播的消息已经传播给了所有节点: infected all nodes 需要说明的是,20个节点且设置fanout=4,公式结果是2.16,这只是个近似值。真实传递时,可能需要3次甚至4次循环才能让所有节点收到消息。这是因为每个节点在传播消息的时候,是随机选择N个节点的,这样的话,就有可能某个节点会被选中2次甚至更多次。 发送消息 由前面对Gossip协议图解分析可知,节点传播消息是周期性的,并且每个节点有它自己的周期。另外,节点发送消息时的目标节点数由参数fanout决定。至于往哪些目标节点发送,则是随机的。 一旦消息被发送到目标节点,那么目标节点也会被感染。一旦某个节点被感染,那么它也会向其他节点传播消息,试图感染更多的节点。最终,每一个节点都会被感染,即消息被同步给了所有节点: infected 可扩展性 Gossip协议是可扩展的,因为它只需要O(logN) 个周期就能把消息传播给所有节点。某个节点在往固定数量节点传播消息过程中,并不需要等待确认 (ack) ,并且,即使某条消息传播过程中丢失,它也不需要做任何补偿措施。大哥比方,某个节点本来需要将消息传播给4个节点,但是由于网络或者其他原因,只有3个消息接收到消息,即使这样,这对最终所有节点接收到消息是没有任何影响的。 如下表格所示,假定fanout=4,那么在节点数分别是20、40、80、160时,消息传播到所有节点需要的循环次数对比,在节点成倍扩大的情况下,循环次数并没有增加很多。所以,Gossip协议具备可扩展性: 可扩展性 失败容错 Gossip也具备失败容错的能力,即使网络故障等一些问题,Gossip协议依然能很好的运行。因为一个节点会多次分享某个需要传播的信息,即使不能连通某个节点,其他被感染的节点也会尝试向这个节点传播信息。 健壮性 Gossip协议下,没有任何扮演特殊角色的节点 (比如leader等) 。任何一个节点无论什么时候下线或者加入,并不会破坏整个系统的服务质量。 然而,Gossip协议也有不完美的地方,例如,拜占庭问题 (Byzantine) 。即,如果有一个恶意传播消息的节点,Gossip协议的分布式系统就会出问题。 作者: 阿飞的博客 链接: https://www.jianshu.com/p/54eab117e6ae 来源: 简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 ...

2021-07-06 · 1 min · 75 words · -