0%

vim可以通过scp来编辑远程文件,大约是这个样子:

1
2
$ vim scp://user@host/path/to/file 
$ vim scp://server_alias/path/to/file

很神奇的样子。此功能依赖于netrw.vim,vim已经在发行中集成。

psql 提供变量替换特性,类似于shell的变量。

psql的变量就是简单的名字/值对,名字只能有字母、数字和下划线组成。

使用\set命令来设置变量:

1
=> \\set foo bar

这样设置了变量foo,其值为bar。这样来显示变量的值:

1
2
=> \\echo :foo
bar

使用\set只指定变量名,不指定值时,会设置该变量,只不过其值为空。

使用\unset命令来销毁变量:

1
=> \\unset foo

使用\set命令,不提供任何参数,显示全部的变量。
下面展示的是系统预置的变量:

1
2
3
4
5
6
7
8
9
10
11
12
=> \\set
AUTOCOMMIT = 'on'
PROMPT1 = '%/%R%# '
PROMPT2 = '%/%R%# '
PROMPT3 = '>> '
VERBOSITY = 'default'
VERSION = 'PostgreSQL 9.4.8 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit'
DBNAME = 'reis'
USER = 'reis'
HOST = 'localhost'
PORT = '5432'
ENCODING = 'UTF8'

查看PostgreSQL版本

因此获取postgresql版本就有了另外一种方法:

1
2
=> \\echo :VERSION
PostgreSQL 9.4.8 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit

另一种方法是:

1
2
3
4
5
=> SELECT VERSION();
version
-----------------------------------------------------------------------------------------------
PostgreSQL 9.4.8 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit
(1 row)

二者结果是一样的。

===
[erq]

psql启动时会先读取系统范围的psqlrc文件,然后读取用户主目录下的.psqlrc文件

下面是一个简单的配置:

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
32
-- 静默模式
\\set QUIET ON

-- 设置扩展显示
\\x auto

--以大写字母自动完成关键字
\\set COMP_KEYWORD_CASE upper

-- null显示为(null)
\\pset null '(null)'

-- 显示query执行时间
\\timing

-- 不同的数据库使用不同的命令历史文件
\\set HISTFILE ~/.psql_history- :DBNAME

-- 历史记录忽略重复的命令
\\set HISTCONTROL ignoredups

-- 更详细的错误报告
\\set VERBOSITY verbose

-- 关闭自动提交事务.
\\set AUTOCOMMIT OFF

-- 提示符1
\\set PROMPT1 '%\[%033\[1m%\]%n@%/(%M)%R%\[%033\[0m%\]%#'

--关闭静默模式
\\unset QUIET

自动提交事务

AUTOCOMMIT是默认打开的,当命令执行成功时会自动进行提交。在自动提交事务打开时,如果要显式手动提交,那么必须在执行命令或命令块之前执行BEGIN或START TRANSACTION命令执行完命令后再执行END或COMMIT来手动提交事务。
当关闭自动提交时,命令执行成功后需要手动END或COMMIT来提交。
关闭自动提交时,系统默默的在任何没有开启事务的语句前自动添加BEGIN或START TRANSACTION等事务开始语句。

自动提交关闭时,要用ABORT或ROLLBACK显式的撤销回滚事务,如果没有提交退出当前会话,则未提交事务会自动回滚。

**注意:**这里有一个坑,当关闭事务自动提交时,使用psql导入数据库时,可能会因为sql文件中没有提交语句而最后回滚,但没有错误提示,只是没有什么数据也没导入而已.比如,pg_dump/pg_dumpall导出的sql脚本文件就没有COMMIT语句,从而导入不会成功.

提示符变量

%[%] 之间的字符解释为终端控制字符序列。

%digits 转换为八进制字符序列,比如 %033 转换为 \033 ,所以 %033[ 正好转换为终端转义控制序列起始字符 \033[ ,后面紧跟的正是终端转义控制序列,可以指定字体的颜色,粗细等等属性。

设置图形模式的终端转义序列的结束字符为m,所以,\033[与m之间的字符为真正的终端转义控制序列,这语法真的很@&^*(#!%

其实 \033[Esc[

完整详细的终端转义控制序列参见[4]

postgresql支持的提示符变量参见[1]

References:
[1]psql
[2]An Explained psqlrc
[3]psqlrc
[4]ANSI Escape sequences

===
[erq]

postgresql支持在表和文件之间拷贝数据,可以使用PostgreSQL扩展的SQL函数COPY或者psql内部命令\copy来做这件事。

导出数据的格式:

1
COPY table_name (query) TO 'filename' PROGRAM 'command' STDOUT \[ WITH OPTIONS \];

导入数据的格式:

1
COPY table_name (query) FROM 'filename' PROGRAM 'command' STDIN \[ WITH OPTIONS \];

更详细的格式描述见[1]

COPY函数

COPY函数在服务器上执行,如果输出到文件,要注意postgresql服务器进程有没有对指定目录的执行权限,比如:

1
=# COPY (SELECT * FROM base.tb_dictionary WHERE ...) TO '/tmp/designusage.csv' WITH CSV DELIMITER ',';

将查询结果输出到临时目录下的指定文件。debian系统postgresql系统进程用户postgres的主目录是/var/lib/postgresql,也可以将文件输出到此目录。
如无写权限,会提示:

1
ERROR: could not open file "..." for writing: Permission denied

\copy命令

psql命令\copy在客户端执行,如果输出到文件是输出到客户端的文件系统,要注意当前执行psql的用户权限。比如:

1
=# \\copy (SELECT * FROM base.tb_dictionary WHERE ...) TO '/tmp/designusage.csv' WITH CSV DELIMITER ','

如果要输出列名,可以指定HEADER选项,HEADER只用于CSV格式。
可以写到临时目录,也可以写到当前用户的主目录。

其实\copy命令实际上是使用了COPY FROM STDIN或者COPY TO STDOUT,然会通过STDIN或STDOUT与文件交互。

所以可以这样:

1
$ psql -c "COPY (SELECT * FROM base.tb_dictionary WHERE ...) TO STDOUT WITH CSV DELIMITER ',' " -U role -h host dbname > export.csv

使用COPY函数输出到STDOUT,然后重定向到文件。

References:
[1]copy data between a file and a table
[2]Outputting to CSV in Postgresql

===
[erq]

一个小坑,windows计划任务执行的命令或脚本,以及嵌套调用的命令或脚本,其路径名中不能包含括号,不能包含括号,不能包含括号。不然只会告诉你执行失败,退出码0x1,别无其他可用信息。

pandoc是一款强悍的文档的转换工具,支持绝大多数文档格式之间的相互转换,而且具有强大的控制能力。

安装

1
# apt install texlive-xetex pandoc

转换markdown

默认latex引擎pdflatex不支持中文,需要使用xelatex引擎,并且要指定中文字体

可以这样查看系统中文字体:

1
$ fc-list :lang=zh

然后mkd转换到pdf:

1
$ pandoc foo.mkd --latex-engine=xelatex -V CJKmainfont="Noto Sans CJK SC" -o foo.pdf

然而对中文的支持还是有些问题,这样会把较长的文本行截断,需要定制template来解决此问题。

先导出pandoc默认模板:

1
$ pandoc -D latex > mytemplate.tex

在生成的模板文件mytemplate.tex文件的第一行后面添加如下行:

1
2
\\XeTeXlinebreaklocale "zh"
\\XeTeXlinebreakskip = 0pt plus 1pt minus 0.1pt

将模板文件mytemplate.lex置于~/.pandoc/templates/路径下,或者置于转换命令当前目录下。

然后这样转换:

1
$ pandoc manual.mkd --latex-engine=xelatex -V CJKmainfont="Noto Sans CJK SC" -o manual.pdf --template=mytemplate.tex

还有一个小问题,默认生成的pdf边距比较大,可以通过geometry参数来控制边距。

所以最后的命令行大约是这个样子的:

1
$ pandoc manual.mkd --latex-engine=xelatex -V CJKmainfont="Noto Sans CJK SC" -o manual.pdf -V geometry:"top=2cm, bottom=1.5cm, left=1cm, right=1cm" --template=mytemplate.tex

可以用模板文件指定使用的字体,模板文件可以很复杂,嗯,latex太复杂了。

pandoc转换markdown时,对两个tab缩进支持不好,还没找到好的解决办法。

Mac OS X

安装pandoc和mactex

1
2
$ brew install pandoc
$ brew cask install mactex

中文字体可以使用苹方简体中文 “PingFang SC”

References:
[1]Pandoc With Chinese (简体中文)
[2]pandoc faqs
[3]Pandoc: Markdown to PDF, without cutting off code block lines that are too long
[4]纯文本做笔记 — 使用 Pandoc 与 Markdown 生成 PDF 文件
[5]使用xelatex生成中文pdf
[6]使用pandoc转换md为PDF并添加中文支持

===
[erq]

tomcat自身支持会话复制的集群。

此post主要讲使用memcached存储会话,使用msm(memcached-session-manager)来管理会话复制。

通过配置共享会话的tomcat集群,可以提高服务的高可用性,并可以做到不停机连续更新应用程序。

示例配置采用两台机器,ip分别为10.100.0.20和10.100.0.21。每台机器分别部署nginx,tomcat和memcached。两个tomcat实例和两个memcached实例通过msm组成一个会话共享集群,前端由nginx做负载均衡。

还可以在nginx之前做DNS负载均衡。

nginx配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

upstream servers {
server 10.100.0.20:8080;
server 10.100.0.21:8080;
}

location / {
proxy_pass http://servers;
proxy_set_header Accept-Encoding "gzip";

# proxy websocket reverse
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

nginx会将客户请求分发到后端服务器组

memcached配置
安装

1
# apt install memcached

memcached默认安装只监听本地回环地址,更改/etc/memcached.conf,注释掉下面的行:

1
#-l 127.0.0.1

重启memcached服务会监听所有本地接口。

msm和tomcat配置

kiro序列化性能较高,因此这里使用kiro序列化器。

将msm基础包memcached-session-manager-${version}.jar,memcached-session-manager-tc8-${version}.jar和spymemcached-2.11.1.jar,以及kryo序列化支持jar包拷贝到$CATALINA_HOME/lib/目录。

debian系统中tomcat8的lib目录位于/usr/share/tomcat8/lib/

还有一个包Objenesis也需要下载安装到此目录中。

sticky sessions + kryo配置

/etc/tomcat8/context.xml文件中context一节最后添加:

1
2
3
4
5
6
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:10.100.0.20:11211,n2:10.100.0.21:11211"
failoverNodes="n1"
requestUriIgnorePattern=".*\\.(icopnggifjpgcssjs)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>

msm默认处于sticky模式,因此不用显式指定sticky参数。failoverNodes参数指定本机memcached节点名称,这样正常情况下msm会存储会话到其他memcached节点,当没有其他节点可用时才会使用failoverNodes。

non-sticky sessions + kryo配置

/etc/tomcat8/context.xml文件中context一节最后添加:

1
2
3
4
5
6
7
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:10.100.0.20:11211,n2:10.100.0.21:11211"
sticky="false"
sessionBackupAsync="false"
lockingMode="auto"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>

这里明确指定sticky参数为false,注意不要设置requestUriIgnorePattern参数,否则当前配置下会出现问题,无法完成session共享。

sticky会话模式就是将用户“粘”在某一个服务器节点上,即同一个会话中的请求必须被转发到同一个节点上,除非该节点宕机才转发到故障转移节点。

non-sticky会话模式则是每一次请求都可能转发到不同节点。

sticky会话模式性能更好。

References:
[1]SetupAndConfiguration
[2]分布式session

===
[erq]

众所周知的原因,访问国外的网络不是那么顺畅。gradle下载插件时,几乎无法下载,而使用proxychains也不凑效。
可以这样为gradle设置全局socks5代理:

$HOME/.gradle/gradle.properties文件中添加如下行,如没有该文件请自行建立:

1
org.gradle.jvmargs=-DsocksProxyHost=127.0.0.1 -DsocksProxyPort=1080

如果不设置代理,也可以使用maven镜像仓库,或者maven本地仓库。

最后,祝狗日的Great Fucking Wall和XXX早日死掉!

===
[erq]

设置NAT内部服务器,并且设置了端口回流,内网可以正常通过公网ip访问内部服务。

但是当通过外网访问该服务时,从服务器上观察,TCP连接的源地址也被替换成了防火墙的内网接口地址,不过访问一切正常。

经排查,是因为设置端口回流时,在内网接口的ACL条目中未指定source,类似如下:

1
rule 216 permit ip destination 10.100.0.31 0

导致防火墙将所有访问NAT服务的源地址全部替换成了防火墙的内网接口地址(内网接口优先级高,且不区分内外网网络地址???)。

通过指定哪些内网段访问NAT服务器时可以通过内网接口,可以只替换这些网段的源地址。

1
2
rule 226 permit ip source 192.168.1.0 0.0.0.255 destination 10.100.0.31 0 
rule 227 permit ip source 192.168.2.0 0.0.0.255 destination 10.100.0.31 0

这样以来,外网访问时,源地址没有被替换,但acl rule未指定的其他内网地址段将不能通过公网ip访问NAT服务。

===
[erq]

rman备份脚本出现错误提示:

1
2
3
4
5
6
7
RMAN-06207: WARNING: 380 objects could not be deleted for DISK channel(s) due
RMAN-06208: to mismatched status. Use CROSSCHECK command to fix status
RMAN-06210: List of Mismatched objects
RMAN-06211: ==========================
RMAN-06212: Object Type Filename/Handle
RMAN-06213: --------------- ---------------------------------------------------
RMAN-06214: Archivelog D:\\ARCHIVED_LOG\\ARC24290_0749146507.001

然后手动执行crosscheck并重新删除:

1
2
RMAN> crosscheck archivelog all;
RMAN> delete obsolete;

提示由于恢复目录中没有归档日志的信息,无法删除。列出的归档日志是早已经物理删除掉、无用的日志。

1
RMAN> delete expired archivelog all;

也无法删除

最后,强制删除废弃的归档日志,force关键字会忽略掉错误将其干掉。

1
RAMN> delete force obsolete;

删除成功。

===
[erq]