0%

双十一全链路压测过程中,收到应用的FGC的耗时告警,提示产生了一次耗时7秒的Full GC。

应用使用CMS GC,相关的JVM参数为:-server -Xms10g -Xmx10g -Xmn5g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:MaxDirectMemorySize=1g -XX:SurvivorRatio=10 -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=5000 -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly

登陆机器,查看gc.log,发现是发生了promotion failed错误:

阅读全文 »

假设有一个社交属性的业务,总用户量在百万级别,并且平均每个用户有30个好友,现在需要查询某个用户的N度人脉,那么你会怎么存储这些数据?

一些典型的多级分销业务也与此类似,需要统计某个人的N级邀请关系;也还有更为复杂的电商类业务,例如查询购买了商品A的用户还购买了哪些其他商品。

用数据库?假设用User表存储用户属性,用Friend表存储用户之间的好友关系,然后进行N次查询?如果时间允许的话可以,因为到3度好友关系时,最坏情况下,一个人会有$30^3=27000$个好友了,到4度就$30^4=810000$了。

随着社交,金融等行业的快速发展,他们产生了很多关系数据,而传统的数据存储引擎大多采用列存储,文档存储,Key-Value存储等,数据和数据之间,在存储层面是没有什么关联的(外键引用等也不太算是数据本身关系层面的关联),很难去处理这一类数据,因此以数据之间的关联关系运算为主的图数据库应运而生。

阅读全文 »

5月15日,Spring Boot 2.3.0正式发布,其提供了原生的优雅关机(Graceful shutdown)的功能,摆脱了第三方优雅关机库的依赖,我们来简单看看其使用姿势以及原理。

用法

pom文件中指定2.3.0版本的依赖:

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/>
</parent>

在.yml配置文件中,开启优雅关机:

1
2
3
server:
port: 12345
shutdown: # 默认为IMMEDIATE,表示立即关机;GRACEFUL表示优雅关机
阅读全文 »

最近看到一篇文章,其中提到:“负向查询不能命中索引,会导致全表扫描”,这个与我之前对索引的理解产生了冲突。

某个SQL语句需要走索引进行查询,至少需要满足以下两个条件:

  • 有与SQL关联的索引,比如查询id=5,那么id列上必须要有索引;

  • MySQL查询优化器按照成本选择“最优执行计划”,例如如果走索引并没有比全表扫描性能好,否则会放弃索引,采用全表扫描。

    参考MySQL - 索引简介中的范围查询不一定会使用索引例子。

那么对于负向查询,则不能绝对的说不能命中索引,而是要根据情况来看。

阅读全文 »

代理模式,是设计模式中经常用到的模式之一,它给某个对象提供一个代理对象,由这个代理对象去控制原有对象的使用。

我们可以将代理模式分为静态代理和动态代理,静态代理也就是我们常用的方式,通过编写源代码去实现代理的逻辑;而动态代理则是在运行时利用Java的反射等技术来实现的。

静态代理

我们先来看个简单的静态代理的例子:

阅读全文 »

前一文中,我们讲了HashMap的一些知识点,文末提到HashMap不是线程安全的,在并发的场景下,建议使用ConcurrentHashMap,它是java.util.concurrent并发包下面的一款线程安全的HashMap容器,本文就ConcurrentHashMap在JDK7和JDK8中的实现进行分析。

与HashMap想通的一些知识,本文就不再赘述了,可以看HashMap的文章。

JDK7

JDK7的ConcurrentHashMap中,加入了分段锁的逻辑,在分段锁的设计中,数据会被按照一定的规则分段(一般是对数据的hashcode,进行二次哈希计算),每个段使用一个锁,这样如果访问的数据不在一个分段中,则不会产生锁冲突,从而提高并发性能。

阅读全文 »

在使用TCP协议进行数据传输的时候,我们考虑一下如下情况:

  • A通过TCP协议向B发送数据,但是B对数据的处理性能比较慢,导致B的TCP接收缓冲区被填满了,无法再对数据进行ACK应答,此时A则认为之后的数据都发送失败,反而继续发送无法ACK应答的数据,形成一个恶性循环;
  • A通过TCP协议向B发送数据,数据会途径网络设备C,假设网络设备C的数据转发性能已经达到了极限,那么数据会在网络设备C上堆积,导致网络拥堵。

第一个问题暴露了发送端和接收端自身的数据收发能力;第二个问题暴露了TCP协议对整个网络的影响,并且第一个问题会加剧第二个问题的产生。

TCP是网络中的基础传输协议,如果协议本身没能很好的控制上面的两个问题,则反而会给整个网络带来灾难,因此TCP协议中,需要定义相关的策略,来防止数据传输导致的网络拥塞。

阅读全文 »

TCP基础 - 连接与状态一文中,我们提到TCP会利用Sequence Number与Acknowledgment Number,对发出的数据进行标记,并且对接收到的数据进行应答,从而确定数据从发送端成功的送达到了接收端。

现在假设有这么一种场景,发送端一共发送了1,2,3,4,5一共五个数据包,并且陆续接收到了1,2,4,5这四个数据包的ACK,但是迟迟没有收到数据3的ACK。由于TCP是可靠传输协议,必须要确保所有的数据包都能成功送达到对端,这种情况下,发送端没法确认接收端到底有没有收到数据包3(有可能在发送过程中失败了;有可能收到了,但是ACK传输失败了),为了保证数据传输的可靠性,就必须对数据包3进行重传。

上述过程中涉及到两个关键的知识点:

  • 多长时间内没有收到ACK才会触发重传;
  • 触发重传之后,重传哪些数据包。
阅读全文 »

TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议),是现代互联网的基础通信架构,是由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇,只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。

建立/断开连接

在互联网的传输中,本身是没有“连接”的概念的,数据通过网络从A传输到B之后,这一次网络通信就完成了。

所谓的TCP连接,其实是双方按照约定的协议,通过几次网络数据的传输,沟通好双方的状态,以便后续的数据通信。本质上是双方各自维护了一个连接状态,来模拟的“连接”,比如“我明确知道你的存在了,并且你也明确知道我的存在”。

所以创建/断开连接,其实是双方进行数据沟通,更新彼此连接状态的一个过程。

阅读全文 »

最近有个个人需求,需要在网页上频繁下单,期间还要有一些网页操作行为,于是想把操作自动化。一个简单的方式是启动一个自定义的浏览器,通过hook一些网页响应,来实现自动化。

于是,把N多年没碰的Qt又捡了起来,Qt是一个跨平台的C++图形用户界面应用程序框架,它提供给开发者建立图形用户界面所需的功能,广泛用于开发GUI程序。在最新的Qt5中,有一个QWebEngineView类,基于Chromium的引擎,可以利用这个来实现自己的浏览器。

而PyQt是一个创建GUI应用程序的工具包。它是Python编程语言和Qt库的成功融合,鉴于已经好几年没碰C++了,加上工程量也不大,于是PyQt就是首选了。

本文不是PyQt的基础教程,本文只会将QWebEngineView中一些常用的技术点罗列出来。基础教程可以看这里

阅读全文 »