DCache踩坑记录

2019年8月3日

DCache在4月份开源了,它是基于Tars微服务框架开发的分布式内存数据库(k-v),就赶紧拿来研究了下。经过了一段时间的验证,遇到了很多问题,在此记录一下。

注意:

本篇笔记写于2019年8月,文章中出现的问题可能已经修复,但您也可以体验一下第一批拥护者完整的采坑过程。

一、权限管理模块问题

DCache接入权限管理模块,有显示的问题:配置显示不出来。

要想在web上修改配置,必须使用 TarsWeb-dcache-alpha 版本的。

或者不接入权限管理模块。

说明:

从2.4.10版本开始,权限模块和Web已经整合了,不需要再自行安装了。

所以此问题可以忽略。

二、模块设计

在设计上, 一个module对应一张表,后端对应1个DbAcessServer。

三、连接DbAcessServer时的配置问题

module的配置,MKCacheServer.conf:(内容简略)

<Main>
        <Cache>
                ##此处内容略
                …………
        </Cache>
        BackupDayLog=dumpAndRecover
        <BinLog>
                ##此处内容略
                …………
        </BinLog>
        CoreSizeLimit=-1
        <Log>
                DbDayLog=db
        </Log>
        <DbAccess>
                DBFlag=Y
                ObjName=DCache.DbAccessServer.DbAccessObj
                ReadDbFlag=Y
        </DbAccess>
        <Record>
                MKey=sync_relation_no
                UKey=ID|NAME
                <Field>
                                                sync_relation_no = 0|long|require||0 
                        ID = 1|int|require||0 
                        NAME = 2|string|require||0 
                        SCORE = 3|int|optional|0|0 
                        SEX = 4|string|require|F|0 
                        AGE = 5|int|require||0 
                        GRADE = 6|int|require||0

                </Field>
                VKey=SCORE|SEX|AGE|GRADE
        </Record>
        MKeyMaxBlockCount=20000
        ModuleName=myAppMKVtest2
        <Router>
                ObjName=DCache.RouterServer.RouterObj
                PageSize=10000
                RouteFile=Route.dat
                SyncInterval=1
        </Router>
        RouterHeartbeatInterval=1000
</Main>

<Main>
        <Cache>
                ShmKey=22331
                ShmSize=1G
        </Cache>
</Main>

DbAcessServer的配置:

<main>
    # 1-KVCache, 2-MKVCache
    CacheType = 2
    # for KVCache, field info of backend db table.
    # <KV>
    #     KeyNameInDB=userId
    #     ValueNameInDB=userInfo
    # </KV>
    # backend db config info
    <DBInfo>
        charset = utf8
        dbname  = test
        dbhost  = 10.4.121.176
        dbport  = 3306
        dbuser  = tars
        dbpass  = tars2015
    </DBInfo>
    # table to persist cache entries
    TableName=mkv_test_2
    # db select limit
    SelectLimit=100000
</main>

当后端需要连接DbAcessServer时,需要注意:

1、配置文件中配置的字段名必须大写

因为当前版本的DbAcessServer从数据库读取字段时,给cacheServer回传的字段都是大写的;如果在创建cacheServer时配置的字段不是大写,会报错:

createEncodeStream field not found:字段名

这段检测的代码逻辑在MKCacheComm.cpp文件的createEncodeStream函数中。

主key字段除外,保证名称一致即可。

2、添加DbAcessServer

如果在已有的cache上添加DbAcessServer,在web管理平台上修改以下3项:

如果字段中有小写字母,需要将字段修改为大写(主key除外):

同时修改Main/Record/Field的配置,该配置需要在数据库中修改(web上有bug,无法实现回车换行)!

直接修改表中数据

select * from t_config_table where config_id=42275  and item_id=527

config_id为对应的cacheServer的id,在表 t_config_reference中可查到;

item_id=527 即为该项配置:

 注意:最后一行,必须有换行!

修改结束后,在web控制台上重启服务,或者reload配置。

3、主key注意事项

在k-k-row类型的cache中,mainKey是可以不唯一的!

所以在数据库设计中,该字段不能设置为primaryKey或者是唯一索引。

可以将mainKey和uKey设计成联合索引,唯一。


2019年10月

四、内存问题

1、ShmKey

服务停止或下线时,不会自动清理共享内存、信号量资源,需要人工在后台手动清理

  • CacheServer程序在启动时会根据该server下是否存在SemKey.dat文件来决定是否重新申请共享内存。因此,如需重新申请共享内存,需要清理tarsnode/data/[CacheServer]/data 目录下的SemKey.dat文件。
  • 信号量的key值与共享内存key值时一样的

2、ShmSize

  • 在创建CacheServer时,不可手动设置小于"G"的内存。
  • 服务发布后,可在“配置中心”中,修改内存大小,必须注明单位,如“50K”,“50M”,“2G”。
  • 内存大小修改后,必须后台手动清理共享资源(共享内存、信号量),删除SemKey.dat文件,然后在web页面重启服务。

3、SemKey.dat作用

在主节点异常down机时(共享内存已经被清除了);这时如果再次重启主节点,会失败,日志中报如下错误:

SemKey.dat exist, but shmget 1601 failed, errno = 2,master server assert.
MKVCacheServer: MKCacheServer.cpp:915: virtual void MKCacheServer::initialize(): Assertion `false' failed.

从节点的共享内存如果也被清理掉了,且后端未接DbAcess,重启时会报错:

SemKey.dat exist, but shmget 1602 failed, errno = 2,has no backend DB, assert.
MKVCacheServer: MKCacheServer.cpp:929: virtual void MKCacheServer::initialize(): Assertion `false' failed.

基于以上逻辑,有如下异常处理机制:

主节点异常down机,共享内存被删除时:

  •   将该cache接入DbAcess
  •   等待有用数据全部同步到db中
  •   清理主节点的SemKey.dat文件,控制台重启主节点

此时,客户端会访问主节点的数据,由于DbAcess的存在,内存中不存在的数据会从db中读取

注意:以上处理方法,需要再做斟酌。

4、pagecache 被大量占用

主机的buffer/cache被大量占用、且不释放(64G内存的主机,61G的buffer/cache)。可以按照如下处理方法:

  • echo 1 > /proc/sys/vm/drop_caches:表示清除pagecache。这一步清理了绝大部分的缓存。
  • echo 2 > /proc/sys/vm/drop_caches:表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)。slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache。
  • echo 3 > /proc/sys/vm/drop_caches:表示清除pagecache和slab分配器中的缓存对象。

五、主备切换不好使

场景:手动停止CacheServer的主节点。

Router日志:

2019-10-09 14:05:29|SwitchThread::doSwitch catch exception: [ServantProxy::invoke timeout:3000,servant:DCache.myAppMKVtest2MKVCacheServer1-1.RouterClientObj,func:helloBaby,adaptertcp -h 10.4.120
.136 -p 19046,reqid:5]
2019-10-09 14:05:32|SwitchThread::doSwitch catch exception: [ServantProxy::invoke timeout:3000,servant:DCache.myAppMKVtest2MKVCacheServer1-1.RouterClientObj,func:helloBaby,adaptertcp -h 10.4.120
.136 -p 19046,reqid:6]
2019-10-09 14:05:32|heartBeatSend to slaveName:DCache.myAppMKVtest2MKVCacheServer1-2
2019-10-09 14:05:32|SwitchThread::doSwitch send heartBeat ok  ServerName:DCache.myAppMKVtest2MKVCacheServer1-2
2019-10-09 14:05:32|heartBeatSend to slaveName  ok:DCache.myAppMKVtest2MKVCacheServer1-2
2019-10-09 14:05:32|query slaveBinlogdif from slaveName:DCache.myAppMKVtest2MKVCacheServer1-2
2019-10-09 14:05:32|SwitchThread:: slaveBinlogdif diffBinlogTime(1570590077) > 300 DCache.myAppMKVtest2MKVCacheServer1-2
2019-10-09 14:05:32|removeSwitchModule moduleName : myAppMKVtest2| switch tasks : 0

可能原因:

  1. 主从节点的时钟有问题,误差不能超过200ms。这个原因最常见。
  2. 一种保护机制,当主从节点的binlog文件超过300ms没有同步时,可能存在数据丢失的风险,因此不会触发自动切换。

从代码层面分析,该差异时间的计算,是在RouterHandle::getBinlogdif 中进行的:

difBinlogTime = g_app.gstat()->getBinlogTimeLast() - g_app.gstat()->getBinlogTimeSync();

即最后一次同步的时间点,减去当前同步的时间点。

如果这个差值大于 getSwitchBinLogDiffLimit 的值(默认300毫秒),就会报错:

SwitchThread:: slaveBinlogdif diffBinlogTime(1570590077) > 300 DCache.myAppMKVtest2MKVCacheServer1-2

为什么主从节点的时钟误差不能超过200ms?来看下binlog同步频率。

binlog的更新时间,是在BinLogTimeThread::UpdateLastBinLogTime中进行的,由BinLogThread::syncBinLog调用。其中,最后一次同步时间和当前同步时间,是调用了BinLogImp::getLog服务获得的,由DCache::BinLogRsp返回:

tars::Int32 BinLogImp::getLog(const DCache::BinLogReq &req, DCache::BinLogRsp &rsp, tars::TarsCurrentPtr current)

看了下BinLogThread的代码,同步线程100ms 执行1次,而且这个值是代码里写死的。

所以主从节点的时钟误差不能超过200ms。


总结

最后,总结下需要重点注意的几点:

1、DCache部署模块(表)时,字段名称要大写

2、服务停止或下线时,不会自动清理共享内存、信号量资源,需要人工在后台手动清理

3、要做好时钟同步(主从节点的时钟误差不能超过200ms,否则主备无法自动切换)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员柒叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值