项目中要遍历,对Key进行处理,弄了N个方案,记录下,具体选哪个再说,呵呵
需求:TC服务中通过KEY-VALUE存储了准备删除的文件KEY和时间,需要定期全量遍历KEY,进行删除,然后清理TC对应的数据。由业务决定了删除数据的量不大,目前主要要求可靠。
1、给TT加个补丁,让其支持memcached协议访问,本人只会JAVA,困难(同时被鄙视了),网上的那个补丁说有问题...
代码:无
2、使用TC的JAVA-API直接访问TC数据问题,已测试通过,注意在TT启动的时候,打开文件时候,mode需要加HDB.ONOLCK,不然,是读取不到数据的,一直卡在哪儿(我的需要是读取KEY,所有mode使用的是:HDB.OREADER|HDB.ONOLCK),这需要部署程序到TC服务,有点不爽,而且JAVA打包也麻烦(有业务逻辑和功能基础包,都是maven依赖的,我靠,如果不人工清理,好多jar啊)。
代码:
import tokyocabinet.*;
public class TCHDBEX {
public static void main(String[] args){
// create the object
HDB hdb = new HDB();
// open the database
if(!hdb.open("/mnt/ttserver/tt_11212.tch", HDB.OREADER | HDB.ONOLCK)){
int ecode = hdb.ecode();
System.err.println("open error: " + hdb.errmsg(ecode));
}
String key;
String value;
hdb.iterinit();
while((key = hdb.iternext2()) != null){
System.out.println(key);
}
// close the database
if(!hdb.close()){
int ecode = hdb.ecode();
System.err.println("close error: " + hdb.errmsg(ecode));
}
}
}
3、使用程序在本地指定tchmgr的cli工具直接读取命令行范围的流,得到keys.比较不好的是需要部署程序到TC服务器了。问题同方案2
代码:
package com.feinno.storage.console.task.clean;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
public class LocalCliTCListKeys implements TCListKeys {
private String charset = "UTF-8";
@Override
public List<String> list(int top) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<String> list() {
String shellCommand = "tchmgr list -nl /mnt/ttserver/tt_11211.tch";
String[] cmd = { "/bin/sh", "-c", shellCommand };
BufferedReader reader = null;
List<String> keys = new ArrayList<String>();
try {
Process process = Runtime.getRuntime().exec(cmd);
reader = new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName(charset)));
String buf = null;
while ((buf = reader.readLine()) != null) {
keys.add(buf);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e2) {
// ig
}
}
}
return keys;
}
}
4、远端使用程序远程SSH执行命令,获取返回的流,得到Keys,但是,需要获得TC服务的账户,会有一定的安全问题,因为是内部系统,如果使用普通用户SUDO,其实也是可行的。
代码:
public class SSHCliTCListKeys implements TCListKeys {
private String charset = "UTF-8";
private String SSHUser = "root";
private String SSHPswd = "!QAZ2wsx";
private String SSHHost = "192.168.30.142";
private String dataFileLocalPath = "/mnt/ttserver/tt_11212.tch";
@Override
public List<String> list(int top) {
String shellCommand = "tchmgr list -nl -m " + top + " " + dataFileLocalPath;
return executeRemoteShellCommand(shellCommand);
}
@Override
public List<String> list() {
String shellCommand = "tchmgr list -nl " + dataFileLocalPath;
return executeRemoteShellCommand(shellCommand);
}
private List<String> executeRemoteShellCommand(String shellCommand) {
List<String> keys = new ArrayList<String>();
BufferedReader reader = null;
Channel channel = null;
Session session = null;
JSch jsch = new JSch();
try {
session = jsch.getSession(SSHUser, SSHHost, 22);
session.setPassword(SSHPswd);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(shellCommand);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
channel.connect();
reader = new BufferedReader(new InputStreamReader(channel.getInputStream(), Charset.forName(charset)));
String buf = null;
while ((buf = reader.readLine()) != null) {
keys.add(buf);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e2) {
// ig
}
}
channel.disconnect();
session.disconnect();
}
return keys;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public String getSSHUser() {
return SSHUser;
}
public void setSSHUser(String sSHUser) {
SSHUser = sSHUser;
}
public String getSSHPswd() {
return SSHPswd;
}
public void setSSHPswd(String sSHPswd) {
SSHPswd = sSHPswd;
}
public String getSSHHost() {
return SSHHost;
}
public void setSSHHost(String sSHHost) {
SSHHost = sSHHost;
}
public String getDataFileLocalPath() {
return dataFileLocalPath;
}
public void setDataFileLocalPath(String dataFileLocalPath) {
this.dataFileLocalPath = dataFileLocalPath;
}
}
5、在TC服务器上写个简单的Socket server,代理远端请求,在服务器上支持API或cli,返回给调用端。这个方法感觉最完美,没有安全问题,也实现了服务也业务解耦,只是,部署和维护麻烦了,多出来一个server,故障的可能性也稍微变大了些
6、另类方案,直接从业务本身出发,修改数据结,使用TT支持的memcached现有的API解决。
需要延迟删除的文件的数据结构:
key1:[{'deleteFileKey1':'yyyy-mm-dd'},..] //配置定义为:10-N个
key2:[....]
key3:[....]
key4:[....]
业务中,执行删除的时候,向使用循环遍历方式,找到空位或新插入keyN保存需要删除的fileKey
扫描遍历的逻辑(伪代码):
int i = 1;
while(memcacheClient.get("key"+i) != null){
// do busi
i++;
}
特点:程序逻辑实现和控制稍微复杂。好处是部署维护相当简单。
兄弟们,你们选哪个!?