SSDB(redis+leveldb)提升记录插入性能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wxid2798226/article/details/82315200

缘起

问题:XX市场的性能要求

XX应用:

  • 假设千万日活,那么
  • 用户社交贡献奖励:每天转账1000w次,假设tps=10000,那么:需要1000w/10000=1000秒=17分钟
  • 自然时间挖矿奖励:每2小时转账600w次(打6折),假设tps=10000,那么:需要600w/10000=600秒=10分钟

XX号:

  • 假设千万日活,10%的人玩内容投资,每人每天平均投资5次,那么:每天总量投资次数500w
  • 投资的平均tps=500w/24/3600=600,假设峰值5倍计算,那么:投资的峰值tps=600*5=3000
    目前看:投资分红需要在产品层面做相应的设计,做到收敛,要不然迟早有一天转账会跪

目前的性能测试情况

从目前看,基于数据库的接口性能尚未达预期,后续拟增加批量转账接口,并对批量转账接口进行压测
从分散风险的角度出发,在进行sql调优,批量转账接口的同时,从架构角度进行新的设计,并对关键技术进行验证
两条腿走路

SSDB(redis+leveldb)提升记录插入性能

首先明确目前的瓶颈在哪里?

在现有的日志条件下,以用户注册为例,目前瓶颈在数据库上

  • 第一次发送,数据库里面啥都没有,时间消耗在插入 耗时:428ms

  • 第二次发送,java直接缓存返回,没有经过数据库 耗时:5ms

修改方案:mysql的代替

既然主要时间费在持久化层,由于mysql的插入需要经过多个环节:sql解析,执行计划,undolog,redolog,binlog等等,于是考虑引入更轻量的持久化层
SSDB是Redis+leveldb,兼有了Redis的高速度(内存缓存)和leveldb的海量容量,获2014年中国开源优秀项目奖项
+ 替代 Redis(兼容Redis协议), Redis 的 100 倍容量
+ LevelDB 网络支持,使存储不局限于本地
+ 支持丰富的数据类型, 如 list, hash, zset…
+ 支持高可用(HA)和集群(兼容Redis,使用Redis的集群方案Twenproxy)


修改实战

目前我们框架5大类,受影响的主要是Impl类采用新的Dao就行,修改相对比较简单,笔者用了半个上午时间就可以完成开户模块的修改
+ model类,不变
+ dao类,老的不变。新写一个dao,在ssdb模式时用新dao
+ service类,不变
+ controller类,不变
+ impl类,修改,ssdb时调用新dao,保存到ssdb中
如下是简单的调起:javasdk已经嵌入我们的项目(因为sdk很简单,只有4个类,我是复制源码,改了包名就可以了

SSDB ssdb = new SSDB("127.0.0.1", 9888);
   ssdb.set("a", "123");
byte[] val = ssdb.get("a");
System.out.println("value is :" +  new String(val));
ssdb.close();

具体的替代UserDao的类,使用了其set和get方法,User这个model类直接序列化和反序列化,以uid为key,value序列化后作为byte数组入SSDB(背后是leveldb的本地存储) leveldb的参考:leveldb日知录

public class UserSSDBDao {
    public static final String TABLE = "..."; //此处略去方案中敏感信息
    public static final String PREFIX = "U";

    public User selectByUid(String uid) {
        User user = null;
        SSDB ssdb = ConnFactory.applyUsable();
        try {
            byte[] tmp = ssdb.get(PREFIX+uid);
            if (tmp != null) {
                ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(tmp));
                user = (User) ois.readObject();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        ConnFactory.putBack(ssdb);
        return user;
    }

    public int insert(User user){
        SSDB ssdb = ConnFactory.applyUsable();
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(user);
            byte[] tmp = bos.toByteArray();
            ssdb.set(PREFIX+user.getUid(), tmp);
        } catch (Exception e) {
            e.printStackTrace();
        }

        ConnFactory.putBack(ssdb);
        return 1;
    }
}

imple类具体的修改(进行数据库操作前,会通过工厂类获得SSDB连接)

private UserSSDBDao userDao = new UserSSDBDao();

@Override
public User getUserByUid(String uid) {
    return userDao.selectByUid(uid);
}

性能测试实战

单机性能测试指标

指标 mysql redis+leveldb
纯insert 300tps 90000tps
用户开户业务场景 40tps 4000tps

性能调优实战

  • java不打印日志了,是否快点?(从4000到4500,提升了10%以上
  • ssdb优化(cache调大到128m和1024m,去掉ssdb的日志,单机在之前基础上到7000
  • 序列化和反序列化,拟将java本身的换成google的protobuf

参考

亿级流量网站架构核心技术作者 Redis/SSDB+Twenproxy安装和使用
SSDB作者国内博客
Twenproxy 基于redis的高可用方案
SSDB入门基础
官网

猜你喜欢

转载自blog.csdn.net/wxid2798226/article/details/82315200