从零开始搭建 NAS: 硬件篇

自从年初注册了 PT 站 就发现原来的 QNAP TS453bmini 的硬盘就不堪重负,所以想要把下载和真正想要管理的数据安全的从硬件上隔离开,所以才有了这篇文章。

研究阶段

自行组装 NAS 相较于买成品 NAS 中间可能遇上许许多多坑,不过填坑的过程就是学习的过程,能学到很多硬件知识,并且通过对自己需求的合理规划能够组一台最合理的符合自己需求的机器。

下面就记录一下研究过程中遇到的一些新名词。

ITX

在看主板的时候不可避免的会看到这个 ITX,实际上 ITX 就是主板的一个大小,ITX 或者又称为 Mini-ITX 是一块 17*17cm 的主板,这种格式的主板是 2001 年时由 VIA Technologies 公司开发。ITX 主板通常被用在小型电脑中,比如一些嵌入式,无风扇,低功耗的机器中,比如家庭媒体中心,或者家用服务器中,在很多人推荐的低功耗华擎 J3455 主板中,就有一款 J3455-itx 的主板。

市面上除了 ITX,还有如下几个常见的主板尺寸:

  • ITX(Mini-ATX,尺寸 17cm*17cm)
  • M-ATX(Micro-ATX,尺寸 24.4cm*24.4cm)
  • ATX(尺寸:30.5cm*24.4cm)

PCIe

PCIe,又叫做 PCI Express 全称是,Peripheral Component Interconnect Express,PCIe 是一个高速串行计算机扩展总线标准,设计的目标是为了替换老的 PCI, PCI-X 和 AGP 总线标准。它是个人计算机主板的显卡,硬盘,SSD,Wi-Fi,网卡的连接接口。有了这个接口就多了一个扩展接口,比如通过 PCIe 接口转 SATA 接口可以扩容,可以通过 PCIe 接口来接外置显卡扩展显示能力,或者扩展以太网卡等等。

通常还会看到 PCIe x1, PCIe x4, PCIe x16 几个,要了解这些就需要知道 lane 的概念,lane 由两个不同的信号对组成,一个用来接收数据,一个用来发送数据。PCIe 的连线由不同的 lane 来连接,lane 组合可以提供更高的带宽。

A PCIe connection consists of one or more (up to sixteen, at the moment) data-transmission lanes, connected serially. Each lane consists of two pairs of wires, one for transmitting and one for receiving. There are 1, 4, 8 or 16 lanes in a single PCIe slot – denoted as x1, x4, x8, or x16.

PCIe 接口也经过了几个迭代,目前最常用的还是 PCIe 3.0.

系列 Bandwidth Gigatransfer Frequency
PCIe 1.0 8 GB/s 2.5 GT/s 2.5 GHz
PCIe 2.0 16 GB/s 5 GT/s 5 GHz
PCIe 3.0 32 GB/s 8 GT/s 8 GHz
PCIe 4.0 64 GB/s 16 GT/s 16 GHz
PCIe 5.0 128 GB/s 32 GT/s 32 GHz
PCIe 6.0 256 GB/s 64 GT/s 32 GHz

TDP

TDP,叫做 Thermal Design Power, 散热设计功耗,表示的是芯片达到最大负荷时热量释放的标准,单位是瓦特,是电脑冷却系统必须有能力驱散热量的最大限度,TDP 不是芯片释放热量的功率。

RAID 卡

RAID 卡是一种把多块独立物理硬盘按照不同方式组合形成一个逻辑硬盘,从而提供比单碟更高性能和提供冗余资料的物理硬件。

RAID 卡又分成硬 RAID 卡和软 RAID 卡,通过硬件完成 RAID 功能的叫做硬 RAID,通过软件使用 CPU 完成 RADI 的叫做软 RAID。一般不推荐使用软 RAID。

网卡

在民用级别,目前市面上大都是千兆网卡,不过渐渐有人已经开始使用万兆网卡了。

网卡 传输速率 理论峰值 备注
百兆 100Mbps 12.5MB/s  
千兆 1000Mbps 125MB/s 超五类以上的网线
万兆 10000Mbps 1250MB/s  

ECC memory

ECC memory 是 Error-correcting code memory 的缩写,这是一个可以校验并检查数据错误的内存。ECC 内存条一般用在不能忍受数据损坏的计算机中,比如科学计算或者金融领域。

塔式 vs 机架 vs 刀片

塔式服务器外形和普通家用服务器相差不多,塔式主机在主板扩展上有优势,一般预留接口较多,方便扩展。适用于入门和工作站。

机架服务器的外观安装工业标准统一设计,需要配合机柜统一使用,主要用于企业服务器密集部署。机架服务器因为需要密集紧凑,所以在设计时会非常紧凑,充分利用有限的空间。机架服务器宽度 19 英寸,高度以 U 为单位 (1U=1.75 英寸 =44.45 毫米).

刀片服务器的主体结构是主体机箱中可以有许多热拔插的主板,每一块主板都可以独立运行自己的系统,这些主板可以集合成一个服务器集群,在集群模式下可以连接起来提供更好的网络以及共享资源。

准备阶段

在了解了这一系列概念后就可以开始准备工作了,但首先需要了解配一台 NAS 的主要需求是什么,是作为媒体备份,是作为 Home Server,还是作为工作文件备份,还是作为下载机。

  1. 首先你了解自己需要多少存储容量,不同的使用需求自然对容量的要求也不一致,我的 QNAP 用了一年多,但是用来存每天使用的文件的 NextCloud 目前也只用了靠近 90G 左右,然而自从注册了 PT,不到半个月时间,就塞了近 1T 的磁盘,加上之前零零落落的文件,一块盘几乎要满了。所以对容量的需求直接决定了 NAS 组件的基础,需要多少盘位,需要多大容量的磁盘。如果普通家庭只用来存储家庭相片,那么即使按照单反最大一张照片几十兆来算,假设 50M 算,一块 4T 的硬盘也足够用好几年的;而如果是视频拍摄者,动辄几个 G 的视频素材,或者是高清视频爱好者,一部蓝光几十 G,那么在硬盘上的预算就要单独考虑了。
  2. 第二,存储在 NAS 中的数据安全性,存储的文件是否容忍丢失,是否需要冗余备份,还是说对数据安全没那么多要求。
  3. NAS 系统的选择,需要重量级的 FreeNAS 呢,还是轻量的 openmediavault,还是说需要开虚拟机,上 unRAID,或者自己用 Linux 的发行版搭建,OS 的选择间接的影响着硬件的选择,比如 FreeNAS 则需要支持 ECC 的内存,并且系统对内存的要求也比较多,如果选择 ESXi 则需要考虑主板是否对硬件直通有支持。
  4. 再次功能方面,对数据的同步是否要各个客户端的支持,是否需要内网穿透等等

如何选购 CPU

在 CPU 选购方面,NAS 看中的是低功耗,我需要 NAS 长时间运行,然而我并不需要 NAS 进行 CPU 密集型任务,所以对于 CPU 而言我并不追求性能,而如果其他人想要自己组一个 Home Server 就需要另外考虑了。

可能需要 CPU 的需求:

  • 视频转解码

如何选购主板

在主板选购时需要注意主板上接口的数量,比如 SATA 接口的数量;有没有预留一些可以扩展的口比如 PCIe;如果想要连接电视或者投影,是否有 HDMI,或者 DP 口。

  • 华擎 J3455-itx 主板
  • 华硕 Strix B360itx 主板
  • 超微 x10sba-o

J3455-itx 对比 J3455B-itx

J3455 自带 4 个 SATA 接口,J3455B 只有 2 个 SATA 口

如何选购内存

内存的选购也得看主板是否支持,上面提到了 ECC 内存,如果主板支持当然更好,不过大部分家用其实也不太需要上 ECC。

  • 如果选用比较老的主板可能只会有 DDR3L 的支持
  • 三星 8GB 2666Mhz DDR4 内存

如何选购机箱

机箱相较于 CPU 和主板,并没有那么主要,基本上也是跟着主板而选择。

  • 迎广 MS04,外观不错,4 个 3.5 寸盘热拔插,1 个或者 2 个 2.5 寸盘,ITX 机箱,1 个 5.25 寸光驱位,半高扩展卡
  • 万由 U-NAS NSC-410,4 盘热拔插,ITX 主板,全高扩展卡,1U 电源
  • mineNAS 4* 3.5 寸盘,2*2.5 寸盘,机箱含电源套装重量约 7 公斤,含电源 880

如何选购电源

不同的主板,机箱对电源大小和功率有一定的要求。

额定功率

不同型号的电源上经常能看到一个额定功率,这里的额定功率指的是电源能提供的最大功率,单位是瓦特 (W). 对于低功耗的 J3455 主板,使用 200~300W 左右的电源即可。

FLEX 和 1U 电源

在关于电源的选购上经常会听到 1U 或者 FLEX 电源这种说法,其实这里的 1U 和 FLEX 指的是电源的型号,有各自的规格:

  • 1U 电源一般是 40.5mm(高)100mm(宽)240mm(长)
  • FLEX 电源大小一般为 40.5mm81.5mm150mm, 一般又被称为小 1U 电源
  • 标准大小电源 ATX 电源,86mm* 140mm * 150mm 大小

1U 电源通常有更高的额定功率;因为 1U 通常是给机架服务器 (rack server) 设计,所以通常缺乏 PCIe 6/8 接口;因为在服务器领域,1U 电源通常设计为一直全功率运行,噪声可能是一个问题。而 FLEX 电源是从 1U 电源进化而来,通常设计为根据负载来调整风扇运行的速度,噪声影响可能稍微小一些。1

如何选择网卡

我对于网卡要求不高,毕竟家里千兆差不多了,也不是不够用。不过看到有人提到一块拆机万兆网卡 Mellanox 淘宝只要¥190,听起来还不错。

如何选择操作系统

之前整理过 几个 NAS 系统,FreeNas 需要硬件,unRAID, ESxi 都是闭源产品,且需要授权,先不论其强大的功能,对我而言 OpenMediaVault 比较合适,基于 Debian,我一直用 Mint 所以也比较熟悉。

实践阶段

可参考的搭配方案

我的搭配方案:

  • 主板 华擎 J3455 京东全新价格 Plus -20 488 入手
  • 内存 QNAP 拆机剩下的笔记本 DDR3L 2G*2
  • 迎广 MS04 加电源 879
  • SSD 拆机的闪迪 128G
  • 电源 益衡 7025B 淘宝价格 245 元
  • 机箱 星际蜗牛机箱 60-100 元

总价格在 1500 元

其他可选的机箱还有无牌的 ITX4 盘位机箱加一个航嘉电源,558。2

Babesun

什么值得买的分享 3

  • 机箱:博世 NAS 机箱(DIVAR IP3000)
  • 主板:ASROCK 华擎 J3455
  • 内存:金士顿 8G 1600
  • 硬盘:希捷 3TB x 2
  • 电源:ZUMAX 小 1U(FLEX) 200W

chriscn 配置

chriscn 的配置 4

  • 主板 /CPU 华擎 J3455-ITX 619 元
  • 金士顿 4GB DDR3L 179 元
  • 机箱 酷冷至尊小魔方 239 元
  • 电源 台达 VX270 270W 179 元
  • 系统盘 光威 120GB SSD 119 元
  • 数据盘 西部数据 紫盘 4TB * 3

v2ex 留言

v2ex 的留言 5:

  • 华擎的板载 CPU 的主板,J5005 J4105 J4005 都可以,板载 CPU 有 Intel 的核显,HDMI 接电视性能足够看 4K,TDP 10W 省电 - 迎广的 4 盘位机箱( J 系列板子最多 4 个 Sata 口,用 PCIe 转 Sata 的转接卡可以再扩展 1-2 个)
  • 系统装 OMV(Debian),系统直接装在 16-32G 的 U 盘长期插在背面( OMV 里有扩展可以优化日志写入,提升节省闪存寿命,怕 U 盘挂掉还可以装个定时备份系统镜像的插件,拷出来写个新 U 盘插上继续用),装个 Docker 扩展,然后 Gogs、Pi-hole、Wiki 等等的都可以用 Docker 来跑,存储部分是用 Snapraid (需要自己写定时任务更新校验盘)+ MergerFS (把多个硬盘分区虚拟成一个分区)。

不算硬盘的话整体下来 2000 左右(半年前的价格),比群辉性能高,还便宜,要是喜欢群辉也可以装黑群晖,CPU 是 x86 架构的跑软件没有兼容问题。5

XEON E3

这是一个来自知乎 的文章:

  • CPU XEON E3 1230V2, 4 核 8 线程,ECC
  • 主板 Supermicro X9SCL/X9SCM
  • 内存 32GB(8GB*4 ECC unbuffered)
  • SSD Samsung 840Pro 或者 Optane NVME MLC 的盘。用来当 L2ARC
  • HDD, 非 SMR 的硬盘 5T*4 个。东芝和 HGST 比较稳一些。SG WD 也不怕,反正 RAIDZ2 很稳。
  • U 盘一个
  • 电源,散热器,风扇,机箱随意。散热最好通畅一些最好。

当然如果追求性能,可以像这位大神一样配置 6:

  • 机箱 Fractal Design Node 804 Micro ATX Chassis
  • 电源 Corsair HX1000i ATX Power Supply
  • 主板 Supermicro A2SDi-H-TP4F Mini-ITX Motherboard
  • 内存 32GB DDR4-2400 Reg / ECC Memory × 4
  • 可信平台模块 Asus TPM-L R2.0 TPM
  • SFP+ 铜缆模块 Ubiquiti UF-RJ45-10G × 2
  • 网络适配器 Intel Ethernet Converged Network Adapter X550-T2
  • M.2 固态硬盘 Intel SSD Pro 7600p Series (1.02TB, M.2 80mm, PCIe 3.0 × 4, 3D2, TLC)
  • SATA 固态硬盘 Intel SSD DC S3710 Series (400GB, 2.5in SATA 6Gb/s, 20nm, MLC) × 2
  • SATA 机械硬盘 WD Red 3.5” 10TB WD100EFAX × 9
  • 光盘驱动器 Pioneer BDR-US01FAN
  • 风扇扩展卡 Asus Fan Extension Card × 2
  • CPU 风扇 Noctua NF-A6x25 60mm PWM Fan
  • 机箱风扇 Thermalright TR-121BP 120mm PWM Fan × 5
  • 机箱风扇 Thermalright TY-145SP 140mm PWM Fan
  • 硬盘支架 E.mini L04
  • 机箱串口挡板 Supermicro Serial Port Bracket
  • 机箱 USB 挡板 Asus USB 2.0 Bracket

推荐几个网站

  1. https://www.reddit.com/r/sffpc/comments/78fxd0/difference_between_flex_atx_and_1u/ 

  2. https://zhuanlan.zhihu.com/p/29970896 

  3. https://post.smzdm.com/p/546701/ 

  4. https://www.chriscn.cn/entry-level-nas-solution-part-01-hardware/ 

  5. https://www.v2ex.com/t/636772  2

  6. https://zhuanlan.zhihu.com/p/92257487 


2018-12-24 nas , linux , cpu , motherboard

每天学习一个命令:jq 命令行下处理 JSON

jq 是一个命令行下的 JSON 字符串处理工具,就像 sed 对于文本一样,jq 对应着 json 文件,jq 命令可以不同方式转换 JSON。jq 可以接受文本输入,默认情况下,jq 从 stdin 读取 JSON 流。通过和管道的组合可以非常方便的处理 JSON。

jq is a lightweight and flexible command-line JSON processor

使用实例

直接处理文件

js -I '.' input.json
cat input.json | jq -I '.'

jq 只能接受标准 JSON 格式,输入的文件内容必须严格遵守 JSON 格式标准。所以的属性名必须是双引号字符串。

格式化 JSON

jq 命令,原文格式化输出:

echo '{ "foo": "lorem", "bar": "ipsum" }' | jq .
cat input.json | jq .

将格式化的 JSON 字符串压缩到一行

如果有一个纯文本的大 JSON,比如好几 M 的文件,那么通过 GUI 去压缩显然不合理,通过命令非常快

jq -c . input.json

获取特定文本

比如上面的字符串

{ "foo": "lorem", "bar": "ipsum" }

那么如果

cat input.json | jq '.foo'

则输出的就是 foo 为 key 的值

"lorem"

如果 key 不存在则返回 null

key 的书写方式支持 .key.key 级联的访问。

外延

在线练习场

reference


2018-12-21 jq , json , linux , command

日志数据脱敏方法研究

日志文件中的敏感信息比如密码,电话号码等等进行过滤处理。第一个想到的方法就是去 log4j 中自定义 Appender,在 Appender 中正则匹配敏感信息进行过滤。

log4j 日志框架在之前 的文章中也也说过,主要有三个组件,Logger,Appenders 和 Layout,要过滤日志内容解决方法也就是从这三个地方着手。

log 时手动处理

Logger 着手就是在打日志的时候就处理,从根源解决。最精确的处理就是在每个类敏感的字段上手动处理,在打印日志时,封装方法手动转换 String 。这种方法唯一的缺点就是对于一个大型成熟的系统,要修改的日志打印地方太多,更本无法顾及。所以还需要寻找统一的方法。

自定义 Appender

如果从根源上没有解决,接下来就是在 Appender 中,Appender 决定了日志往哪里输出,那么这个时候就可以重写 subAppend 方法重新修改 LogEvent 来修改日志信息,将敏感的内容移除。比如

import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.spi.LoggingEvent;

public class DesensitizeDailyRollingFileAppender extends DailyRollingFileAppender {

    @Override
    protected void subAppend(LoggingEvent event) {
        String message = (String) event.getMessage();
        // do your stuff
        LoggingEvent modifiedEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), event.getTimeStamp(), event.getLevel(), modifiedMessage,
                event.getThreadName(), event.getThrowableInformation(), event.getNDC(), event.getLocationInformation(),
                event.getProperties());
        super.subAppend(event);
    }
}

扩展 PatternLayout

最后,如果自定义 Appender 的话,那么每一个日志删除的目的 Appender 都要手动实现一下,这个时候如果复写 PatternLayout 就可以让多个 Appender 来使用。

定义自己的 PatternLayout ,然后在配置文件 Appender 指定用我们自己的实现的 PatternLayout。

import java.lang.reflect.Field;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;

public class DesensitizeLayout extends PatternLayout {

    @Override
    public String format(LoggingEvent event) {
        if (event.getMessage() != null && event.getMessage() instanceof String) {
            String message = event.getMessage().toString();
            // do your stuff to change message
            try {
                Field msgField = LoggingEvent.class.getDeclaredField("message");
                msgField.setAccessible(true);
                msgField.set(event, message);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return super.format(event);
    }
}

RewritePolicy

如果使用的是 log4j 2.x 版本,也可以使用这种方法重写 RewritePolicy,然后 Override rewrite 方法。

总结

通过自定 Appender 或者 PatternLayout 可以实现敏感信息的脱敏,那么其实扩展可以实现其他的同类业务。比如固定格式输出,比如打印日志到内部日志收集器等等。

reference


2018-12-20 log4j , log , desensitize , 日志 , 脱敏

log4j PatternLayout 输出模板

log4j 下的 PatternLayout 只是 Layout 的一种,用来格式化日志文件的输出。在 PatternLayout 中,配置一个样板字符串,通过该字符串来定义输出格式。

log4j 还提供了其他三种 Layout

  • org.apache.log4j.HTMLLayout(以 HTML 表格形式布局)
  • org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
  • org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

这个类的目标是格式化 LoggingEvent 输出结果,这个结果依赖 conversion pattern.

conversion pattern 和 C 语言下面的 printf 方法非常类似。conversion patter 由逐字文本和格式化控制表达式(conversion specifiers) 组成。

每一个 conversion specifiers 都由一个 % 开始,紧跟着一个可选的 format modifiers (被称为 conversion character)。conversion character 指定了类型,比如日期,线程名。format modifiers z 则控制字段宽度,padding,左右调整。

比如 %-5p [%t]: %m%n 配置

root.debug("Message 1");
root.warn("Message 2");

则会输出

DEBUG [main]: Message 1
WARN  [main]: Message 2

ConversionPattern 参数的格式含义

格式名的含义:

%c 输出日志信息所属的类的全名
%C 调用 logger 的类的全名(包含包路径)
%d 输出日志时间点的日期或时间,默认格式为 ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH:mm:ss },输出类似:2002-10-18- 22:10:28
%f 输出调用 logger 所属的类的类名
%l 输出日志事件的发生位置,类,线程,代码行数
%L 调用 logger 的代码行
%m 输出代码中指定的信息,如 log(message) 中的 message
%M 调用 logger 的方法名
%n 输出当前平台的换行符,Windows 平台为“\r\n”,Unix 平台为“\n”
%p 输出日志的优先级,即 DEBUG,INFO,WARN,ERROR,FATAL。如果是调用 debug() 输出的,则为 DEBUG,依此类推
%r 输出自应用启动到输出该日志信息所耗费的毫秒数
%t 输出产生该日志事件的线程名

reference


2018-12-19 log4j , java , log

Unix 进程

Unix 内核在硬件之上,与硬件交互,系统文件读写,网络数据发送,内存分配,扬声器播放音频等等。程序不能直接访问内核,通信通过系统调用完成。

系统调用是内核和用户空间交互的桥梁,规定了程序和计算机硬件之间可以发生的交互。

Unix 的系统调用文档已经在系统中,输入 man man 查看。

进程是 Unix 系统基石,所有的代码都在进程中被执行。

进程标示

唯一进程标示 PID,PID 本身没有任何进程信息,只是一个数字。系统中每一个进程都有其父进程,PPID。多数情况下,特定进程的父进程就是调用他的进程。

文件描述符值用来跟踪打开的资源,已经关闭的资源没有文件描述符。

每个 Unix 进程都有三个打开的资源,STDIN,STDOUT,STDERR。

限制打开的资源数量

每个进程打开的资源数量都是限制的,进程资源限制中,分为 soft limit 和 hard limit. soft limit 指的是内核所能支持的资源上限,hard limit 是 soft limit 的上限,当设置 hard limit 之后 soft limit 只能小于 hard limit.

可以使用 ulimit -a 来查看资源限制情况。

进程环境变量

所有进程都从父进程继承环境变量。

C 库函数 setenv()getenv()

进程都有参数

所有进程都可以访问 ARGV 的特殊数组,argv 是 argument vector 缩写,参数向量

进程 fork

forking 是 Unix 编程中最强大的概念,fork 系统调用允许运行中的进程以编程的形式创建新的进程,这个新进程和原始进程一样。

在 forking 时,调用 fork 的进程被称为“父进程”,而新创建的进程被称为“子进程”。

forking 时会创建一样的新进程,所以 fork 尽管很快,但是会有一些问题,比如如果内存占用比较大,fork 多份之后可能内存被撑爆。

现代 Unix 采用写时复制(copy-on-write, CoW) 方法来克服这个问题,将实际内存复制操作推迟到真正写入的时候,父进程和子进程实际共享内存数据,直到其中一个需要对数据进行修改,才复制。

当 fork 多个并发子进程时,进程看管这些子进程,确保能够保持响应,对子进程的退出做出回应。

信号

信号 动作 说明
SIGHUP 1 Exit Hangup
SIGINT 2 Exit Interrupt
SIGQUIT 3 Core Quit
SIGILL 4 Core Illegal Instruction
SIGTRAP 5 Core Trace/Breakpoint Trap
SIGABRT 6 Core Abort
SIGEMT 7 Core Emulation Trap
SIGFPE 8 Core Arithmetic Exception
SIGKILL 9 Exit Killed
SIGBUS 10 Core Bus Error
SIGSEGV 11 Core Segmentation Fault
SIGSYS 12 Core Bad System Call
SIGPIPE 13 Exit Broken Pipe
SIGALRM 14 Exit Alarm Clock
SIGTERM 15 Exit Terminated
SIGUSR1 16 Exit User Signal 1
SIGUSR2 17 Exit User Signal 2
SIGCHLD 18 Ignore Child Status
SIGPWR 19 Ignore Power Fail/Restart
SIGWINCH 20 Ignore Window Size Change
SIGURG 21 Ignore Urgent Socket Condition
SIGPOLL 22 Ignore Socket I/O Possible
SIGSTOP 23 Stop Stopped (signal)
SIGTSTP 24 Stop Stopped (user)
SIGCONT 25 Ignore Continued
SIGTTIN 26 Stop Stopped (tty input)
SIGTTOU 27 Stop Stopped (tty output)
SIGVTALRM 28 Exit Virtual Timer Expired
SIGPROF 29 Exit Profiling Timer Expired
SIGXCPU 30 Core CPU time limit exceeded
SIGXFSZ 31 Core File size limit exceeded
SIGWAITING 32 Ignore All LWPs blocked
SIGLWP 33 Ignore Virtual Interprocessor Interrupt for Threads Library
SIGAIO 34 Ignore Asynchronous I/O

进程可以在任何时候收到信号,常见的用法在 shell 中使用 kill 发送信号。在时间中,信号多由长期运行的进程使用,例如服务器和守护进程。

进程间通信

管道

管道是一个单向数据流,管道也是一种资源,有自己的文件描述符和其他一切,也可以和子进程共享。“流”数据没有开始和结束的概念,需要通过分隔符来确定。

套接字

Unix 套接字是一种只能用于同一台物理主机中进行通信的套接字,比 TCP 套接字快,适合用于 IPC。

管道提供的是单向通信,而套接字提供双向通信。

远程 IPC

如果要从单机扩展到多台机器,可以使用 TCP 套接字,或者 RPC,远程过程调用等来实现。

守护进程

在后台运行,不受终端用户控制。init 进程是所有进程的父进程。

总结

这本书能简单的了解下 Unix 下进程的一些知识,包括系统调用,资源限制,资源竞争,信号,进程通信等等内容,但内容都稍微有点浅,并且作者用了 Ruby,虽然不影响阅读,总有些隔阂。

reference

  • 《理解 Unix 进程》

2018-12-17 unix , linux , process

log4j appender

Appender 表示日志输出的地方,常见的有控制台,文件等等,log4j 自带了一些常用的 Appender。

日志中的 LEVEL 和 threshhold

log4j 框架中有两个概念 logger 和 appender。如果 logger 的最低 level 设置为 warn,这意味着任何日志 level 低于 warn 的日志都会被忽略。

一旦一个消息被 logger 接收,这条消息会被发送给一个或者多个 appenders(to console,to file,to mail server, etc). 每一个 appender 都会定义 threshold。比如可以限制打印到 console 的消息为 error,但是打印到文件的日志接收 warn 及以上。1

ConsoleAppender

可能是最常见的一个 Appender,输出到控制台,ConsoleAppender 将日志事件输出到 System.out 或者 System.err 中。

<appender name="console-appender" class="org.apache.log4j.ConsoleAppender">
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern"
      value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
  </layout>
</appender>

AsyncAppender

AsyncAppender 允许用户异步(asynchronously) 地打印日志,AsyncAppender 会收集所有发送到它的事件,并将它们分发到所有附加在它的 appenders 中。可以在 AsyncAppender 上附属多个 appenders。

AsyncAppender 会使用单独的线程来处理它缓冲区中的事件。

Important note: The AsyncAppender can only be script configured using the DOMConfigurator.

FileAppender

将日志 event 输出到文件,直接子类有 DailyRollingFileAppender,和 RollingFileAppender。

可选的 append 配置表示是否在原来的文件内容上追加日志,如果是 false,log4j 会清理文件内容,每次重启程序,原来的日志文件会丢失,默认为 true,日志文件会越来越大。

RollingFileAppender

RollingFileAppender 继承自 FileAppender 用来配置当日志文件到达一定大小则自动备份日志文件到其他地方。

两个参数 maxFileSize 和 maxBackupIndex

<appender name="file" class="org.apache.log4j.RollingFileAppender">
  <param name="append" value="false"/>
  <param name="maxFileSize" value="10KB"/>
  <param name="maxBackupIndex" value="5"/>
  <param name="file" value="/tmp/jutils/jutils.log"/>
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern"
      value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
  </layout>
</appender>

DailyRollingFileAppender

DailyRollingFileAppender 继承自 FileAppender,定义的日志文件在用户指定的频率下会定时产生新的日志文件。

日志周期由 DatePattern 选项定义,模式需要遵循 SimpleDateFormat 格式,此处定义的日期格式会作为滚动日志文件的后缀。

举例,如果 File 选项设置为 /foo/bar.log 并且 DatePattern 设置为 “’.’yyyy-MM-dd”,那么在 2001-02-16 的午夜,日志文件 /foo/bar.log 文件会被拷贝到 /foo/ba.log.2001-02-16,然后在 /foo/bar.log 日志文件中会继续记录 2001-02-17 的日志。

<appender name="dailyRolling" class="org.apache.log4j.DailyRollingFileAppender">
  <param name="File"  value="/tmp/jutils/roll_jutils.log"/>
  <param name="DatePattern" value=".yyyyMMdd"/>
  <param name="threshold" value="error"/>
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%d{ISO8601} %-5p [%t] [%l] - %m%n"/>
  </layout>
</appender>

DailyRollingFileAppender 同样支持指定按照月,星期,半天,天,小时,分钟间隔的分割配置。

DatePattern Rollover schedule Example
’.’yyyy-MM 每月初  
’.’yyyy-ww 每个星期第一天,每星期第一天由地区决定  
’.’yyyy-MM-dd 每天 midnight  
’.’yyyy-MM-dd-a 每天 midnight 和 midday  
’.’yyyy-MM-dd-HH 每个小时  
’.’yyyy-MM-dd-HH-mm 每分钟开始时  

不要在 DatePattern 选项中使用冒号 : .

自定义 Appender

自定义 Appender 以实现在记录日志时将其中部分信息过滤。

import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.spi.LoggingEvent;

public class SensitiveDailyRollingFileAppender extends DailyRollingFileAppender {

    @Override
    protected void subAppend(LoggingEvent event) {
        String message = (String) event.getMessage();
        String modifiedMessage = SensitiveUtils.filterName(message);
        modifiedMessage = SensitiveUtils.filterName(modifiedMessage);
        modifiedMessage = SensitiveUtils.filterIdentityId(modifiedMessage);
        LoggingEvent modifiedEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), event.getTimeStamp(), event.getLevel(), modifiedMessage,
                event.getThreadName(), event.getThrowableInformation(), event.getNDC(), event.getLocationInformation(),
                event.getProperties());
        super.subAppend(event);
    }
}

如果想要更加基础可以继承 AppenderSkeletion,需要实现三个方法

  • protected void append(LoggingEvent loggingEvent) 打印日志核心方法
  • public void close() 关闭资源
  • public boolean requiresLayout() 是否需要 Layout

复写 append 方法实现自己的内容。

reference

  1. https://stackoverflow.com/a/5120069/1820217 


2018-12-17 log , java , log4j , slf4j

重构读书笔记

重构第一步,构造可靠的测试环境。

What

任何可以立即查阅的东西,都故意不去记忆。

什么是重构

重构,对软件内部结构调整,在不改变外部可观察行为的前提下,提高其可理解性,减低修改成本。

重构难题

对于修改接口,能获取所有调用者,那么可以安心修改。如果无法修改全部调用者,如果是公开已经发布的接口,就需要同时维护新旧两个接口,直到所有用户将该变化做出反应。

How

Duplicated Code

重复代码提炼。兄弟类,则推到 super class,如果是不完全相同的,则分解方法提炼统一的方法。

Long method

小函数准确的命名,积极地分解长函数。每当需要注释来说明,就应该把需要说明的内容写入独立函数,以其用途命名。

Large Class

如果类内部变量有相同的前缀和后缀,可能可以将其提炼到某个组件。

Long Parameter List

参数列表不应该过长,对象传递。

Divergent Change

类在不同方向上发生变化,针对外界发生的变化所有的修改都只发生在单一类中,需要找出特定原因造成的修改,将其提炼到另一个类中。

Shotgun Surgery

每次遇到某种变化,需要在不同的类内部做修改,这时候需要用 Move Method 和 Move Field 将所需要修改的代码放到同一个类中,如果没有合适的类,就创造一个。

Divergent Change 是“一个类受多种变化影响”,Shotgun Surgery 是“一种变化引发多个类修改”。

Feature Envy

面向对象的技术要点在于,这是一种“将数据和对数据的操作行为包装在一起”的技术。函数对某个类的兴趣超过了对自己所处类的兴趣,这种问题的焦点便是数据。比如某个函数为了计算某个值,从另一个对象调用半打取值函数,解法,将这个函数移动到另外的地方。

Data Clumps

数据泥团,数据项成群结队在一起。

Primitive Obsession

对象打破了基本数据和体积较大的类的界限。

Switch Statements

switch 用多态来代替

Parallel Inheritance Hierarchies 平行继承

在为某个类增加子杯,也必须为另一个类增加子类。

Lazy Class


2018-12-16 java , refactor , coding , programming

JProfile 简单使用

在学习 ThreadLocal 的时候有人推荐了 JProfiler ,可以用来对 Java 内存泄露分析,JProfile 其实是一个 Java 的性能分析工具,不仅可以用来排查 OutOfMemoryError 的错误,对于查找系统瓶颈,查看 Java 堆信息等等都有很强大的功能支持。

搜索一番之后发现也有很多 Java Profiler 的工具,JDK 自带也有 Java VisualVM 这样的工具。

JProfiler

JProfiler’s intuitive UI helps you resolve performance bottlenecks, pin down memory leaks and understand threading issues.

安装注册

官网地址:

JProfiler 是商业软件,有 10 天试用期,到期注册码自行解决。

特性

  • profile a demo session and a saved session
  • attach a running jvm
  • profile an application server, locally or remotely
  • open a snapshot, can open HPROF and PHD snapshots

数据采集方式

两种采集方式

  • Sampling 采样,间隔时间将每个线程栈中方法栈中的信息统计出来,对应用影响小,数据统计可能不精确
  • Instrumentation, 在 class 加载之前,JProfier 把相关功能代码写入到需要分析的 class 中,对正在运行的 jvm 有一定影响。

启动方式

  • Attach mode ,将本机正在运行的 jvm 加载 JProfiler Agent
  • Profile at startup,将指定的 JProfiler Agent 手动加载到该 jvm
  • Prepare for profiling
  • Offline profiling

jprofiler

Java VisualVM

reference


2018-12-14 java , jprofiler , visualvm

英语搭配语字典整理

最近用 GoldenDict 查词非常频繁且非常有效的提高了阅读的效率,但是在日常有的时候听一些英语口语的广播节目的时候,经常会有一些短语搭配,而我们平时如果写作的话,其实短语较于单词更为重要,口语亦然。所以产生了一个念头,如果有一本英语搭配语字典就能够提高不少效率,没想到都不用去刻意搜索,就出来了好几个推荐。

  • Oxford Collocation Dictionary 牛津英语搭配语词典
  • The BBI dictionary of English word combinations BBI 英语搭配词典
  • Longman Collocations Dictionary and Thesaurus 朗文搭配
  • Longman Language Activator 朗文英语联想活用词典,更准确来说这一本更像是一部同义词解析词典,但也有涉及短语搭配
  • Oxford Learner’s Thesaurus

比如在查阅 dictionary 时,将查阅字典这一类的词组 look up the dictionary 也能够显示出来。在别人分享的一篇文章中,作者举了一个例子 open up the possibility ,开启了什么的可能性,possibility 这个单词非常常见,但是却少有人意识到它可以和 open up 一起用。搭配字典在英语学习中,尤其是非母语人士的英语写作中起着很大的帮助作用。越普通,越常见的单词就越应该了解其常用的搭配。

牛津英语搭配语词典 Oxford Collocation Dictionary

一种全新的英文词典,提供词于词见常用并且地道搭配用法。可以有效帮组英语学生或成人 学习,写作和说地道的英文。 该词典对准备雅思、托福等英语考试也非常有益。

级别:Upper-Intermediate to Advanced

主要特点:

《牛津英语搭配词典》(英汉双解版)从崭新的角度探究了英语中词与词之间的组合关系,如 ‘bright idea’ or ‘talk freely’。这种组合不是任意的,而是受到语义、语法、语体和文化的制约。只有熟悉和掌握了英语搭配,才能真正做到让英语单词“为我所用”,地道自然地传达思想,与人高效沟通。本词典收录搭配丰富,逾 9,000 个常用英语词条, 达 150,000 个搭配词组;例句真实自然,50,000 条示例全部选自语料库;专辟 25 个不同主题的用法说明,加深对搭配词应用的理解;

oxford collocation

The BBI Dictionary of English Word Combinations

是一本非常轻薄的搭配语字典,词条详细,内容丰富,编排紧凑,同样也带来了一定阅读的不便。

bbi collocations

Longman Collocations Dictionary and Thesaurus

朗文搭配语词典,虽然没有牛津搭配语词典有名,但一样是一本非常地道的搭配语词典,排版甚至较牛津的更加清晰易读。

longman collocations

Longman Language Activator

朗文英语写作活用词典

Oxford Learner’s Thesaurus

更加准确来说这是一本 Thesaurus 词典,也就是同义词词典,会给出查阅单词的相近含义的单词,以便于联想学习。

总结

前三本字典是真正的搭配语词典,有着非常丰富的搭配语用法和解释,所以推荐可以日常对比使用。而后两本更加偏向于同义词活用,有时间再整理一下同义词词典吧。

reference


2018-12-14 english , learning , dictionary , goldendict , mdx , mdd , oxford

Bash Script

Shell Syntax - what is your input means to the shell

Shell Operations - what can shell do

  • read input from file
  • breaks the input into words and operations
  • parse the token into simple and compound commands
  • performs the various shell expansions
  • redirections
  • execute the commands
  • wait for command to complete and collect the exit status

Quoting - remove the special meaning from characters

Escape Character

A non-quoted backslash \ is the Base escape character. It preserves the literal value of the next character that follows.

除了 \newline 有特殊意义。其他都表示转义。

Single Quotes

Enclosing characters in single quotes(') perserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when proceded by a backslash.

Double Quotes

Enclosing characters in double quotes (") perserves the literal value of all characters within the quotes, with the exception of $, ```, \.

ANSI-C Quoting

\a      alert
\e \E   an escape character
\n      newline

$(command) is the modern synonym for command , $() will evaluate this command result and then evaluate the reset of line.

echo $(pwd)/file

with be

echo /path/to/file

Curly braces (${}) are also unconditionally required when

  • expanding array elements, as in ${array[2]}

Shell Commands - the types of commands you can use

Shell Functions - the way you group commands by name

Two ways to define a function:

function functname {

}

or

functionName() {

}

Shell Parameters - how shell stores values

Shell Expansions - how bash expands parameters and the various expansions available

Redirections - a way to control where input and output go

Executing Commands - what happens when you run a command

Shell Scripts - executing files of shell commands

Double parentheses

Double parentheses are used for arithmetic operations:

((a++))

((meaning = 42))

for ((i=0; i<10; i++))

echo $((a + b + (14 * c)))

Bash built-in variables

if we have file test.sh

#! /bin/sh
echo '$#' $#
echo '$@' $@
echo '$?' $?

then run:

> ./test.sh 1 2 3

We will get:

$#  3
$@  1 2 3
$?  0

Explain:

$# = number of arguments. Answer is 3
$@ = what parameters were passed. Answer is 1 2 3
$? = was last command successful. Answer is 0 which means 'yes'

Tips

看一些 shell 脚本的时候发现了如下的写法

VAR1=${VAR1:-VAR2}

这个语句允许当 VAR1 为空时用 VAR2 来赋值。

${parameter:-word}
    If parameter is unset or null, the expansion of word is substituted.
    Otherwise, the value of parameter is substituted.

这个在 Bash 中叫做 parameter expansion ,更多的内容可以参考 Bash Hacker’s Wiki

使用举例

当 variable 不存在时,会默认使用后者

$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value

当 variable 存在时,则使用前者

$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value

reference


2018-12-14 linux , shell , bash , assignment

电子书

最近文章

  • 使用 assh 来管理 SSH config 前两天一直在思考如何管理我的 SSH config 配置,最后的解决办法就是通过 git 版本管理起来。但这两天由冒出一个新的问题,那就是经常在国内直连 aws 或者 oracle 的机器时 ssh 连不上,但是通过国内的 VPS 中转就非常快,那这就意味着,我每一次连接国外的机器时必须先登录腾讯云的机器,然后在从腾讯云的机器上连过去,有些麻烦,但那天在 Twitter 上看到有人分享了一个 SSH 管理的命令行工具 assh,大致的看了一下使用简介,通过配置就可以完美的解决这个问题。
  • 备份和恢复从 Chrome Webstore 中下架的 Google Chrome Extension 这两天重装系统同步 Chrome 的数据才发现,我一直使用的 Dream Afar New Tab 这个我用了很久的扩展从 Chrome Webstore 消失了,不清楚是 Google 主动下架,还是作者很久没有更新被 Webstore 下了还是为什么。但这个扩展经过了很多的 Chrome 版本依然运行良好至今为止都能每天给我提供世界不同地方的美景。
  • Docker 网络与容器互联 简单整理一下 Docker 中 network 子命令,以及 docker 中相关 network 方面的内容。
  • MacBook Pro 初始设置记录 这里就简单的记录一下我从 Linux Mint 迁移到 MacOS 根据我的个人需求来初始化新的 MacBook Pro 的一些设置,和一些基本的感想。下面的内容会按照我自身的需求出发,我会列举我想要的功能然后在此基础上我需要借助哪些工具来实现。在切换到 MacBook Pro 之前,我使用了大约 6 年多的 Linux Mint,我已经有一套我自己的 Workflow,在切换到 Mac OS 之前我就在想哪一些的事情我是必须有 Mac 的软硬件才能做到,并且很提高某一方面的效率的,我列了一些
  • 多设备间同步 ssh 配置及密钥 ssh 客户端会在用户目录 ~/.ssh/ 目录下存放配置信息 (~/.ssh/config) 和公钥和私钥,如果有多个设备不同设备间的同步和管理就会成为一个比较头疼的问题。我在 Reddit 上抛出这个问题 后,我本来想的是通过 git 版本控制来进行管理,但有人说因为公钥和私钥都是二进制的文件,其实没有必要使用 git,任何一个同步工具就能够解决。