0%

Innodb结构

索引

Innodb的索引分为聚簇索引和非聚簇索引(二级索引)。

聚簇索引是存储主键和数据本身,定位到该主键则直接检索数据而不需要额外的磁盘寻道。

非聚簇索引也就是二级索引,包含了主键以及索引,然后通过聚簇索引再去拿数据

缓冲池

Innodb使用缓冲池来存储数据变更和事务,通过数据变更保存到缓存池中的数据页中进行缓存。每次引用数据页都会放到缓存池中,发生改变后就标记为”dirty”。之后在写入磁盘中来更新数据

sql监控命令

  • show index from <table> 显示表的索引信息
  • show plugins 显示已知插件列表
  • show [full] processlist 显示系统上运行的所有线程
  • show [global | session] status 显示所有系统变量的值
  • show table status 显示数据库下表的详情,包括存储引擎、排序规则、创建信息、索引数据、行统计信息等
  • show [global | session] variables 显示系统变量

使用show命令时可以使用 like语句来进行筛选

  • show engine <engine_name> logs 显示指定存储引擎的日志信息
  • show engine <engine_name> status 显示指定存储引擎的状态信息
  • show engines 显示可用存储引擎列表
  • show binlog events [in '<log_file>'] [from <pos>] [limit [<offset>,]<row count>] 显示被记录到二进制日志的事件
  • show binary logs 显示二进制日志列表
  • show relaylog events [in '<log_file>'] [from <pos>] [limit [<offset>,]<row count>] 显示中继日志的事件
  • show master status 显示master的当前配置,当前二进制日志文件、文件的当前位置、所有排他性和包容性复制的设置
  • show slave hosts 显示连接到master的slave列表
  • show slave status 显示复制中的slave的系统状态信息

检查连接泄露

Druid连接池中有一个检查连接泄露的功能

1
2
3
4
5
6
7
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true"/>

<!-- 1800秒,也就是30分钟-->
<property name="removeAbandonedTimeout" value="180" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />

连接泄露检查,打开removeAbandoned功能,连接从连接池借出后,长时间不归还,将触发强制关闭其staement并归还。回收周期随timeBetweenEvictionRunsMillis进行,如果连接借出时间起超过removeAbandonedTimeout,则强制关闭其staement并归还。对性能会有一些影响,建议怀疑存在泄漏之后再打开,不建议在生产环境中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public int removeAbandoned() {
int removeCount = 0;

long currrentNanos = System.nanoTime();

List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>();

activeConnectionLock.lock();
try {
Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator();

for (; iter.hasNext();) {
DruidPooledConnection pooledConnection = iter.next();

if (pooledConnection.isRunning()) {
continue;
}

long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);

if (timeMillis >= removeAbandonedTimeoutMillis) {
iter.remove();
pooledConnection.setTraceEnable(false);
abandonedList.add(pooledConnection);
}
}
} finally {
activeConnectionLock.unlock();
}

if (abandonedList.size() > 0) {
for (DruidPooledConnection pooledConnection : abandonedList) {
final ReentrantLock lock = pooledConnection.lock;
lock.lock();
try {
if (pooledConnection.isDisable()) {
continue;
}
} finally {
lock.unlock();
}

JdbcUtils.close(pooledConnection);
pooledConnection.abandond();
removeAbandonedCount++;
removeCount++;

if (isLogAbandoned()) {
StringBuilder buf = new StringBuilder();
buf.append("abandon connection, owner thread: ");
buf.append(pooledConnection.getOwnerThread().getName());
buf.append(", connected at : ");
buf.append(pooledConnection.getConnectedTimeMillis());
buf.append(", open stackTrace\n");

StackTraceElement[] trace = pooledConnection.getConnectStackTrace();
for (int i = 0; i < trace.length; i++) {
buf.append("\tat ");
buf.append(trace[i].toString());
buf.append("\n");
}

buf.append("ownerThread current state is " + pooledConnection.getOwnerThread().getState()
+ ", current stackTrace\n");
trace = pooledConnection.getOwnerThread().getStackTrace();
for (int i = 0; i < trace.length; i++) {
buf.append("\tat ");
buf.append(trace[i].toString());
buf.append("\n");
}

LOG.error(buf.toString());
}
}
}

return removeCount;
}

页面实时获取数据

在当今数字化交互日益频繁的时代,前端开发面临着诸多挑战,其中任务执行耗时久以及如何实时获取数据便是极为常见且棘手的问题。想象一下,当用户在网页上触发某个操作,比如提交一份复杂的表单申请、查询海量数据的检索结果,又或是等待一个长时间运行的后台任务反馈,他们往往被迫陷入漫长的等待之中,盯着屏幕发呆,期望着那个迟迟未到的回应。而这背后,正是前端实时获取数据的困境在作祟。

如何使得后端数据可以实时推送到前端呢?下面介绍几种方案

方案一:轮询

这是最容易理解的一种方式。前端实现一个定时器,让客户端每隔较短固定时间就向服务端发起请求,服务器判断任务还没跑完,就回复一个未跑完,定时器一直到服务器回复任务完成并把数据返回回来。

短轮询的优劣势一目了然。优势在于,容易理解、实现过程简便,同时兼容性又很好,在几乎所有支持 HTTP 协议的浏览器及服务器环境都能很好的运行短轮询。不过,缺点也非常显而易见。当按照很短的固定时间间隔去频繁请求数据,如果此时的数据并未更新,这些请求就成了无效请求,但是每一个无效的请求都得完成 HTTP 建立连接的一系列流程,像三次握手四次挥手 ,这无疑造成了不必要的资源浪费。同时也是由于按固定间隔请求,数据更新也可能会存在延迟的现象,在要求实时性的场景下就不满足了。

方案二:WebSocket

阅读全文 »

路径监听

在java NIO中提供了一个路径监听器WatchService,可以用来监听目录中的更改

我这里有个示例,是用来监听目录下的新建文件/文件夹的事件的,有没有zookeeper的事件监听的感觉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Watch {
public static void main(String[] args) throws IOException, InterruptedException {
// 监听器
WatchService watchService = FileSystems.getDefault().newWatchService();

Path path = Paths.get("/Users/zhanghe/Desktop");
// 监听创建事件
path.register(watchService,ENTRY_CREATE);
// 会进行阻塞
WatchKey take = watchService.take();

for(WatchEvent event : take.pollEvents()){
System.out.println("evt.context(): " + event.context() +
" evt.count(): " + event.count() +
" evt.kind(): " + event.kind());
}
}
}