代码之旅

I love Coding !

获取Docker容器的内存使用情况

在之前介绍linux命令free时,有提到过docker中使用free命令获得的常常是宿主机的内存使用情况。那么怎么获取docker中内存的使用情况呢?

阅读全文 »

响应式宣言

版本 2.0,2014 年 9 月 16 日发布

在不同领域中深耕的组织都在不约而同地尝试发现相似的软件构建模式。 希望这些系统会更健壮、更具回弹性 、更灵活,也能更好地满足现代化的需求。

近年来,应用程序的需求已经发生了戏剧性的更改,模式变化也随之而来。仅在几年前, 一个大型应用程序通常拥有数十台服务器、 秒级的响应时间、 数小时的维护时间以及GB级的数据。 而今,应用程序被部署到了形态各异的载体上, 从移动设备到运行着数以千计的多核心处理器的云端集群。 用户期望着毫秒级的响应时间,以及服务100%正常运行(随时可用)。 而数据则以PB计量。 昨日的软件架构已经根本无法满足今天的需求。

我们相信大家需要一套贯通整个系统的架构设计方案, 而设计中必需要关注的各个角度也已被理清, 我们需要系统具备以下特质:即时响应性(Responsive)、回弹性(Resilient)、弹性(Elastic)以及消息驱动(Message Driven)。 我们称这样的系统为反应式系统(Reactive System)。

阅读全文 »

Socket IO 模型

在《UNIX网络编程》中介绍了5中I/O模型:阻塞I/O、非阻塞I/O、I/O复用、SIGIO 、异步I/O; Unix的I/O模型,一个输入操作通常包括两个不同的阶段:

  • 等待数据准备好;
  • 从内核向进程复制数据。

对于一个套接字的输入操作,第一步通常涉及等待数据从网络到达,当所等待分组到达时,被复制到内核的某个缓冲区;第二步把数据从内核缓冲区复制到应用进程缓冲区。

网络应用需要处理的无非就是两大类问题,网络IO,数据计算。相对于后者,网络IO的延迟,给应用带来的性能瓶颈大于后者。网络IO的模型大致有如下几种:

  • 阻塞IO(bloking IO)
  • 非阻塞IO(non-blocking IO)
  • 多路复用IO(multiplexing IO)
  • 信号驱动式IO(signal-driven IO)
  • 异步IO(asynchronous IO)
阅读全文 »

RAID技术

RAID ( Redundant Array of Independent Disks )即独立磁盘冗余阵列,通常简称为磁盘阵列。简单地说, RAID 是由多个独立的高性能磁盘驱动器组成的磁盘子系统,从而提供比单个磁盘更高的存储性能和数据冗余的技术。

阅读全文 »

操作系统概述

操作系统(Operating System,OS)是指控制和管理整个计算机系统的硬件和软件资源,并合理地组织调度计算机的工作和资源分配;以提供给用户和其他软件方便的接口和环境;它是计算机系统中最基本的系统软件。

  • 操作系统是系统资源的管理者
  • 向上层提供方便易用的服务
  • 是最接近硬件的一层软件
阅读全文 »

Ubuntu环境编译openjdk

  • ubuntu 环境: 20.04
  • jdk 版本: openjdk-8

源码下载

openjdk的源码可以从github中获取:

1
2
3
git clone https://github.com/openjdk/jdk.git
git checkout jdk8-b120
git checkout -b tag-jdk8-b120

国内码云上有同步的镜像仓库:

1
git clone git@gitee.com:mirrors/openjdk.git

源码编译

安装依赖

运行configure前先安装一些依赖:

1
sudo apt install gcc g++ gdb make build-essential cpio libasound2-dev libfreetype6-dev libcups2-dev libfontconfig1-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libffi-dev

configure

执行configure

1
bash configure

configure会检查项目依赖,如果有缺失的,按照提示安装即可。

Boot JDK

JDK的编译需要“版本-1”的JDK,例如在编译JDK8时,会提示:

1
configure: Could not find a valid Boot JDK. You might be able to fix this by running 'sudo apt-get install openjdk-7-jdk'.

由于当前源不包含openjdk7,直接使用jdk8进行编译

1
bash configure --with-boot-jdk=/home/victorchutian/.sdkman/candidates/java/8.0.282-open

freeType

参考stackoverflow增加编译参数:

1
2
3
4
bash configure \
--with-boot-jdk=/home/victorchutian/.sdkman/candidates/java/8.0.282-open \
--with-freetype-include=/usr/include/freetype2 \
--with-freetype-lib=/usr/lib/x86_64-linux-gnu \

最终参数

configure最终参数为:

1
2
3
4
5
6
7
8
bash configure \
--with-boot-jdk=/home/victorchutian/.sdkman/candidates/java/8.0.282-open \
--with-freetype-include=/usr/include/freetype2 \
--with-freetype-lib=/usr/lib/x86_64-linux-gnu \
--with-target-bits=64 \
--with-debug-level=slowdebug \
--with-jvm-variants=server \
--enable-debug-symbols

make

接下来就是编译:

1
make all

OS is not supported

编译报错:

1
*** This OS is not supported: Linux 9c888f853395 5.19.0-43-generic #44~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon May 22 13:39:36 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

修改Makefile

1
2
# hotspot/make/linux/Makefile
SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% 4% 5%

/usr/bin/make: invalid option -- '/'

修改hotspot/make/linux/makefiles/adjust-mflags.sh文件

1
2
3
4
5
6
7
8
9
@@ -64,7 +64,7 @@
echo "$MFLAGS" \
| sed '
s/^-/ -/
- s/ -\([^ ][^ ]*\)j/ -\1 -j/
+ s/ -\([^ I][^ I]*\)j/ -\1 -j/
s/ -j[0-9][0-9]*/ -j/
s/ -j\([^ ]\)/ -j -\1/
s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/

all warnings being treated as errors

hotspot/make/linux/makefiles/gcc.make,200行左右:

1
2
3
WARNINGS_ARE_ERRORS=-Werror
改为
WARNINGS_ARE_ERRORS=-Wno-error

语法错误

重新编译后还是有大量语法错误。将gcc版本控制在5.0以下,见jdk8最小构建环境

1
sudo apt install gcc-4.8 g++-4.8

如果出现Package ‘gcc-4.8’ has no installation candidate

1
2
3
4
# vim /etc/apt/sources.list
deb http://dk.archive.ubuntu.com/ubuntu xenial main
deb http://dk.archive.ubuntu.com/ubuntu xenial universe
apt update

设置gcc为4.8版本的gcc

1
2
3
4
# 配置新安装的gcc 4.8的启动优先级为100
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
# 配置新安装的g++ 4.8的启动优先级为100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100

然后重新运行configure,继续编译。

class jdk.nashorn.internal.objects.ScriptFunctionImpl overrides final method setPrototype

修改nashorn/make/BuildNashorn.gmk文件,修改前:

1
2
3
4
5
6
7
8
9
10
11
73 # Copy classes to final classes dir and run nasgen to modify classes in jdk.nashorn.internal.objects package
74 $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN)
75 $(ECHO) Running nasgen
76 $(MKDIR) -p $(@D)
77 $(RM) -rf $(@D)/jdk $(@D)/netscape
78 $(CP) -R -p $(NASHORN_OUTPUTDIR)/nashorn_classes/* $(@D)/
79 $(FIXPATH) $(JAVA) \
80 -cp "$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
81 jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
82 $(TOUCH) $@
83

修改第80行,修改后:

1
2
3
4
5
6
7
8
9
10
11
73 # Copy classes to final classes dir and run nasgen to modify classes in jdk.nashorn.internal.objects package
74 $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN)
75 $(ECHO) Running nasgen
76 $(MKDIR) -p $(@D)
77 $(RM) -rf $(@D)/jdk $(@D)/netscape
78 $(CP) -R -p $(NASHORN_OUTPUTDIR)/nashorn_classes/* $(@D)/
79 $(FIXPATH) $(JAVA) \
80 -Xbootclasspath/p:"$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
81 jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
82 $(TOUCH) $@
83

编译完成

最后可以看到编译完成的日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## Finished docs (build time 00:00:43)

----- Build times -------
Start 2020-07-03 01:06:25
End 2020-07-03 01:09:40
00:00:09 corba
00:00:05 demos
00:00:43 docs
00:00:48 hotspot
00:00:07 images
00:00:06 jaxp
00:00:08 jaxws
00:00:53 jdk
00:00:12 langtools
00:00:04 nashorn
00:03:15 TOTAL

执行java命令:

1
2
3
4
5
$ ./build/linux-x86_64-normal-server-slowdebug/jdk/bin/java -version
openjdk version "1.8.0-internal-debug"
OpenJDK Runtime Environment (build 1.8.0-internal-debug-victorchutian_2020_07_03_18_32-b00)
OpenJDK 64-Bit Server VM (build 25.0-b62-debug, mixed mode)
victorchutian@9c888f853395:~/projects/openjdk$

vscode

launch.json

launch.json配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java",
"args": ["-version"],
"stopAtEntry": true, //设置debug停住
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath":"/usr/bin/gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

c_cpp_properties.json

vscode cpp插件需要c_cpp_properties.json.

首先安装compiledb。然后使用compiledb make all编译。然后会在项目根目录下生成文件compile_commands.json。将其中的 -D 后的所有参数收集起来,然后将收集起来的参数添加到 c_cpp_properties.json 中的 define 配置中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"LINUX",
"_GNU_SOURCE",
"AMD64",
"ASSERT",
"TARGET_OS_FAMILY_linux",
"TARGET_ARCH_x86",
"TARGET_ARCH_MODEL_x86_64",
"TARGET_OS_ARCH_linux_x86",
"TARGET_OS_ARCH_MODEL_linux_x86_64",
"TARGET_COMPILER_gcc",
"COMPILER2",
"COMPILER1",
"_REENTRANT"
],
"compilerPath": "/usr/bin/g++",
"cStandard": "c11",
"cppStandard": "c++14",
"intelliSenseMode": "linux-gcc-x64",
"compileCommands": "${workspaceFolder}/compile_commands.json"
}
],
"version": 4
}

参考资料

使用update-alternatives切换GCC版本

首先在ubuntu上安装多版本的GCC:

1
2
$ sudo apt install build-essential
$ sudo apt -y install gcc-7 g++-7 gcc-8 g++-8 gcc-9 g++-9

然后使用update-alternatives注册不同版本的GCC:

1
2
3
4
5
6
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 7
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 7
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 8
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 8
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 9
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 9

选择想使用的GCC:

1
2
3
4
5
6
7
8
9
10
$ sudo update-alternatives --config gcc
There are 3 choices for the alternative gcc (providing /usr/bin/gcc).

Selection Path Priority Status
------------------------------------------------------------
0 /usr/bin/gcc-9 9 auto mode
1 /usr/bin/gcc-7 7 manual mode
* 2 /usr/bin/gcc-8 8 manual mode
3 /usr/bin/gcc-9 9 manual mode
Press to keep the current choice[*], or type selection number:
阅读全文 »

Apache Flink™: Stream and Batch Processing in a Single Engine

本篇是论文的中文简单翻译

Apache Flink 是一个开放源代码系统,用于处理流数据和批处理数据。Flink的哲学是,许多类别的数据处理应用程序(包括实时分析,数据管道,历史数据处理(批处理)和迭代算法(机器学习,图形分析)都可以表示为容错的流水线数据流并执行。在本文中,我们提出Flink的体系结构,并就如何在单一执行模型下执行一组多样性用例进行扩展分析。

阅读全文 »

分布式锁简介

在分布式场景中分布式锁是一种很常见的需求。实现一个分布式锁要注意以下几点:

  • 安全: 独享(相互排斥)。在任意一个时刻,只有一个客户端持有锁。
  • 锁失效保护: 无死锁。即便持有锁的客户端崩溃(crashed)或者网络被分裂(gets partitioned),锁仍然可以被获取。
  • 集群容错。 只要大部分节点都活着,客户端就可以获取和释放锁。
  • 原子性:获取释放锁最好是原子操作,获取释放锁的性能要好。
  • 可重入(optional): 同一个线程在没有释放锁之前,如果想再次操作,可以直接获得锁。
  • 阻塞/非阻塞(optional):若没有获取到锁,返回获取失败。
阅读全文 »

Dataflow 模型:一种能平衡准确性、延迟、成本的大规模、无限、乱序的数据处理的实践方法

本篇是论文的中文简单翻译

概述

在日常商业运营中,无边界、乱序、大规模数据集越来越普遍了。(例如,网站日志,手机应用统计,传感器网络)。同时,对这些数据的消费需求也越来越复杂。比如说按事件发生时间序列处理数据,按数据本身的特征进行窗口计算等等。同时人们也越来越苛求立刻得到数据分析结果。然而,实践表明,我们永远无法同时优化数据处理的准确性、延迟程度和处理成本等各个维度。因此,数据工作者面临如何协调这些几乎相互冲突的数据处理技术指标的窘境,设计出来各种纷繁的数据处理系统和实践方法。

我们建议数据处理的方法必须进行根本性的改进。作为数据工作者,我们不能把无边界数据集(数据流)切分成有边界的数据,等待一个批次完整后处理。相反地,我们应该假设我们永远无法知道数据流是否终结,何时数据会变完整。唯一应该确信的是,新的数据会源源不断而来,老的数据可能会被撤销或更新。而能够让数据工作者应对这个挑战的唯一可行的方法是通过一个遵守原则的抽象来平衡折衷取舍数据处理的准确性、延迟程度和处理成本。

在这篇论文中,我们提出了Dataflow模型,并详细地阐述了它的语义,设计的核心原则,以及在实践开发过程中对模型的检验。

阅读全文 »