KDB是Kx System开发的时间序列数据库,通常用于处理交易行情相关数据。具体介绍可以参考:https://en.wikipedia.org/wiki/Kdb%2B。
在我们的计价系统中使用kdb来存储计价数据,由于KDB是基于Q语言的,我们的计价系统是Java写的,所以使用了KDB提供的Java API。
KDB的Java实现在KDB源代码有下载。其中最核心的是c.java,我们先来看看它的实现。
c.java的使用需要通过创建一个新的c对象,以c的构造函数为例:
public C(final String h, final int p, final String u, final boolean useTLS)
throws KException, IOException {
B = new byte[2 + C.ns(u)];
s = new Socket(h, p);
if (useTLS) {
s = ((SSLSocketFactory) SSLSocketFactory.getDefault())
.createSocket(s, h, p, true);
((SSLSocket) s).startHandshake();
}
io(s);
J = 0;
w(u + "\3");
o.write(B);
if (1 != i.read(B, 0, 1)) {
close();
B = new byte[1 + C.ns(u)];
io(new Socket(h, p));
J = 0;
w(u);
o.write(B);
if (1 != i.read(B, 0, 1)) {
close();
throw new KException("access");
}
}
vt = Math.min(B[0], 3);
}
它通过参数kdb host: h,kdb port: p,kdb user&pass: u 以及是否使用安全传输: useTLS和远程kdb服务器进行通信,建立连接并且登陆,通常u是由username:password的形式传输。可以看到 通过socket给kdb传输数据。
void io(final Socket x) throws IOException {
s = x;
s.setTcpNoDelay(true);
{
final InetAddress a = s.getInetAddress();
l = a.isAnyLocalAddress() || a.isLoopbackAddress();
}
i = new DataInputStream(s.getInputStream());
o = s.getOutputStream();
s.setKeepAlive(true);
}
那么一般使用什么函数往kdb里面插入数据呢?这里有2种实现,同步(public Object k(String s) throws KException, IOException)和异步(public void ks(String s) throws IOException),同步异步还有重载方法直接写入Object对象,我们系统写入的是完整的计价数据,所以必须先自己打包成String。同步和异步的实现差别就在于同步在往Socket写入数据后会等待kdb服务器返回结果。
public void ks(final String s) throws IOException {
w(0, cs(s));
}
public synchronized Object k(final Object x) throws KException, IOException {
w(1, x);
return k();
}
public Object k(final String s) throws KException, IOException {
return k(cs(s));
}
protected void w(final int i, final Object x) throws IOException {
final int n = nx(x) + 8;
synchronized (o) {
B = new byte[n];
B[0] = 0;
B[1] = (byte) i;
J = 4;
w(n);
w(x);
if (zip && J > 2000 && !l) {
z();
}
o.write(B, 0, J);
}
}
这里有一点非常值得注意,这些方法的执行是同步的!!!在最开始我们的实现中,使用了多线程往kdb写入数据,而Connection我们只使用了一个C实例,这样意义就不是很大了。在我们想对实现做修改的时候,和kdb服务端维护人员沟通,发现kdb默认的实现就是单线程写入的,只支持多线程查询,单线程写入。所以我们改变多线程变成单线程,后面再说说相关实现细节。
single-thread which requires positive number of port
multi-thread which requires negative number of port