html 转 pdf 命令行工具 wkhtmltopdf

最近因为用 HTML 写了一个文档,当想要输出时保存为 PDF,而 Chrome 自带的打印功能,本来就能够快速的保存为 PDF,但是却保留不了页面中的链接,所以找到了这个 wkhtmltopdf.

官网地址:https://wkhtmltopdf.org/

wkhtmltopdf and wkhtmltoimage are open source (LGPLv3) command line tools to render HTML into PDF and various image formats using the Qt WebKit rendering engine. These run entirely “headless” and do not require a display or display service.

简而言之,wkhtmltopdf 是一个能够把 HTML 文档,或者在线 url 转换为 pdf 文档或者 image 图片的命令行工具。跨平台,支持 Linux,Windows,Mac。

安装

有两种方法,一种是直接使用编译好的版本,下载 安装即可,一种是用源码 编译安装。

验证

wkhtmltopdf -V

查看版本。注意只有 qt 版本才能保留页面中链接。

命令格式

命令用法

wkhtmltopdf [GLOBAL OPTION]... [OBJECT]... <output file>

实例

将 HTML 文件转换成 PDF

wkhtmltopdf a.html a.pdf

将 URL 保存为 PDF

wkhtmltopdf https://douban.com douban.pdf

把网页转换为图片同理

wkhtmltoimage a.html a.jpg
wkhtmltoimage https://douban.com douban.jpg

全局参数解析

--collate             当输出多个副本时进行校验(这是默认设置)
    --no-collate          当输出多个副本时不进行校验
    --cookie-jar <path>   从提供的 JAR 文件中读写 cookie 数据
    --copies <number>     设置输出副本的数量(默认主 1),其实为 1 就够了
-d, --dpi <dpi>           指定一个要分辨率(这在 X11 系统中并没有什么卵用)
-H, --extended-help       相对 -h 参数,显示更详细的说明文档
-g, --grayscale           指定以灰度图生成 PDF 文档。占用的空间更小
-h, --help                显示帮助信息
    --htmldoc             输出程序的 html 帮助文档
    --image-dpi <integer> 当页面中有内嵌的图片时,
                          会下载此命令行参数指定尺寸的图片(默认值是 600)
    --image-quality <interger> 当使用 jpeg 算法压缩图片时使用这个参数指定的质量(默认为 94)
    --license             输出授权信息并退出
-l, --lowquality          生成低质量的 PDF/PS , 能够很好的节约最终生成文档所占存储空间
    --manpage             输出程序的手册页
-B, --margin-bottom <unitreal> 设置页面的 底边距
-L, --margin-left <unitreal>   设置页面的 左边距 (默认是 10mm)
-R, --margin-right <unitreal>  设置页面的 右边距 (默认是 10mm)
-T, --margin-top <unitreal>    设置页面的 上边距
-O, --orientation <orientation> 设置为“风景 (Landscape)”或“肖像 (Portrait)”模式,
                                默认是肖像模块 (Portrait)
    --page-height <unitreal>   页面高度
-s, --page-size <Size>         设置页面的尺寸,如:A4,Letter 等,默认是:A4
    --page-width <unitreal>    页面宽度
    --no-pdf-compression       不对 PDF 对象使用丢失少量信息的压缩算法,不建议使用些参数,
                               因为生成的 PDF 文件会非常大。
-q, --quiet                    静态模式,不在标准输出中打印任何信息
    --read-args-from-stdin     从标准输入中读取命令行参数,后续会有针对此指令的详细介绍,
                               请参见 **从标准输入获取参数**
    --readme                   输出程序的 readme 文档
    --title <text>             生成的 PDF 文档的标题,如果不指定则使用第一个文档的标题
-V, --version                  输出版本信息后退出

reference


2019-01-05 html , pdf , linux , command

Java 模板引擎 freemarker

FreeMarker is a free Java-based template engine, originally focusing on dynamic web page generation with MVC software architecture. However, it is a general purpose template engine, with no dependency on servlets or HTTP or HTML, and is thus often used for generating source code, configuration files or e-mails. by wikiPedia

Official site:

Maven dependencies

Since with maven-based project, add these requirement to pom.xml

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.23</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${spring.version}</version>
</dependency>

FreeMarker with Spring MVC

import freemarker.template.*;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

private Configuration configuration;
configuration = new Configuration(new Version(2, 3, 20));
configuration.setClassForTemplateLoading(FreeMarkerTemplateUtils.class, "/templates");
configuration.setDefaultEncoding("UTF-8");
configuration.setLocale(Locale.CHINA);
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
try {
  Template template = configuration.getTemplate("user_email.ftl");

  String body = FreeMarkerTemplateUtils.processTemplateIntoString(template, userTemplateVariable);
} catch (IOException | TemplateException e) {
  log.error("userTemplate error", e);
}

Write to file

Writer out = new FileWriter(dir + "/freemarker.html");
template.process(root, out);

Syntax

default value

Starting from freemarker 2.3.7, you can use this syntax :

${(object.attribute)!}

or, if you want display a default text when the attribute is null :

${(object.attribute)!"default text"}

list

If you have a list as List<Food> menu

<#list menu as food>
    ${food.name} ${food.price?string.currency}
</#list>

if/switch

<#if var == 1>
1
<#elseif var == 2>
2
<#else>
0
</#if>

and switch

<#switch y>
<#case "one">
    one
    <#break>
<#case "two">
    two
    <#break>
<#case "three">
    three
    <#break>
<#default>
    zero
</#switch>

function

<#function fact n>
  <#if n == 0>
    <#return 1 />
  <#else>
    <#return fact(n - 1) * n />
  </#if>
</#function>

<#list 0..10 as i>
  ${i}! => ${fact(i)}
</#list>

reference


2019-01-04 java , template-engine , freemarker , email-template , html

RSS 订阅列表整理

用 RSS 这么多年,陆陆续续给自己的订阅列表增加,删除,更新了很多的订阅源,也有很多的订阅源陆陆续续的失效,也有很多的新博客陆陆续续的涌现,不过如今的 RSS 早已经不像当年,很多新站点甚至都不会再提供 RSS 输出。

之前偶然间看到过一篇关于 RSS 整理的文章,觉得定期检视一下自己的订阅,更新也好,删除也好,整理让这些订阅源继续存在的理由也好,或者分享给更多的人也好,都是一件不错的事情。

我的所有订阅源都从 Google Reader 迁移到了 InoReader,订阅列表好几百项就不单独一一例举,只是将我平时经常查阅的,我觉得非常值得关注的列举一下,也欢迎大家推荐高质量的订阅源。我的部分订阅已经整理成了 InoReader 的 Bundle,具体内容可以参考下方。

个人订阅分类

00 每日必读

这一个分类是更新不频繁,但是只要更新质量有一定保证的源,我会刻意选择不让每天更新的数量有 999,所以这是一个经常清零的高质量源。

01 个人博客

这个分类中是一些关注的个人博客输出,因为有些博客更新并不是那么频繁,所以这个分类下的未读数一直都不是很高,这个目录下我存放一些有必要关注(可能是内容,可能是标题),但是又不需要非常及时关注的内容,比如说技术博客,常用工具博客等等

02Weibo&Ins

这个分类建了很久了,知道我的人肯定知道我不用 weibo,也把很多国内的社交网站删的一干二净了,但是有些时候总是有些信息源只更新 weibo,比如有些同学的,比如有些资源号,所以没办法我只能用工具 把 Weibo 的内容转成 RSS 输出到 InoReader 以便于存档和及时关注。至于 Instagram 同样,因为不怎么常打开,所以反而 RSS 看起来比较舒服。

03 VPS

这个分类创建之后只有特殊需求的时候才会看一下,大部分情况下都只是做个参考,这个分类收录了一些更新 VPS 优惠活动的站点,每当我想要购买 VPS 的时候会从中搜索一下这个提供商,看看历史记录里面的评价好坏。

04 Kindle

这个目录下是一些图书,Kindle 技巧,图书优惠的站点,本人看的也不是非常多,只是有需要的时候,一方面作为检索,另一方面作为备份。

05 软件与应用

这个目录放了一些推荐软件和应用专题的站点,很早再用 Windows 的时候关注了一批就顺手关注了,但是现在看的很少了。

06 播客

这个目录有关注一些播客制作的博客,有一些混音的博客,很少看。

07 购物

记录了商品的优惠价格,以作备份。

InoReader 组合包

每日必读

Kindle 相关

软件及应用

reference

  • http://maybeiwill.me/rss%E6%BA%90/

2019-01-03 rss , blog , blogger

2018 读书记录

又到一年的年末,和前几年 一样,总需要总结下今年,再畅想一下明年,前些年有些时候会用 Google Photos 来存书的封面,也会记录下书的名字,今年就直接用了豆瓣的豆列 来记录了。

虚构文学

相较于前两年对东野圭吾的狂热,今年刻意地减少了虚构文学的数量,一方面也是因为东野圭吾的小说已经看遍,再没有另外一个小说家能够如此吸引我。所以看今年的书单,除了《造彩虹的人》《白金数据》外,只有特德姜的《你一生的故事》等少数几本。

人文哲学

人文哲学或许是今年最大的改变,这都要从哈耶克的《通往奴役之路》开始,因为这本书听了一档人文通识解读的播客,自此之后看着一类的书籍再也不会感到无聊,再就是今年国内形势明显发生了改变,所以这一类的文学作品才又被重新认识。然后因为哈耶克所以又读 了哈耶克的《我为什么写作》,很多人认识哈耶克仅仅因为《通往奴役之路》然而这本杂文集却从另外一个维度让我认识了哈耶克,以及他的思想从何而来,甚至前几篇文章都可以作为自传来看,在别国维和的所见所闻至今让我印象深刻。

之后又看了《独裁者手册》这也是一本让我震惊的书,一本让我觉得每一个段落都值得摘抄的书,一本让我一读就停不下的书。不像有些书写得像学术论文,这本手册虽然也是两位教授的研究性报告,但却有条有理,甚至会让我觉得有些“八股”,抛出一个论点,辅以一些论证,每一章节,每一个观点都非常充分的表达了。

再到《人类简史》一本走到哪里都是放在畅销书架的大热门,而实话说,虽然一定程度上和作者的一些观点一致,但并没有让我觉得这本书的预见性。阅读这本书倒是让我学习了很多人类进化的历史过程。

最后还有一部不得不提的杂文集《野火集》,知道龙应台也已经好久,因为在看《大江大海 1949》的时候看到这本《野火集》就将其加到了待看列表,一本写在 1985 年的书,却预言了几十年后发生的事情,做坏事的方法不管在哪个年代都一样,也是非常值得推荐一读的。

技术

今年最多的可能就是技术类书籍了,也一定程度上达成了之前几年定下的目标,在看这些书的过程中,我也学会了粗读和精读,有些书因为出版年份较久,而技术发展是出版物无法跟随的,但是有些书中的理念和核心观点是不会变化的,就像年初看的 Docker 虽然有些技术细节发生了很大的变化,但是 Docker 的内在机制是没有发生大的变化的,再到 Python ,虽然很多书基于 2.x 版本,但是其实原理是相通的。

传记

就像我在一条豆瓣书评中说的那样,个人对传记类的书籍并不是很关心,想来也只在大学的时候读过金庸的传记,甚至连我最喜欢的 Verne,都没有特意去寻找他的传记,我觉得一个好的作家只需要在作品中表现自己即可,但是今年的一个契机,让我看了一些人物传记,这其中包括巴菲特,万达的王健林,再到腾讯传。看一个人物的成功历程,或许有些鸡汤,也能看出一些美化的痕迹,然而却都少不了这些人物之所以成功的理由,抛开那些勤奋,努力,天资,我看到的更多是这些人在那个时代超前的视野,对于时代变化的敏感,而这又离不开曾经的勤奋和努力。


2018-12-30 reading , book , douban , plan

用 Google Calendar 培养习惯

这一个条目在 Trello 的代办事项中已经躺了快两周,期间一直在寻找合适的任务提醒 app 能够来帮助初期养成一定的习惯,没想到寻寻觅觅最后竟然又回到了 Google Calendar 的怀抱。

培养习惯

个人原来就有一习惯,对于需要长期规划的有固定时间的事情一般都会记录在 Google Calendar 中,比如周期性长时间的课程,或者一次性的旅程时间安排等等,而对于非周期性任务用 Trello 来管理,所以一直想要寻找一个能够周期性提醒,关键是要手机通知栏提醒,但是使用起来又比较方便(可以一键 mark as done,定制任务快捷)的应用,下面是我总结出来的一些此类习惯培养 app,我认为必须匹配的一些功能:

  • 需要定时提醒,最好能够移动端通知栏提醒
  • 能够跨平台,至少移动端和桌面端要有提醒(Android,iOS,Web) 最好
  • 可以 mark as done
  • 即使任务比较短也能比较友好的显示

最开始的时候想用 Google Calendar 来定义周期性定时任务,这本来非常简单,但是 Google Calendar 在提醒的同时并不能 mark done,这就有些不便,并且对于短期,比如签到此类的任务总不能定义 5min 的任务吧。

其次又想到了日常天天在用的 Trello,然而 Trello 适合任务管理,对周期性任务支持也并不友好。

然后又在 iOS 上找到了番茄 todo,Tiny Routines,小目标,都非常精致,但都不是理想中的那么方便。并且这些 app 都参杂了太多的商业内容,虽然承认这些应用都很不错,但是也无形中增加了使用成本。

Google Calendar 中的 event,reminder,和 task

Google Calendar 中创建日程可能会发现如下三种类型

  • Event
  • Reminder
  • Task

这三种类型在 Google Calendar 中的作用各不相同,通常情况下,使用创建按钮在标题下方可能会看见 Event 和 Reminder 选项

google calendar new event

当时如果在周视图,或者月视图中,使用鼠标选择多天,那么在创建的对话框中会出现 Task 选项

google calendar new task

但是需要注意的是 Task 只能够选择一天,而事件则能够选择一个时间范围。所以这里就要求我们来具体区分一下这三者的区别。

Event

Event 事件是 Google Calendar 最重要的概念,事件是有发生的时间范围的,从创建事件的选择中就能看到,一个事件可以拥有如下的选项:

  • 事件的标题
  • 事件发生的时间,可以具体到分钟,或者定义是否重复
  • 在时间的具体信息中可以定义时间发生的地点,通知,是否有会议,事件安排在哪一个日历中,事件详细描述(包括格式化的内容,附件等)等等
  • 事件也可以有 Guests,可以邀请其他人来参与这个事件

总体来说 Event 是 Calendar 的核心,如果是有固定发生时间的事情,那么用 Event 来组织是最好的,在 Google Calendar 中会在视图中以设定的颜色来显示在图中。

Reminder

Reminder 提醒,提醒相较于 Event 就要简单很多,提醒只能够定义:

  • 标题
  • 需要提醒的时刻,而不是时间段
  • 是否需要重复提醒

所以从他的涵盖范围就能够知道 Reminder 是用来在特定时间来提醒一件比较能够快速完成的事情的,理论上提醒的事情应该能够短则几分钟,长则十分钟就能够完成的事情。而新建 Reminder 也是最最简单的事情,甚至用语音 “reminder me to do something at some time” 就能快速建立的事情。Reminder 生成的内容可以标记 Done,在界面中就会显示为横线删除的样子,表示已做,非常清楚。

Task

Task 是最让人混淆的事情,我个人习惯使用 Trello 来管理我的 Task,可以这么理解,Task 可以是还没有具体时间安排的任务。所以在日历中最上方全天安排点击的时候 Task 的选择才会出现。Task 能够设定的只有:

  • 标题
  • 一个模糊的日期,只能是天为单位
  • 一个简单的纯文本的描述

对于需要办但是却没有安排出具体时间来办的事情就可以使用 Task 来组织管理。Task 则更像一个 to-do list 管理工具,不过这个 to-do list 则会贯穿整个 Google 的产品线,在 Google Calendar 中创建的 Task 会在 Gmail 中出现

Goal

在 Google Calendar 的移动版,包括 Android 和 iOS 在点击加号之后可能会发现桌面版没有的一个选项,就是 Goal,目标,这个功能是我发现将 Google Calendar 提升一个境界的地方。在这个 Goal 中可以设定一个目标,比如看一本书,坚持一定时间的锻炼,再比如学习一个技能,包括但不限于语言啊,乐器啊等等,Google Calendar 默认给出了非常好看的一些模板,非常容易上手。在 Goal 中可以定义:

  • 目标的方向(比如说 Exercise,Build a skill, Friends & Family, Me time, Organize my life 等等等等)
  • 期望发生的频率 (Once a month, Twice a month, Once a week,Twice a week, 3 times a week, 4 times a week, 5 times a week, 6 times a week, Every day)
  • 期望每次花费多长时间(30min,1h,2h,半天,整天)
  • 期望发生在什么时间段(早上,中午,晚上,任意时间)

在制定这一系列方案之后 Google Calendar 会自动分析日程安排,将这个目标穿插在日程安排中,以给定的时间范围和频率定时提醒来完成目标。于是这个功能就可以当做习惯培养的绝好工具,不管做任何事情,指定一个目标让 Google Calendar 帮助你安排时间,简直太赞了。

更加重要的一点是,Goal 产生的每一次事件都能够标注是否 done,每一个事件打开都能够看到这个目标前几周的完成情况,以及是否 Mark 这一次 Done,这样就能够很好的督促自己的认真的完成每一次目标。

解决方案

后来在寻觅的过程中突然发现了移动版的 Google Calendar 点开加号除了常规的 Event,竟然还有 Goal 和 Reminder 两个选项。

Reminder 很好理解,字面意思,提醒,不过 Google Calendar 更加智能的是可以周期性提醒,那这就完美的解决了培养习惯通常开始需要的提醒,并且跨平台,有通知,这就非常方便了。

而 Goal 则是制定一个目标,由 Google Calendar 来自动决定哪个时间段来帮助完成这个目标。

几个 Chrome Extension

Checker Plus for Google Calendar

直接在 Chrome 的工具栏中访问 Google Calendar 中内容。

Toggl Button

允许在浏览器中追踪花了具体多长时间,和 Calendar 结合就能具体看到做一件事情花费了多久。需要结合 Toggl 这个网站使用,所有的数据都会被导入到该网站。


2018-12-29 google , google-calendar , habit , app

Java 查漏补缺之 Exception 和 RuntimeException

通常来讲 RuntimeException 是在编码过程中可以被避免的 Exception ,比如说 NullPointerException, ArrayIndexOutOfBoundException 等。如果每次都在调用前检查 null,就永远不会发生 NullPointerExceptionArrayIndexOutOfBoundException 同理。RuntimeException 不会被编译器检查。

Java 中有两种类型异常,一种是 checked exceptions,一种是 un-checked exceptions。检查的异常必须被显示的代码处理,un-checked exceptions 则不需要。任何一个从 Exception 派生的类都是 checked exception, 而从 RuntimeException 派生的则是 un-checked.

继承等级

Exception 和 Error 都是继承自 Throwable,Throwable 则是继承 Object。而 RuntimeException 则是继承 Exception。

举例

下面是一些常见的 RuntimeException

AnnotationTypeMismatchException,
ArithmeticException,
ArrayStoreException,
BufferOverflowException,
BufferUnderflowException,
CannotRedoException,
CannotUndoException,
ClassCastException,
CMMException,
ConcurrentModificationException,
DataBindingException,
DOMException,
EmptyStackException,
EnumConstantNotPresentException,
EventException,
IllegalArgumentException,
IllegalMonitorStateException,
IllegalPathStateException,
IllegalStateException,
ImagingOpException,
IncompleteAnnotationException,
IndexOutOfBoundsException,
JMRuntimeException,
LSException,
MalformedParameterizedTypeException,
MirroredTypeException,
MirroredTypesException,
MissingResourceException,
NegativeArraySizeException,
NoSuchElementException,
NoSuchMechanismException,
NullPointerException,
ProfileDataException,
ProviderException,
RasterFormatException,
RejectedExecutionException,
SecurityException,
SystemException,
TypeConstraintException,
TypeNotPresentException,
UndeclaredThrowableException,
UnknownAnnotationValueException,
UnknownElementException,
UnknownTypeException,
UnmodifiableSetException,
UnsupportedOperationException,
WebServiceException

reference


2018-12-24 java , exception

从零开始搭建 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

电子书

最近文章