博客主页

带你彻底理解Linux五种I/O模型

在编程中I/O是必不可少的操作。日常中,我们最常接触的就是Blocking I/O,也就是常说的阻塞I/O。相信你也听过同步非阻塞I/O(Non-Blocking I/O),异步I/O(Asynchronous I/O)。

要理解这些I/O模型并不是一件容易的事,相信你也在网上看到许多人尝试对这些概念解释,不过我认为目前并没有什么文章能对它们解释的比较清晰的文章。尤其是很多一知半解的人胡乱举例,更是加深理解难度。

知识准备

阅读本文之前,希望读者具备一下的知识,否则看了也是一脸懵。

  • 了解你所知语言中的基本I/O操作
  • User space & Kernel space 的概念
  • 理解File Descriptor。如果不懂,请移步理解linux中的file descriptor(文件描述符)。建议读者不管对file descriptor有没有了解,都去阅读这篇文章,对你理解I/O模型会有非常大的帮助。

看完了上面的内容,希望读者已经理解了下面内容

  1. 程序无法直接访问硬件资源,对磁盘(硬件)的读写需要发起system call,让kernel处理。
  2. 大部分和I/O有关的system call,都需要把fd(file descriptor)作为参数传递给kernel。

Read more

理解linux中的file descriptor(文件描述符)

file descriptor(以下简称fd)又叫文件描述符,他是一个抽象的指示符,用一个整数表示(非负整数)。它指向了由系统内核维护的一个file table中的某个条目(entry)。这个解释可能过于抽象,不过在正式详细介绍fd之前,有必要先了解用户程序和系统内核之间的工作过程。

注: 本文描述的所有场景仅限于类unix系统环境,在windows中这玩意叫file handle(臭名昭著的翻译: 句柄)。

User space & Kernel space

现代操作系统会把内存划分为2个区域,分别为Use space(用户空间) 和 Kernel space(内核空间)。用户的程序在User space执行,系统内核在Kernel space中执行。

用户的程序没有权限直接访问硬件资源,但系统内核可以。比如读写本地文件需要访问磁盘,创建socket需要网卡等。因此用户程序想要读写文件,必须要向内核发起读写请求,这个过程叫system call。

内核收到用户程序system call时,负责访问硬件,并把结果返回给程序。

FileInputStream fis = new FileInputStream("/tmp/test.txt");
byte[] buf = new byte[256];
fis.read(buf);

上面代码的流程如下图所示

/assets/images/fd/us_ks.png

Read more

深入浅出Redis Sentinel

Sentinel是Redis官方提供的高可用方案,传统的master slave(现在叫repliacation)模式中,当master故障时,需要手动修改配置文件指定新的master,Sentinel解决了这个问题,可以不需人工干预自动切换新的master。

sentinel节点是一个独立的进程,它不仅监测master节点,同时也会监测slave、sentinel节点的状态。

Sentinel介绍

架构

       +----+
       | M1 |
       | S1 |
       +----+
          |
+----+    |    +----+
| R2 |----+----| R3 |
| S2 |         | S3 |
+----+         +----+

Configuration: quorum = 2

Read more

深入理解Spring Security—框架设计

上个章节用一个Demo展示了Spring Security的基本配置。整体来说,Spring Security是一个配置简单,设计优雅,但不是很容易理解的框架。本文将叙述Spring Security的框架设计,带领大家更进一步理解Spring Security的设计细节。

注: 本文仅叙述Servlet部分的设计,不对WebFlux做任何补充,读者有兴趣请自己翻阅文档和源码。

知识准备

读者在阅读本文之前,最好具备下面的知识点,以便更容易理解文章内容

  • 了解Servlet Filter
  • 了解设计模式中的责任链模式
  • 最好是了解Spring Web Mvc的工作原理

Read more

深入理解Spring Security - HelloWorld

前言

之前公司一直使用Apache Shiro作为认证和授权的框架,前些天朋友叫我研究SSO时,发现在Spring的技术栈中,Spring Security是个更好的选择,于是花几天时间研究了一下Spring Security,打算把研究所得记录下来。

在我的理解中,Spring Security是一个配置简单,却不是很容易理解的框架。主要是它的内容所涵盖的领域很广,在代码层面,它构造Filter的流程可能也会有点难以理解。这个系列将带大家抽丝剥茧Spring Security的细节。

Read more

解决segmentfault等网站的登录复制限制

不知道从什么时候开始segmentfault也启用了需登录才能复制的限制,其实我很反感这种限制。尤其是作为一个技术社区,这样的限制又怎么能真的对技术人员有用?下面开始贴代码解决这烦人的限制。

对于这类禁止复制的,大多都是通过监听dom的copy事件实现的,segmentfault也一样。我们只需要把原本的eventlistener移除即可。

(function() {
  let arr = Array.from(document.querySelectorAll("article.article"));
  if (arr && arr.length <= 0) { return; } 
  let articleContent = arr[0];
  let eventHolder = getEventListeners(articleContent);
  if (!eventHolder || !eventHolder.copy) { return; }
  eventHolder.copy.forEach(e => {
    articleContent.removeEventListener('copy',e.listener)
  })
})();

当然还有个有点搞笑的办法,观察segmentfault的console输出,每次选中有一段log,点进去发现会查找一个SFUserId的dom节点获取用户ID,只需要几行代码就能解决了。

/assets/images/sf/sf_log_pos.png

/assets/images/sf/sf_login_func.png

(function () {
	const span = document.createElement("span");
  span.id = 'SFUserId';
  span.innerText = '123321'
  document.body.appendChild(span);
})();

希望决策者不要把程序员当傻子,稍微有点经验的程序员解决这种问题易如反掌,再不济在浏览器把你js禁用了你也无可奈何。还是把心思放在产品上吧,别想这种歪点子。

Read more

深入理解Spring事务: 物理事务和逻辑事务

Spring事务模块的文档中有描述了两个专业术语,分别是物理事务(physical transaciton)逻辑事务(logic transaction)。读者可能会一头雾水,因为Spring文档中并没有对这两个术语进行过多的介绍。

In Spring-managed transactions, be aware of the difference between physical and logical transactions, and how the propagation setting applies to this difference.

Ref: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#tx-propagation

Read more

深入理解Spring事务: Spring如何实现挂起事务

我们在看Spring的事务传播行为(Propagation)时会发现在某些条件下,线程会被挂起(suspend),接着去执行其他事务。比如Propagation.REQUIRES_NEW有一段这样的描述:

Create a new transaction, and suspend the current transaction if one exists.

这个挂起要怎么去理解呢?

事务和线程的关系

要理解事务挂起必须先了解事务和线程的关系。Oracle的文档中有个描述。

When a transaction is created, it is associated with the thread that created it. As long as the transaction is associated with the thread, no other transaction can be created for that thread.

Ref: https://docs.oracle.com/cd/E23095_01/Platform.93/ATGProgGuide/html/s1204transactionsuspension01.html

spring-tx的Propagation其实就是参考了EJB的Transaction设计。作为参考者,这方面和Oracle的设计是一致的。

当事务创建时,就会被绑定到一个线程上。该线程会伴随着事务整个生命周期,直到事务提交、回滚或挂起(临时解绑)。线程和事务的关系是1:1,当线程绑定了一个事务后,其他事务不可以再绑定该线程,反之亦然。

Read more