快照持久化方式:可以将存在于某一时刻的所有数据都写入硬盘里面。
只追加文件:(append-only file,AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面。
redis.conf参数配置:
save 900 1, 900秒内有一次写入,存入快照
save 300 10
,300秒内有10次写入,存入快照
save 60 10000,60秒内有10000此写入,存入快照
同步机制(快照持久化):
appendfsync always:每个Redis写命令都要同步写入硬盘
,比较影响性能
appendfsync everysec:每秒执行一次同步,显式地将多个写命令同步到硬盘
(推荐)
appendfsync no:让操作系统来决定应该何时进行同步,有不确定性
AOF持久化:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
就是当AOF文件的体积大雨64MB,并且AOF文件的体积比上一次重写之后的体积大了一倍(100%)的时候,Redis会对AOF文件执行重写操作,整理AOF文件。
主从服务器:
如果用户在启动Redis服务器的时候,指定了一个包含slaveof host port选项的配置文件,那么Redis服务器将根据该选项给定的IP地址和端口来连接主服务器。
jedis.info()可以查询到大量与服务器相关的讯息。
关于redis的文章,网络上大多介绍的不是特别全面,简明易懂,下面是一个游戏平台商品交易市场,用redis实现的例子,里面充分用到了redis的事务特性,并对每行代码做出了详细解释:
只追加文件:(append-only file,AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面。
redis.conf参数配置:
save 900 1, 900秒内有一次写入,存入快照
save 300 10
,300秒内有10次写入,存入快照
save 60 10000,60秒内有10000此写入,存入快照
同步机制(快照持久化):
appendfsync always:每个Redis写命令都要同步写入硬盘
,比较影响性能
appendfsync everysec:每秒执行一次同步,显式地将多个写命令同步到硬盘
(推荐)
appendfsync no:让操作系统来决定应该何时进行同步,有不确定性
AOF持久化:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
就是当AOF文件的体积大雨64MB,并且AOF文件的体积比上一次重写之后的体积大了一倍(100%)的时候,Redis会对AOF文件执行重写操作,整理AOF文件。
主从服务器:
如果用户在启动Redis服务器的时候,指定了一个包含slaveof host port选项的配置文件,那么Redis服务器将根据该选项给定的IP地址和端口来连接主服务器。
jedis.info()可以查询到大量与服务器相关的讯息。
关于redis的文章,网络上大多介绍的不是特别全面,简明易懂,下面是一个游戏平台商品交易市场,用redis实现的例子,里面充分用到了redis的事务特性,并对每行代码做出了详细解释:
/**
* 用户将商品放入市场的过程
* @param jedis
* @param itemid
* @param sellerid
* @param price
* @return
*/
private boolean listItem(Jedis jedis, String itemid, String sellerid, double price) {
String inventory = "inventory:" + sellerid;
String item = itemid + "." + sellerid;
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
//监护用户包裹发生的变化,此处用了watch的乐观锁,watch之后其他线程都不可修改包裹信息
jedis.watch(inventory);
//如果指定的商品不在用户包裹里面,那么停止监控并返回false
if (!jedis.sismember(inventory, itemid)) {
jedis.unwatch();
return false;
}
//从jedis.multi()到trans.exec(),这是一个redis事务,redis事务可以一次性提交其中的所有命令,避免了分步提交
//数据的不一致性,同时减少了与redis连接的次数,缩短时间。
Transaction trans = jedis.multi();
//把商品添加到商品市场,并移除包裹中商品。
trans.zadd("market:", price, item);
trans.srem(inventory, itemid);
//若因为watch的乐观锁返回失败,则继续重试。
List<Object> results = trans.exec();
if (results == null){
continue;
}
return true;
}
return false;
}
/**
* 用户从市场购买商品
* @param jedis
* @param buyerid
* @param itemid
* @param sellerid
* @param lprice
* @return
*/
private boolean purchaseItem(Jedis jedis, String buyerid, String itemid, String sellerid, double lprice) {
String buyer = "users:" + buyerid;
String seller = "users:" + sellerid;
String item = itemid + "." + sellerid;
String inventory = "inventory:" + buyerid;
long end = System.currentTimeMillis() + 10000;
while (System.currentTimeMillis() < end) {
//此处从市场拿走了商品,从买家拿走了钱,所以两者状态要同时watch
try {
jedis.watch("market:", buyer);
Set<Tuple> tuples = jedis.zrangeWithScores("market:", 0, -1);
System.out.println("The market PurchaseItem liuzhe contains:");
for (Tuple tuple : tuples) {
System.out.println(" " + tuple.getElement() + ", " + tuple.getScore());
}
System.out.println("jedis.name():" + jedis);
double price = jedis.zscore("market:", item);
int funds = Integer.parseInt(jedis.hget(buyer, "funds"));
//检查商品价格是否变化,以及买家是否有钱购买
if (price != lprice || price > funds) {
jedis.unwatch();
return false;
}
Transaction trans = jedis.multi();
//先将买家钱给卖家,在将市场商品给买家
trans.hincrBy(seller, "funds", (long) price);
trans.hincrBy(buyer, "funds", (long) (-price));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
trans.sadd(inventory, itemid);
trans.zrem("market:", item);
List<Object> results = trans.exec();
//如果有人正在修改,watch的乐观锁会返回空数据,重试。
if (results == null) {
System.out.println("purchaseItem results null continue!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
continue;
}
return true;
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
return false;
}
/**
* redis中提供了pipelline参数,可以让用户在不用封装mutil()与exec()的时候,将命令一次请求,即非事务型
* 一次性连接redis进行处理。
* @param jedis
* @param token
* @param user
* @param item
*/
private void updateTokenPipeline(Jedis jedis, String token, String user, String item) {
long timestamp = System.currentTimeMillis();
Pipeline pipe = jedis.pipelined();
pipe.hset("login:", token, user);
pipe.zadd("recent:", timestamp, token);
if (item != null) {
pipe.zadd("viewed:", timestamp, token);
pipe.zremrangeByRank("viewed:" + token, 0, -26);
pipe.zincrby("viewed:", -1, item);
}
pipe.exec();
}
关于redis的安全以及事务性,在这里就基本介绍完毕,redis其性能非常高,但也不该乱用,应该用在合适的地方。