gojavaqps的简单介绍

博主:adminadmin 2022-11-28 16:08:06 47

今天给各位分享gojavaqps的知识,其中也会对进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

java多线程详细理解?

多线程:指的是这个程序(一个进程)运行时产生了不止一个线程

并行与并发:

并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:

请点击输入图片描述

同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。

PHP的未来在哪?

php整个从业者的平均技术素养基本决定了这门技术以及其构建的生态走不远了。即使有几个大牛,比如鸟哥啊,韩天峰啊,还有laravel整个社区啊,不可否认这些都极其优秀的技术工作者以及牛逼作品,但是个别英雄扭转不了滚滚的历史车轮。原因如下:已经2017年了,php80%应用领域仍然集中在搞网页这个层面。已经2017年了,众多phper仍然推崇粗狂式编写代码。总结:整个从业者平均水平和其主要应用领域把php的上限牢牢锁死了,未来php的主要应用地方,可以预见的应用场景是:一些建站公司,拿模板给甲方套一个又一个的网站。

序列化的原理

XML 序列化的好处在于可读性好,方便阅读和调试。但是序列化以后的字节码文件比较大,而且效率不高,适用于对性能不高,而且 QPS 较低的企业级内部系统之间的数据交换的场景,同时 XML 又具有语言无关性,所以还可以用于异构系统之间的数据交换和协议。比如我们熟知的 webservice,就是采用 XML 格式对数据进行序列化的。XML 序列化/反序列化的实现方式有很多,熟知的方式有 XStream 和 Java 自带的 XML 序列化和反序列化两种

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相对于 XML 来说,JSON的字节流更小,而且可读性也非常好。现在 JSON 数据格式在企业运用是最普遍的JSON 序列化常用的开源工具有很多

这几种 json 序列化工具中,Jackson 与 fastjson 要比 GSON 的性能要好,但是 Jackson、GSON 的稳定性要比 Fastjson 好。而 fastjson 的优势在于提供的 api 非常容易使用

Hessian 是一个支持跨语言传输的二进制序列化协议,相对于 Java 默认的序列化机制来说,Hessian 具有更好的性能和易用性,而且支持多种不同的语言

实际上 Dubbo 采用的就是 Hessian 序列化来实现,只不过 Dubbo 对 Hessian 进行了重构,性能更高

Avro 是一个数据序列化系统,设计用于支持大批量数据交换的应用。它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据;动态语言友好,Avro 提供的机制使动态语言可以方便地处理 Avro 数据

Kryo 是一种非常成熟的序列化实现,已经在 Hive、Storm)中使用得比较广泛,不过它不能跨语言. 目前 dubbo 已经在 2.6 版本支持 kyro 的序列化机制。它的性能要优于之前的hessian2

Protobuf 是 Google 的一种数据交换格式,它独立于语言、独立于平台。Google 提供了多种语言来实现,比如 Java、C、Go、Python,每一种实现都包含了相应语言的编译器和库文件,Protobuf 是一个纯粹的表示层协议,可以和各种传输层协议一起使用。

Protobuf 使用比较广泛,主要是空间开销小和性能比较好,非常适合用于公司内部对性能要求高的 RPC 调用。 另外由于解析性能比较高,序列化以后数据量相对较少,所以也可以应用在对象的持久化场景中但是要使用 Protobuf 会相对来说麻烦些,因为他有自己的语法,有自己的编译器,如果需要用到的话必须要去投入成本在这个技术的学习中

protobuf 有个缺点就是要传输的每一个类的结构都要生成对应的 proto 文件,如果某个类发生修改,还得重新生成该类对应的 proto 文件

各个序列化技术的性能比较

这个地址有针对不同序列化技术进行性能比较:

使用 protobuf 开发的一般步骤是

编写 proto 文件

数据类型

string / bytes / bool / int32(4 个字节)

/int64/float/double

enum 枚举类

message 自定义类

修饰符

required 表示必填字段

optional 表示可选字段

repeated 可重复,表示集合

1,2,3,4 需要在当前范围内是唯一的,表示顺序

生成实体类

实现序列化

输出结果:10 3 77 105 99 16 -84 2

可以看到,序列化出来的数字基本看不懂,但是序列化以后的数据确实很小,那我们来了解一下底层的原理

正常来说,要达到最小的序列化结果,一定会用到压缩的技术,而 protobuf 里面用到了两种

压缩算法,一种是 varint,另一种是 zigzag

-varint

先来看 age=300 这个数字是如何被压缩的

这两个字节字节分别的结果是:-84 、2

-84 怎么计算来的呢? 我们知道在二进制中表示负数的方法,高位设置为 1, 并且是对应数字的二进制取反以后再计算补码表示(补码是反码+1)

所以如果要反过来计算

字符如何转化为编码

“Mic”这个字符,需要根据 ASCII 对照表转化为数字。

M =77、i=105、c=99

所以结果为 77 105 99

这里的结果为什么直接就是 ASCII 编码的值呢?怎么没有做压缩呢?

原因是,varint 是对字节码做压缩,但是如果这个数字的二进制只需要一个字节表示的时候,其实最终编码出来的结果是不会变化的

还有两个数字,3 和 16 代表什么呢?那就要了解 protobuf 的存储格式了

存储格式

protobuf 采用 T-L-V 作为存储方式

tag 的计算方式是 field_number(当前字段的编号) 3 | wire_type

比如 Mic 的字段编号是 1 ,类型 wire_type 的值为 2 所以 : 1 3 | 2 =10

age=300 的字段编号是 2,类型 wire_type 的值是 0, 所以 : 23|0 =16

第一个数字 10,代表的是 key,剩下的都是 value

负数的存储

在计算机中,负数会被表示为很大的整数,因为计算机定义负数符号位为数字的最高位,所以如果采用 varint 编码表示一个负数,那么一定需要 5 个比特位。所以在 protobuf 中通过sint32/sint64 类型来表示负数,负数的处理形式是先采用 zigzag 编码(把符号数转化为无符号数),再采用 varint 编码。

sint32:(n 1) ^ (n 31)

sint64:(n 1) ^ (n 63)

比如存储一个(-300)的值

-300

原码:0001 0010 1100

取反:1110 1101 0011

加 1 :1110 1101 0100

n1: 整体左移一位,右边补 0 - 1101 1010 1000

n31: 整体右移 31 位,左边补 1 - 1111 1111 1111

n1 ^ n 31

1101 1010 1000 ^ 1111 1111 1111 = 0010 0101 0111

十进制: 0010 0101 0111 = 599

varint 算法: 从右往做,选取 7 位,高位补 1/0(取决于字节数)

得到两个字节

1101 0111 和 0000 0100

-41 和 4

Protocol Buffer 的性能好,主要体现在 序列化后的数据体积小 序列化速度快,最终使得传输效率高,其原因如下:

系统压测时CPU达到100%但是QPS却很低

线上系统,正在做压力测试,刚开始10并发进行压测,cpu压到了100%但是系统最大qps才200多。通过JVM监控查看JVM younggc很频繁,fullGC数量为零。

cpu 达到100% 则先看cpu使用率最高是哪个进程,可以直接通过linux命令 top查看,找到对应的进程ID,发现正是压测的java系统进程ID,找到进程ID后,然后在查找该进程下CPU使用率最高是哪个线程,可以通过top -p 进程ID -H 命令显示线程使用cpu信息,效果如下:

图片中PID列则为十进制显示的线程ID,然后转换为16进制通过jstack 系统进程ID | grep 16进制线程ID 可以找到对应的线程信息如下,也就是该线程占用了一半左右的cpu

Finalizer线程是个单一职责的线程。这个线程会不停的循环等待java.lang.ref.Finalizer.ReferenceQueue中的新增对象。一旦Finalizer线程发现队列中出现了新的对象,它会弹出该对象,调用它的finalize()方法,将该引用从Finalizer类中移除,因此下次GC再执行的时候,这个Finalizer实例以及它引用的那个对象就可以回垃圾回收掉了。

说明Finalizer的队列中有许多的等待回收的垃圾对象,可以通过命令查看等待回收的对象都有哪些;

jmap -finalizerinfo 进程ID

执行命令后显示结果如下

发现有好多的自定义对象,通过类名可以看到这些对象都是通过CGLIB动态代理创建的,而这些动态代理类都默认实现了finalize方法,导致这些对象在进行垃圾回收时必须先要执行finalize方法,所以都积压到了finalizer的队列中。

1.不要使用cglib来给那些需要频繁进行垃圾回收的对象创建动态代理,这些对象大量创建的同时,也会创建相等数量的动态代理对象,使得内存占用迅速增长,并且不断进行垃圾回收,由于代理类重写了finalize方法,给垃圾回收带来了额外的压力。

2.尽量能够复用对象,不要每次都new一个对象

java如何计算redis的QPS?

qps表示每秒查询率,是一台服务器每秒能够响应的查询次数。

只要知道服务器台数和指定时间内的查询次数,就可以计算了。

【知识总结】6.服务注册发现框架比较(Consul/Zookeeper/etcd/Eureka)

服务发现就是服务提供者将自己提供的地址post或者update到服务中介,服务消费者从服务中介那里get自己想要的服务的地址。

但是有两个问题:

第一个问题:如果有一个服务提供者宕机,那么中介的key/value中会有一个不能访问的地址,该怎么办?

心跳机制: 服务提供者需要每隔5秒左右向服务中介汇报存活,服务中介将服务地址和汇报时间记录在zset数据结构的value和score中。服务中介需要每隔10秒左右检查zset数据结构,踢掉汇报时间严重落后的地址。这样就可以保证服务列表中地址的有效性。

第二个问题是服务地址变动时如何通知消费者。有两种解决方案。

第一种是轮询,消费者每隔几秒查询服务列表是否有改变。如果服务地址很多,查询会很慢。这时候可以引入服务版本号机制,给每个服务提供一个版本号,在服务变动时,递增这个版本号。消费者只需要轮询这个版本号的变动即可知道服务列表是否发生了变化。

第二种是采用pubsub。这种方式及时性要明显好于轮询。缺点是每个pubsub都会占用消费者一个线程和一个额外的连接。为了减少对线程和连接的浪费,我们使用单个pubsub广播全局版本号的变动。所谓全局版本号就是任意服务列表发生了变动,这个版本号都会递增。接收到版本变动的消费者再去检查各自的依赖服务列表的版本号是否发生了变动。这种全局版本号也可以用于第一种轮询方案。

CAP理论

CAP理论是分布式架构中重要理论

关于P的理解,我觉得是在整个系统中某个部分,挂掉了,或者宕机了,并不影响整个系统的运作或者说使用,而可用性是,某个系统的某个节点挂了,但是并不影响系统的接受或者发出请求,CAP 不可能都取,只能取其中2个。原因是

(1)如果C是第一需求的话,那么会影响A的性能,因为要数据同步,不然请求结果会有差异,但是数据同步会消耗时间,期间可用性就会降低。

(2)如果A是第一需求,那么只要有一个服务在,就能正常接受请求,但是对与返回结果变不能保证,原因是,在分布式部署的时候,数据一致的过程不可能想切线路那么快。

(3)再如果,同事满足一致性和可用性,那么分区容错就很难保证了,也就是单点,也是分布式的基本核心,好了,明白这些理论,就可以在相应的场景选取服务注册与发现了。

平时经常用到的服务发现的产品进行下特性的对比,首先看下结论:

补充:

(1)运维和开发如果是 Java 更熟,也更多 Java 的应用,那毫无疑问应该用 ZK;如果是搞 Go 的,那么还是 etcd 吧,毕竟有时候遇到问题还是要看源码的。

(2)在创建一百万个或更多键时,etcd可以比Zookeeper或Consul稳定地提供更好的吞吐量和延迟。此外,它实现了这一目标,只有一半的内存,显示出更高的效率。但是,还有一些改进的余地,Zookeeper设法通过etcd提供更好的最小延迟,代价是不可预测的平均延迟。

(3)

一致性协议: etcd 使用 Raft 协议,Zookeeper 使用 ZAB(类PAXOS协议),前者容易理解,方便工程实现;

运维方面:etcd 方便运维,Zookeeper 难以运维;

数据存储:etcd 多版本并发控制(MVCC)数据模型 , 支持查询先前版本的键值对

项目活跃度:etcd 社区与开发活跃,Zookeeper 感觉已经快死了;

API:etcd 提供 HTTP+JSON, gRPC 接口,跨平台跨语言,Zookeeper 需要使用其客户端;

访问安全方面:etcd 支持 HTTPS 访问,Zookeeper 在这方面缺失;

与 Eureka 有所不同,Apache Zookeeper 在设计时就紧遵CP原则,即任何时候对 Zookeeper 的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性,但是 Zookeeper 不能保证每次服务请求都是可达的。

从 Zookeeper 的实际应用情况来看,在使用 Zookeeper 获取服务列表时,如果此时的 Zookeeper 集群中的 Leader 宕机了,该集群就要进行 Leader 的选举,又或者 Zookeeper 集群中半数以上服务器节点不可用(例如有三个节点,如果节点一检测到节点三挂了 ,节点二也检测到节点三挂了,那这个节点才算是真的挂了),那么将无法处理该请求。所以说,Zookeeper 不能保证服务可用性。

当然,在大多数分布式环境中,尤其是涉及到数据存储的场景,数据一致性应该是首先被保证的,这也是 Zookeeper 设计紧遵CP原则的另一个原因。

但是对于服务发现来说,情况就不太一样了,针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不尽相同,也并不会造成灾难性的后果。

因为对于服务消费者来说,能消费才是最重要的,消费者虽然拿到可能不正确的服务实例信息后尝试消费一下,也要胜过因为无法获取实例信息而不去消费,导致系统异常要好(淘宝的双十一,京东的618就是紧遵AP的最好参照)。

当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,而且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。

在云部署环境下, 因为网络问题使得zk集群失去master节点是大概率事件,虽然服务能最终恢复,但是漫长的选举事件导致注册长期不可用是不能容忍的。

Spring Cloud Netflix 在设计 Eureka 时就紧遵AP原则。Eureka是在Java语言上,基于Restful Api开发的服务注册与发现组件,由Netflix开源。遗憾的是,目前Eureka仅开源到1.X版本,2.X版本已经宣布闭源。

Eureka Server 也可以运行多个实例来构建集群,解决单点问题,但不同于 ZooKeeper 的选举 leader 的过程,Eureka Server 采用的是Peer to Peer 对等通信。这是一种去中心化的架构,无 master/slave 之分,每一个 Peer 都是对等的。在这种架构风格中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。每个节点都可被视为其他节点的副本。

在集群环境中如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点上,当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会在节点间进行复制(replicate To Peer)操作,将请求复制到该 Eureka Server 当前所知的其它所有节点中。

当一个新的 Eureka Server 节点启动后,会首先尝试从邻近节点获取所有注册列表信息,并完成初始化。Eureka Server 通过 getEurekaServiceUrls() 方法获取所有的节点,并且会通过心跳契约的方式定期更新。

默认情况下,如果 Eureka Server 在一定时间内没有接收到某个服务实例的心跳(默认周期为30秒),Eureka Server 将会注销该实例(默认为90秒, eureka.instance.lease-expiration-duration-in-seconds 进行自定义配置)。

当 Eureka Server 节点在短时间内丢失过多的心跳时,那么这个节点就会进入自我保护模式。

Eureka的集群中,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

Eureka不再从注册表中移除因为长时间没有收到心跳而过期的服务;

Eureka仍然能够接受新服务注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用);

当网络稳定时,当前实例新注册的信息会被同步到其它节点中;

因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使得整个注册服务瘫痪。

Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。Consul 使用 Go 语言编写,因此具有天然可移植性(支持Linux、windows和Mac OS X)。

Consul采用主从模式的设计,使得集群的数量可以大规模扩展,集群间通过RPC的方式调用(HTTP和DNS)。

Consul 内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其他工具(比如 ZooKeeper 等),使用起来也较为简单。

Consul 遵循CAP原理中的CP原则,保证了强一致性和分区容错性,且使用的是Raft算法,比zookeeper使用的Paxos算法更加简单。虽然保证了强一致性,但是可用性就相应下降了,例如服务注册的时间会稍长一些,因为 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功 ;在leader挂掉了之后,重新选举出leader之前会导致Consul 服务不可用。

默认依赖于SDK

Consul本质上属于应用外的注册方式,但可以通过SDK简化注册流程。而服务发现恰好相反,默认依赖于SDK,但可以通过Consul Template(下文会提到)去除SDK依赖。

Consul Template

Consul,默认服务调用者需要依赖Consul SDK来发现服务,这就无法保证对应用的零侵入性。

所幸通过 Consul Template ,可以定时从Consul集群获取最新的服务提供者列表并刷新LB配置(比如nginx的upstream),这样对于服务调用者而言,只需要配置一个统一的服务调用地址即可。

Consul强一致性(C)带来的是:

Eureka保证高可用(A)和最终一致性:

其他方面,eureka就是个servlet程序,跑在servlet容器中; Consul则是go编写而成。

etcd是一个采用http协议的分布式键值对存储系统,因其易用,简单。很多系统都采用或支持etcd作为服务发现的一部分,比如kubernetes。但正事因为其只是一个存储系统,如果想要提供完整的服务发现功能,必须搭配一些第三方的工具。

比如配合etcd、Registrator、confd组合,就能搭建一个非常简单而强大的服务发现框架。但这种搭建操作就稍微麻烦了点,尤其是相对consul来说。所以etcd大部分场景都是被用来做kv存储,比如kubernetes。

etcd 比较多的应用场景是用于服务发现,服务发现 (Service Discovery) 要解决的是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务如何才能找到对方并建立连接。和 Zookeeper 类似,etcd 有很多使用场景,包括:

配置管理

服务注册发现

选主

应用调度

分布式队列

分布式锁

按照官网给出的数据, 在 2CPU,1.8G 内存,SSD 磁盘这样的配置下,单节点的写性能可以达到 16K QPS, 而先写后读也能达到12K QPS。这个性能还是相当可观。

etcd 提供了 etcdctl 命令行工具 和 HTTP API 两种交互方法。etcdctl命令行工具用 go 语言编写,也是对 HTTP API 的封装,日常使用起来也更容易。所以这里我们主要使用 etcdctl 命令行工具演示。

(1)注册中心ZooKeeper、Eureka、Consul 、Nacos对比

(2)常用的服务发现对比(Consul、zookeeper、etcd、eureka)

gojavaqps的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、gojavaqps的信息别忘了在本站进行查找喔。

The End

发布于:2022-11-28,除非注明,否则均为首码项目网原创文章,转载请注明出处。