0%

在express站点中使用ejs模板引擎

选择ejs 是因为使用类似jsp技术,使用方式很像,页面可读性要比jade要好,个人习惯使用ejs。

配置模板

1
2
3
4
5
6
7
var express = require('express');

var app = express();
app.set('views', './views')
app.engine('.html', require('ejs').__express);
app.set('view engine', 'html');

后台代码

1
2
3
app.use('/demo', function (req, res, next) {
res.render('demo', {'template':"ejs});
});

模板代码

demo.html

1
2
3
4
5
6
7
<!DOCTYPE html>
<html lang="en">
<body>
hello <%=template %>
</body>
</html>

node.js读取json文件

目的

在node.js项目中如何获取json文件,本篇文章主要讲述两个方面:1.客户端 2.服务端。

实践

本次采用web框架为express

1.客户端
目录结构为:

1
2
3
4
5
/
/public/conf/demo.json
/index.js
/package.json
/index.html

index.js内容如下:

1
2
3
4
5
6
var express = require('express');
var app = express();
app.use(express.static('public'));
app.listen(80, function () {
console.log('Example app listening on port 80!');
});

在index.html中获取如下:

1
2
3
$.getJSON('conf/demo.json', function (data) {
console.log(data);
})

2.服务端
index.js内容如下:

1
2
3
4
5
6
7
8
9
var express = require('express');
var app = express();
var CONFPATH = "./public/conf/demo.json";
var fs = require('fs');
var result = JSON.parse(fs.readFileSync(CONFPATH));
console.log(result);
app.listen(80, function () {
console.log('Example app listening on port 80!');
});

Kibana之sentinl slack使用教程

简介

Slack是一个团队协作沟通平台,至于它的强大,就不在这里多说了,sentinl 集成slack,可以将监控告警发送至其中,这个平台支持PC和APP,可以让开发运维人员实时获取监控服务状态。

申请slack

  1. 注册账户
  2. 点击右上方按钮创建workspace
  3. 新建channel ,进入创建好的workspace,在左侧菜单栏创建,将该chanel设置成public
  4. 集成incoming-webhook,获取Webhook URL。详细步骤详见此处

kibana配置

在kibana.yml配置文件中增加以下内容

1
2
3
4
5
6
7
8
sentinl:
settings:
slack:
active: true
username: truman
hook: 'https://hooks.slack.com/services/******/*****/*****'
channel: '#messagesend'

其中hook配置项为Webhook URL

sentinl 配置slack action

在sentinl中增加slack action

1
2
3
4
5
6
7
"slack action": {
"throttle_period": "0h0m1s",
"slack": {
"channel": "#messagesend",
"message": "payload.hits.total:{{payload.hits.total}}",
"stateless": false
}

nodejs邮件发送

介绍

node.js发送邮件有多种第三方模块,比较有名的是emailjs,nodemailer,个人感觉emailjs更轻量级,使用更简单,nodemailer关注人更多,功能更加完善。

实践

本次选用这两种,仅实现简单发送邮件功能,更多功能,请查询官网API.
首先新建文件夹node,然后在该文件夹下新建package.json文件,在其中增加以下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "node_email_demo",
"description": "application created by truman",
"version": "1.0.0",
"dependencies": {
"emailjs": "^1.0.8",
"nodemailer": "^4.1.0"
},
"repository": "",
"license": "MIT",
"engines": {
"node": ">=6.0.0"
},
"readmeFilename": "README.md"
}

在node 目录下执行命令

1
npm install
  • emailjs
    新建myemailjs.js文件,添加如下内容:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var email       = require("emailjs");
    var server = email.server.connect({
    user: "aibibang@sohu.com",
    password:"*********",
    host: "smtp.sohu.com",
    ssl: false
    });

    // send the message and get a callback with an error or details of the message that was sent
    server.send({
    text: "i hope this works",
    from: "aibibang@sohu.com",
    to: "aibibang@sohu.com",
    subject: "testing emailjs"
    }, function(err, message) { console.log(err || message); });

执行即可发送成功!

1
node myemailjs.js
  • nodemailer
    新建mynodemailer.js文件,添加如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const nodemailer=require("nodemailer");

let transporter = nodemailer.createTransport({
host: 'smtp.sohu.com',
port: 25,
auth: {
user: "aibibang@sohu.com", // generated ethereal user
pass: "*********" // generated ethereal password
},
secure: false // true for 465, false for other ports
});
var message = {
from: 'aibibang@sohu.com',
to: 'aibibang@sohu.com',
subject: 'nodemailer test',
text: 'i hope this works'
};

transporter.sendMail(message, function(err){
if(err){
console.log(err);
}
});

执行即可发送成功!

1
node mynodemailer.js

总结

  1. 如果SMPT服务器没有进行安全校验,那么一定要去掉用户与密码,这点要和java API区别,切记,为了这个问题,花费了一天代价。
    例如如下问题:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    { Error: no form of authorization supported
    at module.exports (/data/truman/node/node_modules/emailjs/smtp/error.js:2:13)
    at initiate (/data/truman/node/node_modules/emailjs/smtp/smtp.js:543:44)
    at caller (/data/truman/node/node_modules/emailjs/smtp/smtp.js:48:14)
    at attempt (/data/truman/node/node_modules/emailjs/smtp/smtp.js:415:14)
    at caller (/data/truman/node/node_modules/emailjs/smtp/smtp.js:48:14)
    at response (/data/truman/node/node_modules/emailjs/smtp/smtp.js:345:13)
    at caller (/data/truman/node/node_modules/emailjs/smtp/smtp.js:48:14)
    at response (/data/truman/node/node_modules/emailjs/smtp/smtp.js:201:11)
    at caller (/data/truman/node/node_modules/emailjs/smtp/smtp.js:48:14)
    at Socket.response (/data/truman/node/node_modules/emailjs/smtp/smtp.js:181:11)
    code: 7,
  2. 对于本地是否可以访问SMTP服务器,可以使用telnet,进行查验,如果都无法telnet通,肯定是无法发送邮件的。
    1
    telnet smtp.sohu.com 25

Sentinl-(Kibana Alert&Report App for Elasticsearch)

前言

最近公司ES集群升级到5.5.1,新版增加了许多新的功能,也废弃了一些特性,同时整合一些插件,做了一个统一的封装,ES栈也越来越丰富,强大了。

最近有增加X-PACK,X-Pack是一个Elastic栈扩展,将安全性,警报,监视,报告和图形功能捆绑到一个易于安装的软件包中。 X-Pack组件旨在无缝协同工作,您可以轻松地启用或禁用要使用的功能。

然并卵,这个东西是要收费的,但是这个并不妨碍开源方案,Sentinl就是一个开源方案,作为kibana插件,集成在kibana中,主要提供了预警和报告功能,在架构设计上往X-PACK上靠拢,只提供了一些基本功能,但对于目前一些简单业务需求,完全可以满足需求,这个软件开源不久,期待更多完善。

Sentinl简介

Sentinl 5扩展自Kibi / Kibana 5,具有警报和报告功能,可使用标准查询,可编程验证器和各种可配置操作来监控,通知和报告数据系列更改 - 将其视为一个独立的“观察者” “报告”功能(PNG / PDFs快照)。

SENTINEL还旨在通过直接在Kibana UI中整合来简化在Kibi / Kibana中创建和管理警报和报告的过程。

功能模块

  • Watchers
  • Alarms
  • Reports

Watchers是Sentinl核心,主要由 input,Condition,Transform,Actions几大块组成,可以和X-Pack一一对应,部分文档可参考X-Pack,但需要注意的是它和X-Pack还有一些区别,主要体现在input只实现了search,其他并未实现,Actions也并未都实现

Sentinl安装与配置

1. 安装

1
/opt/kibana/bin/kibana-plugin install https://github.com/sirensolutions/sentinl/releases/download/tag-5.5/sentinl-v5.5.1.zip

2. 配置
在kibana.yml添加以下内容,可以根据具体需求删减

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
sentinl:
es:
timefield: '@timestamp'
default_index: watcher
type: watch
alarm_index: watcher_alarms
sentinl:
history: 20
results: 50
settings:
email:
active: false
user: username
password: password
host: smtp.server.com
ssl: true
timeout: 10000 # mail server connection timeout
slack:
active: false
username: username
hook: 'https://hooks.slack.com/services/<token>'
channel: '#channel'
report:
active: false
tmp_path: /tmp/
pushapps:
active: false
api_key: '<pushapps API Key>'

使用案例

业务需求:

监控指定索引1小时内数量大于1w,控制台提醒

实践:

  1. 配置General

输入名称和监控频率
2. 配置input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"search": {
"request": {
"index": [
"shoppingcartapi-*"
],
"body": {
"_source": false,
"query": {
"bool": {
"filter": {
"range": {
"post_date": {
"from": "now-1h"
}
}
}
}
}
}
}
}
}

其中shoppingcartapi-*为索引模糊名称,post_date为时间字段
3. 配置Condition

1
payload.hits.total > 10
  1. 配置Action

配置一个console action message填写以下内容

1
payload.hits.total:{ {payload.hits.total} }

Tip:通过{ { } }可以拿出search结果中的值,此处有空格是避免hexo问题,正常使用无需如此。

node.js简介

what node.js?

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
Node.js 的包管理器 npm,是全球最大的开源库生态系统。

node.js 原理

NodeJS的工作原理其实就是事件循环。可以说每一条NodeJS的逻辑都是写在回调函数里面的,而回调函数都是有返回之后才异步执行的!

应用场景

既然NodeJS处理并发的能力强,但处理计算和逻辑的能力反而很弱,因此,如果我们把复杂的逻辑运算都搬到前端(客户端)完成,而NodeJS只需要提供异步I/O,这样就可以实现对高并发的高性能处理。情况就很多啦,比如:RESTFUL API、实时聊天、客户端逻辑强大的单页APP,具体的例子比如说:本地化的在线音乐应用,本地化的在线搜索应用,本地化的在线APP等。

node.js优缺点

优点

  1. 采用事件驱动、异步编程,为网络服务而设计。其实Javascript的匿名函数和闭包特性非常适合事件驱动、异步编程。而且JavaScript也简单易学,很多前端设计人员可以很快上手做后端设计。
  2. Node.js非阻塞模式的IO处理给Node.js带来在相对低系统资源耗用下的高性能与出众的负载能力,非常适合用作依赖其它IO资源的中间层服务。
  3. Node.js轻量高效,可以认为是数据密集型分布式部署环境下的实时应用系统的完美解决方案。Node非常适合如下情况:在响应客户端之前,您预计可能有很高的流量,但所需的服务器端逻辑和处理不一定很多。

缺点

  1. 可靠性低
  2. 单进程,单线程,只支持单核CPU,不能充分的利用多核CPU服务器。一旦这个进程崩掉,那么整个web服务就崩掉了。

最近做docker image,编写shell 脚本,遇到以下问题,做个记录

1.问题一:

1
2
3
if [ "${1:0:1}" = '-' ]; then
set -- elasticsearch "$@"
fi

解释:以上if 条件是指第一个参数的第一个字符为-,则符合条件

2.问题二:

1
exec "$@"

解释:exec执行命令

3.问题三:

1
set -- elasticsearch "$@"

解释:set设置环境,这句话的意思其实是将elasticsearch 作为第一个参数补充到”$@”中
例如:
demo.sh

1
2
3
#!/bin/bash
set -- elasticsearch "$@"
echo "$@"

执行脚本

1
bash demo.sh hello truman

输出结果为:elasticsearch hello truman

4.问题四:

1
"$(id -u)"

解释:输出当前shell 环境UID(用户ID)

RediSearch 探索

简介

RediSearch是一个高性能的全文搜索引擎,可作为一个Redis Module 运行在Redis上,是由RedisLabs团队开发的。

特性

  • 多字段全文检索
  • 增量索引无性能损失
  • 文档排序
  • 复杂的子查询 and,or,not
  • 可选查询子句。
  • 基于前缀的搜索
  • 字段权重
  • 自动完成建议(使用模糊前缀建议)
  • 精确词组搜索,基于Slop的搜索
  • 基于Stemming的查询扩展在许多语言(使用Snowball)
  • 支持用于查询扩展和评分的自定义函数(请参阅扩展)。
  • 限制搜索到特定文档字段(最多支持8个字段)。
  • 数字过滤以及范围查找
  • 使用Redis自己的地理命令进行地理过滤
  • 支持任何utf-8编码文本
  • 检索完整的文档内容或只是ids
  • 将现有的HASH键自动索引为文档
  • 使用索引垃圾回收文档删除和更新

入门

安装/运行

1
2
3
4
5
wget https://github.com/RedisLabsModules/RediSearch/archive/v0.19.1.tar.gz
tar xvf v0.19.1.tar.gz
cd RediSearch-0.19.1/src
make all
nohup redis-server --loadmodule ./redisearch.so &

1. 创建索引

1
2
3
127.0.0.1:6379> FT.CREATE myIDs SCHEMA title TEXT WEIGHT 5.0 body TEXT url TEXT
OK

2. 增加文档到该索引

1
2
3
127.0.0.1:6379> FT.ADD myIDs doc1 1.0 FIELDS title "hello world" body "lorem ipsum" url "http://redis.io"
OK

3. 在该索引中搜索

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> ft.search myIDs "hello world" limit 0 10
1) (integer) 1
2) "doc1"
3) 1) "title"
2) "hello world"
3) "body"
4) "lorem ipsum"
5) "url"
6) "http://redis.io"

4. 删除索引

1
2
3
127.0.0.1:6379> ft.drop myIDs
OK

5. 添加并获取自动完成建议

1
2
3
4
5
127.0.0.1:6379> ft.sugadd autocomplete "hello truman" 100
(integer) 1
127.0.0.1:6379> ft.sugget autocomplete "he"
1) "hello truman"

引用

  1. redisearch.io

Redis 运维shell 工具

介绍

在Redis 集群运维过程中,经常需要做一些重复性工作,因为Redis 无中心设计,这就需要在每个节点中执行相同命令,对于这些重复性劳动工作完全可以通过shell处理,降低运维难度,减少工作量,以下是我在工作冲总结的脚本,仅供大家参考。

工具集

1. 集群健康状态检测

新建脚本redis_tool.sh,然后执行

1
sh redis_tool.sh clusterStatus 127.0.0.1 7000

2. 移除fail节点

新建脚本redis_tool.sh,然后执行

1
sh redis_tool.sh forget 127.0.0.1 7000

脚本内容

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
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/sh

function clusterStatus(){
instans=`redis-cli -c -h $1 -p $2 cluster nodes|grep -v fail|awk '{print $2}'`
for var in ${instans[@]};
do
echo $var
host=${var%:*}
port=${var#*:}
redis-cli -c -h $host -p $port cluster info |grep cluster_state:fail
done
}

function forget(){
instans=`redis-cli -c -h $1 -p $2 cluster nodes|grep -v fail|awk '{print $2}'`
for var in ${instans[@]};
do
echo $var
host=${var%:*}
port=${var#*:}
failnodes=`redis-cli -c -h $host -p $port cluster nodes|grep fail|awk '{print $1}'`
for nodeid in ${failnodes[@]};
do
echo $nodeid
redis-cli -c -h $host -p $port cluster forget $nodeid
done

done
}

# main start
case $1 in
clusterStatus)
echo "check redis cluster cluster_state..."
clusterStatus $2 $3;
;;
forget)
echo "forget redis fail nodes ..."
forget $2 $3;
;;
*)
echo "Usage: the options [clusterStatus|forget]"
;;
esac

Redis4.0 新特性尝鲜

1.目录结构

  1. 目录
  2. 前言
  3. 环境搭建
    1. 下载
    2. 安装
    3. 集群搭建
  4. 特性尝鲜
    1. 注意事项
    2. 升级内容
    3. 模块系统
    4. PSYNC 2.0
    5. 缓存驱逐策略优化
    6. 非阻塞 DEL 、 FLUSHDB 和 FLUSHALL
    7. 交换数据库
    8. 混合RDBAOF持久化格式
    9. 内存命令
    10. 兼容 NAT 和 Docker
  5. 引用

2. 前言

2017-07-14 redis 4.0 Stable version release,新增了许多新功能,此次专门抽出时间,探索一些功能,把握Redis未来的发展方向,同时积累经验,为未来升级Redis打下坚实基础。学习新的东西,如果不将它记录下来,过上两周,基本上就忘记做过什么了,对知识的掌握不利,以后尽量所有的学习都能产生文字记录,便于自己总结学习各种技术,也能给新人带去一点便利。

3. 环境搭建

安装方式,较之前没有多大变化,还是写一下,便于新手学习。

3.1. 下载

1
2
$ wget http://download.redis.io/releases/redis-4.0.0.tar.gz
$ tar xzf redis-4.0.0.tar.gz

3.2. 编译安装

1
2
$ cd redis-4.0.0
$ make

如果需要将redis-cli,redis-server等相关命令安装到/bin目录下,全局使用的话,可以使用如下命令:

1
$ make install

或者利用软连接实现:

1
2
3
$ make
$ ln -s redis-4.0.0/src/redis-server /bin/redis-server
$ ln -s redis-4.0.0/src/redis-cli /bin/redis-cli

在编译中可能会遇到如下问题:

1
zmalloc.h:50:31: 错误:jemalloc/jemalloc.h:没有那个文件或目录

出现这个问题是libc 并不是默认的 分配器, 默认的是 jemalloc, 因为 jemalloc 被证明 有更少的 fragmentation problems 比libc,关于更详细信息可以查看redis中REAME,md,其中有详细介绍,此处不再细说。

解决办法:

1
make MALLOC=libc

3.3. 新建集群

按照官方指导,搭建3m+3s集群,端口号7000-7005

以下为创建脚本:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/bin/bash
nodes=(7000 7001 7002 7003 7004 7005)
HOME_DIR=`pwd`
function create(){
echo "create"
if [ -d redis_cluster ];then
rm -rf redis_cluster
fi

mkdir redis_cluster
cd redis_cluster

mkdir `echo ${nodes[*]}`

for var in ${nodes[*]}
do
cd $var
touch $var-redis.conf
echo "port" $var >> $var-redis.conf
echo "cluster-enabled yes" >> $var-redis.conf
echo "cluster-config-file nodes.conf" >> $var-redis.conf
echo "cluster-node-timeout 5000" >> $var-redis.conf
echo "appendonly yes" >> $var-redis.conf
echo "daemonize yes" >> $var-redis.conf
echo "pidfile redis.pid" >> $var-redis.conf
cd ../
done
run;
src/redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

}

function run(){
echo run
for var in ${nodes[*]}
do
cd $HOME_DIR/redis_cluster/$var/
redis-server $var-redis.conf
cd $HOME_DIR/
echo Start redis ports ${var} finish.
done
}
function stop(){
cd $HOME_DIR/redis_cluster/
DIRS=`ls -l | grep "^d" | awk '{print $NF}'`
for d in $DIRS
do
PID=`cat $d/redis.pid`
if [ -n "$PID" ];then
kill -9 $PID
rm -f $d/redis.pid
fi
done
cd $HOME_DIR/
echo Stop redis ports ${DIRS} finish.
}


case $1 in
create)
echo " create redis cluster 锛?000,7001,7002,7003,7004.7005,7006,7007"
create
;;
run)
run
;;
stop)
stop
;;
*)
echo "Usage:[create|run|stop]"
;;
esac

执行

1
sh createCluster.sh create

一路回车即可,注意构建集群需要使用redis-trib.rb,需要额外执行

1
gem install redis

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[bigdata@trumanlab1 redis-4.0.0]$ redis-cli -c -h 127.0.0.1  -p 7000
127.0.0.1:7000> cluster nodes
63e698210378f4fda23c4070bea3b46f93952811 127.0.0.1:7000@17000 myself,master - 0 1500391716000 1 connected 0-5460
4091630217b64ece9a6fa55c26687a10c1f9a8b5 127.0.0.1:7001@17001 master - 0 1500391717501 2 connected 5461-10922
0b23853c3aa4f5b942a6239bc7bca71df36e121c 127.0.0.1:7005@17005 slave 12d05fb7c20bf001759f80cf3f65ad9df4b01af5 0 1500391716498 6 connected
12d05fb7c20bf001759f80cf3f65ad9df4b01af5 127.0.0.1:7002@17002 master - 0 1500391717000 3 connected 10923-16383
2e559b462362a9563f98b398af3984c05e25ef19 127.0.0.1:7003@17003 slave 63e698210378f4fda23c4070bea3b46f93952811 0 1500391716000 4 connected
c4f8e0a95579c772c7506c195b3c7984c73312b4 127.0.0.1:7004@17004 slave 4091630217b64ece9a6fa55c26687a10c1f9a8b5 0 1500391716000 5 connected
127.0.0.1:7000> set a a
-> Redirected to slot [15495] located at 127.0.0.1:7002
OK
127.0.0.1:7002> get a
"a"
127.0.0.1:7002>

4. 特性尝鲜

4.1 注意事项

IMPORTANT: Redis Cluster users, please note that, as specified in the list
of incompatibilities, Redis 4.0 cluster bus protocol is not compatible with
Redis 3.2, so in order to upgrade, a mass reboot of the instances is needed
and rolling upgrades are not possible. This change was needed in order to
add compatibility for Containers/NAT, where the bus port at a fixed offset
was not an acceptable design, so we had to change many things, resulting
in the incompatible protocol.

4.0版本与3.2版本传输协议不兼容,更改该协议的目的是为了实现Containers/NAT
为了升级,需要重启大量节点,无法做到滚动升级。

4.2 升级内容

  • Different replication fixes to PSYNC2, the new 4.0 replication engine.
  • Modules thread safe contexts were introduced. They are an >experimental API right now, but the API is considered to be stable and usable when needed.
  • SLOWLOG now logs the offending client name and address. Note that this is a backward compatibility breakage in case old code assumes that the slowlog entry is composed of exactly three entries.
  • The modules native data types RDB format changed.
  • The AOF check utility is now able to deal with RDB preambles.
  • GEORADIUS_RO and GEORADIUSBYMEMBER_RO variants, not supporting the STORE option, were added in order to allow read-only scaling of such queries.
  • HSET is now variadic, and HMSET is considered deprecated (but will be supported for years to come). Please use HSET in new code.
  • GEORADIUS huge radius (>= ~6000 km) corner cases fixed, certain elements near the edges were not returned.
  • DEBUG DIGEST modules API added.
  • HyperLogLog commands no longer crash on certain input (non HLL) strings.
  • Fixed SLAVEOF inside MULTI/EXEC blocks.
  • Many other minor bug fixes and improvements.

4.3 模块系统

Redis 4.0 发生的最大变化就是加入了模块系统, 这个系统可以让用户通过自己编写的代码来扩展和实现 Redis 本身并不具备的功能, 具体使用方法可以参考 antirez 的博文《Redis Loadable Module System》: http://antirez.com/news/106
因为模块系统是通过高层次 API 实现的, 它与 Redis 内核本身完全分离、互不干扰, 所以用户可以在有需要的情况下才启用这个功能, 以下是 redis.conf 中记载的模块载入方法:

1
2
3
4
5
6
7
################################## MODULES #####################################

# Load modules at startup. If the server is not able to load modules
# it will abort. It is possible to use multiple loadmodule directives.
#
# loadmodule /path/to/my_module.so
# loadmodule /path/to/other_module.so

目前已经有人使用这个功能开发了各种各样的模块, 比如 Redis Labs 开发的一些模块就可以在 http://redismodules.com 看到, 此外 antirez 自己也使用这个功能开发了一个神经网络模块: https://github.com/antirez/neural-redis
模块功能使得用户可以将 Redis 用作基础设施, 并在上面构建更多功能, 这给 Redis 带来了无数新的可能性。

4.4 PSYNC 2.0

新版本的 PSYNC 命令解决了旧版本的 Redis 在复制时的一些不够优化的地方:

  • 在旧版本 Redis 中, 如果一个从服务器在 FAILOVER 之后成为了新的主节点, 那么其他从节点在复制这个新主的时候就必须进行全量复制。 在 Redis 4.0 中, 新主和从服务器在处理这种情况时, 将在条件允许的情况下使用部分复制。
  • 在旧版本 Redis 中, 一个从服务器如果重启了, 那么它就必须与主服务器重新进行全量复制, 在 Redis 4.0 中, 只要条件允许, 主从在处理这种情况时将使用部分复制。

4.5 缓存驱逐策略优化

新添加了 Last Frequently Used 缓存驱逐策略, 具体信息见 antirez 的博文《Random notes on improving the Redis LRU algorithm》: http://antirez.com/news/109
另外 Redis 4.0 还对已有的缓存驱逐策略进行了优化, 使得它们能够更健壮、高效、快速和精确。

4.6 非阻塞 DEL 、 FLUSHDB 和 FLUSHALL

在 Redis 4.0 之前, 用户在使用 DEL 命令删除体积较大的键, 又或者在使用 FLUSHDB 和 FLUSHALL 删除包含大量键的数据库时, 都可能会造成服务器阻塞。
为了解决以上问题, Redis 4.0 新添加了 UNLINK 命令, 这个命令是 DEL 命令的异步版本, 它可以将删除指定键的操作放在后台线程里面执行, 从而尽可能地避免服务器阻塞:

1
2
3
4
5
6
7
8
9
10

127.0.0.1:7002> set a test
OK
127.0.0.1:7002> get a
"test"
127.0.0.1:7002> unlink a
(integer) 1
127.0.0.1:7002> get a
(nil)

因为一些历史原因, 执行同步删除操作的 DEL 命令将会继续保留。
此外, Redis 4.0 中的 FLUSHDB 和 FLUSHALL 这两个命令都新添加了 ASYNC 选项, 带有这个选项的数据库删除操作将在后台线程进行:

1
2
3
4
5
redis> FLUSHDB ASYNC
OK

redis> FLUSHALL ASYNC
OK

4.7 交换数据库

Redis 4.0 对数据库命令的另外一个修改是新增了 SWAPDB 命令, 这个命令可以对指定的两个数据库进行互换: 比如说, 通过执行命令 SWAPDB 0 1 , 我们可以将原来的数据库 0 变成数据库 1 , 而原来的数据库 1 则变成数据库 0 。这种场景是在非集群模式下使用的,在集群模式是不支持切换数据库的。默认所有的节点使用index 0。
以下是一个使用 SWAPDB 的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
redis> SET your_name "aibibang"  -- 在数据库 0 中设置一个键
OK

redis> GET your_name
"aibibang"

redis> SWAPDB 0 1 -- 互换数据库 0 和数据库 1
OK

redis> GET your_name -- 现在的数据库 0 已经没有之前设置的键了
(nil)

redis> SELECT 1 -- 切换到数据库 1
OK

redis[1]> GET your_name -- 之前在数据库 0 设置的键现在可以在数据库 1 找到
"aibibang" -- 证明两个数据库已经互换

4.8 混合 RDB-AOF 持久化格式

Redis 4.0 新增了 RDB-AOF 混合持久化格式, 这是一个可选的功能, 在开启了这个功能之后, AOF 重写产生的文件将同时包含 RDB 格式的内容和 AOF 格式的内容, 其中 RDB 格式的内容用于记录已有的数据, 而 AOF 格式的内存则用于记录最近发生了变化的数据, 这样 Redis 就可以同时兼有 RDB 持久化和 AOF 持久化的优点 —— 既能够快速地生成重写文件, 也能够在出现问题时, 快速地载入数据。
这个功能可以通过 aof-use-rdb-preamble 选项进行开启, redis.conf 文件中记录了这个选项的使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 When rewriting the AOF file, Redis is able to use an RDB preamble in the
# AOF file for faster rewrites and recoveries. When this option is turned
# on the rewritten AOF file is composed of two different stanzas:
#
# [RDB file][AOF tail]
#
# When loading Redis recognizes that the AOF file starts with the "REDIS"
# string and loads the prefixed RDB file, and continues loading the AOF
# tail.
#
# This is currently turned off by default in order to avoid the surprise
# of a format change, but will at some point be used as the default.
aof-use-rdb-preamble no

4.9 内存命令

新添加了一个 MEMORY 命令, 这个命令可以用于视察内存使用情况, 并进行相应的内存管理操作:

1
2
3
4
5
6
127.0.0.1:7002> memory help
1) "MEMORY USAGE <key> [SAMPLES <count>] - Estimate memory usage of key"
2) "MEMORY STATS - Show memory usage details"
3) "MEMORY PURGE - Ask the allocator to release memory"
4) "MEMORY MALLOC-STATS - Show allocator internal stats"

其中, 使用 MEMORY USAGE 子命令可以估算储存给定键所需的内存:

1
2
3
4
5
6

127.0.0.1:7002> set truman aibibang
-> Redirected to slot [2113] located at 127.0.0.1:7000
OK
127.0.0.1:7000> memory usage truman
(integer) 59

使用 MEMORY STATS 子命令可以查看 Redis 当前的内存使用情况:

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
33
34
127.0.0.1:7000> memory stats
1) "peak.allocated"
2) (integer) 2228415
3) "total.allocated"
4) (integer) 2228474
5) "startup.allocated"
6) (integer) 1054396
7) "replication.backlog"
8) (integer) 1048584
9) "clients.slaves"
10) (integer) 16858
11) "clients.normal"
12) (integer) 49630
13) "aof.buffer"
14) (integer) 0
15) "db.0"
16) 1) "overhead.hashtable.main"
2) (integer) 112
3) "overhead.hashtable.expires"
4) (integer) 0
17) "overhead.total"
18) (integer) 2169580
19) "keys.count"
20) (integer) 2
21) "keys.bytes-per-key"
22) (integer) 587039
23) "dataset.bytes"
24) (integer) 58894
25) "dataset.percentage"
26) "5.0161914825439453"
27) "peak.percentage"
28) "100.00264739990234"
29) "fragmentation"
30) "1.2773568630218506"

使用 MEMORY PURGE 子命令可以要求分配器释放更多内存:

1
2
redis> MEMORY PURGE
OK

使用 MEMORY MALLOC-STATS 子命令可以展示分配器内部状态:

1
2
redis> MEMORY MALLOC-STATS
Stats not supported for the current allocator

4.10 兼容NAT和Docker

Redis 4.0 将兼容 NAT 和 Docker , 具体的使用方法在 redis.conf 中有记载:

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
########################## CLUSTER DOCKER/NAT support  ########################
# In certain deployments, Redis Cluster nodes address discovery fails, because
# addresses are NAT-ted or because ports are forwarded (the typical case is
# Docker and other containers).
#
# In order to make Redis Cluster working in such environments, a static
# configuration where each node known its public address is needed. The
# following two options are used for this scope, and are:
#
# * cluster-announce-ip
# * cluster-announce-port
# * cluster-announce-bus-port
#
# Each instruct the node about its address, client port, and cluster message
# bus port. The information is then published in the header of the bus packets
# so that other nodes will be able to correctly map the address of the node
# publishing the information.
#
# If the above options are not used, the normal Redis Cluster auto-detection
# will be used instead.
#
# Note that when remapped, the bus port may not be at the fixed offset of
# clients port + 10000, so you can specify any port and bus-port depending
# on how they get remapped. If the bus-port is not set, a fixed offset of
# 10000 will be used as usually.
#
# Example:
#
# cluster-announce-ip 10.1.1.5
# cluster-announce-port 6379
# cluster-announce-bus-port 6380

5. 引用

  1. Redis 4.0新功能介绍
  2. Redis 4.0 release note