王某某的笔记

记录我的编程之路

相关说明:

eth0是一块物理网卡。eth0.1 eth0.2都是从此设备上虚拟出来的
eth0.1 是vlan1分出的lan口
eth0.2 是vlan分出的wan口

方法一:配置新接口

配置接口

vi /etc/config/network

增加一个接口,这里取名为gm,ip地址要与光猫在一个网段

1
2
3
4
5
6
config interface 'gm'
option ifname 'eth0.2'
option proto 'static'
option netmask '255.255.255.0'
option ipaddr '192.168.1.100'
option gateway '192.168.1.1'

重启网络 /etc/init.d/network restart

配置防火墙

vi /etc/config/firewall

修改 wan 域,加上上面定义的接口 gm

option network ‘wan’ 修改为 option network ‘wan gm’

1
2
3
4
5
6
7
8
config zone
option name 'wan'
option network 'wan gm'
option input 'REJECT'
option output 'ACCEPT'
option forward 'REJECT'
option masq '1'
option mtu_fix '1'

重启防护墙 /etc/init.d/firewall restart

访问即可

路由表无需配置,默认有一条

1
2
3
4
5
6
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0.2
......
......

方法二:配置双IP

使用命令的方式,重启会丢失配置

这个需要重新验证,之前是怎么测试的忘记了。。。。

1
2
ifconfig eth0.2:0 192.168.1.100 netmask 255.255.255.0
iptables -t nat -I POSTROUTING -o eth0.2 -d 192.168.1.0/24 -j MASQUERADE

-I 在头部插入规则
-o 匹配出口网卡流出的数据
-d 匹配目的地址
-j 要进行的处理动作 MASQUERADE 改写封包来源 IP 为防火墙 NIC IP,与 SNAT 略有不同,当进行IP伪装时,不需指定要伪装成哪个IP,IP会从网卡直接读取,适用于动态获取IP的情况

关闭

1
2
ifconfig eth0.2:0 down

问题解决

出现问题请尝试重启

重启网络命令

1
/etc/init.d/network reload

重启路由器

1
reboot

在 Linux 系统中,文件或目录的权限通常用字符 rwx 来表示,同时也可以用数字来表示,比如 755 。

权限说明

rwx 分别代表读(Read)、写(Write)、执行(Execute)权限:

  • r 表示可读权限,允许读取文件的内容或列出目录中的文件。
  • w 表示可写权限,允许修改文件的内容或在目录中创建、删除、重命名文件。
  • x 表示可执行权限,对于文件,允许执行该文件;对于目录,允许进入该目录。

每个权限位可以用数字来表示:

  • r 对应数字 4
  • w 对应数字 2
  • x 对应数字 1

那么三位数字就分别对应了文件 所有者(User)、所属组(Group)和 其他用户(Other)的权限。


例子

例如,权限 755 可以这样解读:

  • 第一位数字 7 表示所有者的权限,是 4 + 2 + 1 ,即所有者具有读、写和执行的权限。
  • 第二位数字 5 表示所属组的权限,是 4 + 1 ,即所属组具有读和执行的权限。
  • 第三位数字 5 表示其他用户的权限,同样是 4 + 1 ,即其他用户具有读和执行的权限。

再举几个例子:

  • 权限 644 :所有者具有读和写的权限(4 + 2 = 6),所属组和其他用户都只有读的权限(4)。
  • 权限 700 :所有者具有所有权限,所属组和其他用户没有任何权限。

通过这种数字表示权限的方式,可以更简洁和方便地设置和理解文件或目录的权限。


命令

chmod 命令用于更改文件或目录的权限。

语法:

1
chmod [选项] 权限模式 文件名/目录名

常用选项:

  • -R :递归地更改目录及其子目录和文件的权限。

权限模式:

可以使用数字表示法(如前面提到的 755 ),也可以使用字符表示法(如 rwxr-xr-x )。

权限模式中的用户类型

  • u 表示所有者(User)
  • g 表示所属组(Group)
  • o 表示其他用户(Other)
  • a 表示表所有用户(All)

示例

下面这两个命令是一样的效果,

1
2
chmod 755 file 
chmod rwxr-xr-x file

为文件 file.sh 的所有者添加执行权限

1
chmod u+x file.sh

去掉目录 dir 所属组(Group)的写权限

1
chmod g-w dir 

为文件 file 的其他用户(Other)添加读权限

1
chmod o+r file

为所有用户添加读权限

1
chmod a+r file.txt

Top程序提供了一个运行系统的动态实时视图。它可以显示系统摘要信息以及当前由Linux内核管理的进程或线程列表。 所显示的系统摘要信息的类型以及为进程显示的信息的类型,顺序和大小都是用户可配置的,并且配置可以在重新启动时保持不变。
该程序为过程操作提供了一个有限的交互式界面,以及一个用于个人配置的更广泛的界面 - 涵盖了其操作的每个方面。

一、显示区域介绍

系统信息栏

第一行(TOP)

1
top - 14:28:52 up 39 days, 20:56,  1 user,  load average: 0.20, 0.42, 0.52
  • 系统当前时间
  • 系统已经运行时间
  • 登录当前系统的终端数
  • load average 为当前系统负载的平均值,后面的三个值分别为1分钟前、5分钟前、15分钟前进程的平均数

    平均负载(load average)是指系统的运行队列的平均利用率,也可以认为是可运行进程的平均数。
    多核CPU的话,满负荷状态的数字为 “1.00 * CPU核数”,即双核CPU为2.00,四核CPU为4.00。

第二行(Tasks)

1
Tasks: 236 total,   2 running, 234 sleeping,   0 stopped,   0 zombie

当前系统的进程情况

字段 含义
total 为当前系统进程总数
running 为当前运行中的进程数
sleeping 为当前处于等待状态中的进程数
stoped 为被停止的系统进程数
zombie 为被复原的进程数

第三行(Cpus)

1
%Cpu(s):  2.9 us,  1.4 sy,  0.0 ni, 95.1 id,  0.5 wa,  0.0 hi,  0.1 si,  0.0 st

分别表示了 CPU 当前的使用率

字段 含义
us 用户空间占用CPU百分比
sy 内核空间占用CPU百分比
ni 用户进程空间内改变过优先级的进程占用CPU百分比
id 空闲CPU百分比
wa 等待输入输出的CPU时间百分比
hi 硬件中断
si 软件中断
st 实时

第四行(Mem)

1
GiB Mem :   62.645 total,    4.274 free,   22.042 used,   36.329 buff/cache

分别表示了内存总量、空闲内存量、当前使用量、以及缓冲使用中的内存量

第五行(Swap)

1
GiB Swap:   64.000 total,   63.203 free,    0.797 used.   39.949 avail Mem

表示类别同第四行(Mem),但此处反映着交换分区(Swap)的使用情况。通常,交换分区(Swap)被频繁使用的情况,将被视作物理内存不足而造成的。

进程列表栏

1
2
3
4
5
 PID USER       PR   NI   VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
23090 root 20 0 9.793g 818716 7460 S 14.6 1.2 1971:30 java
3617 root 20 0 20.274g 220676 7468 S 12.6 0.3 10874:44 java
23496 root 20 0 9.780g 444548 7524 S 8.3 0.7 1228:19 java
2648 elastic+ 20 0 50.123g 1.527g 7612 S 7.3 2.4 662:56.49 java
列名 含义
PID 进程id
PPID 父进程id
RUSER Real user name
UID 进程所有者的用户id
USER 进程所有者的用户名
GROUP 进程所有者的组名
TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?
PR 优先级
NI nice值。负值表示高优先级,正值表示低优先级
P 最后使用的CPU,仅在多CPU环境下有意义
%CPU 上次更新到现在的CPU时间占用百分比
TIME 进程使用的CPU时间总计,单位秒
TIME+ 进程使用的CPU时间总计,单位1/100秒
%MEM 进程使用的物理内存百分比
VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
SWAP 进程使用的虚拟内存中,被换出的大小,单位kb。
RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
CODE 可执行代码占用的物理内存大小,单位kb
DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb
SHR 共享内存大小,单位kb
nFLT 页面错误次数
nDRT 最后一次写入到现在,被修改过的页面数。
S 进程状态。
D=不可中断的睡眠状态
R=运行
S=睡眠
T=跟踪/停止
Z=僵尸进程
COMMAND 命令名/命令行
WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名
Flags 任务标志,参考 sched.h

默认情况下仅显示比较重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 列。

可以使用快捷键 f 更改显示内容

有时候进程的cpu使用率可能大于100,那是因为该进程启用了多线程占用了多个核心,所以有时候该值得时候会超过100%,但不会超过总核数*100。


二、命令介绍

命令行

详细内容可以参考MAN 帮助文档。

命令格式:

top [-] [d] [p] [q] [c] [C] [S] [n]

参数说明:

d: 指定每两次屏幕信息刷新之间的时间间隔。当然用户可以使用s交互命令来改变之。

p: 通过指定监控进程ID来仅仅监控某个进程的状态。

q:该选项将使top没有任何延迟的进行刷新。如果调用程序有超级用户权限,那么top将以尽可能高的优先级运行。

S: 指定累计模式

s : 使top命令在安全模式中运行。这将去除交互命令所带来的潜在危险。

i: 使top不显示任何闲置或者僵死进程。

c: 显示整个命令行而不只是显示命令名

交互式命令

1 显示所有的CPU核心的使用率

d/s 改变刷新平率

l - 关闭或开启第一部分第一行 top 信息的表示

t - 关闭或开启第一部分第二行 Tasks 和第三行 Cpus 信息的表示

m - 关闭或开启第一部分第四行 Mem 和 第五行 Swap 信息的表示

N - 以 PID 的大小的顺序排列表示进程列表

P - 以 CPU 占用率大小的顺序排列进程列表

M - 以内存占用率大小的顺序排列进程列表

h - 显示帮助

n - 设置在进程列表所显示进程的数量

q - 退出 top

c - 显示进程的命令名称或命令行

Z - 改变颜色映射

z - 显示或关闭颜色

B - 开启/关闭加粗显示

b - 高亮显示排序字段

f - 显示和隐藏字段

F/O - 控制排序的字段

< / > - 控制排序的字段

R - 升序排列或倒序排列

x - 高亮显示排序字段

H - 显示线程

u - 仅显示指定的用户

Lambda表达式

java 8 的新特性,是一种语法糖,简化了只有一个方法的匿名内部类的编写,让编码更方便,代码更简洁。

只有一个方法的接口(又叫函数式接口)在写匿名内部类时看起来很啰嗦,真正有用的只是方法实现中的那一段代码。通常情况下我们使用匿名内部类是想将功能作为参数传递给另外的方法,例如点击按钮时应该采取的措施。Lambda表达式使我们能够执行此操作,将功能视为方法参数,或将代码视为数据。

个人理解:主要作用是为了更方便的创建 函数接口 的匿名内部类的实例,减少啰嗦的代码。

基本语法

主要是加了箭头符号 ‘->’ 称为Lambda操作符或箭头操作符

1
(参数) -> {函数体}

左边是参数,中间是箭头符号,右边是方法体

这里以jdk内置Consumer 函数式接口示例:

原来的匿名内部类写法

1
2
3
4
5
6
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String str) {
System.out.println("msg=" + str);
}
};

新的Lambda表达式写法

1
2
3
Consumer<String> c1 = (String str) -> {
System.out.println("msg=" + str);
};

可以看到代码简洁了很多

再比Runnable是一个函数接口,创建线程可以这样写

1
2
3
4
5
Thread t = new Thread(() -> {
System.out.print("Lambda!");
System.out.print("Do Something...");
});
t.run();

更简化的写法

参数可以声明类型,也可以根据类型推断而省略

如上面的c1可以省略参数类型String

1
2
3
Consumer<String> c1 = (str) -> {
System.out.println("msg=" + str);
};

但是如果有两个参数不能只写一个参数的类型,要么都写类型,要么都不写类型

只有一个参数时可以省略参数的小括号
1
2
3
Consumer<String> c2 = str -> {
System.out.println("msg=" + str);
};
方法体只有一条语句时花括号和语句的分号都可以省略
1
Consumer<String> c3 = str -> System.out.println(str);
只有一条返回语句时return可以不写

如返回一个String

1
2
3
Supplier<String> s1 = () -> {
return "Lambad!";
};

可以写成

1
Supplier<String> s2 = () -> "Lambad!";

返回对象可以写成

1
Supplier<User> s3 = () -> new User("张三", 20);
使用方法引用时参数和箭头符号都可以省略

前提是:接口定义的参数 和 方法的参数匹配

如:

1
Consumer<String> c4 = System.out::println;

accept.accept(String t) 的参数与 System.out.println(String x)的参数匹配

构造器引用

1
Supplier<User> s4 = User::new;

静态方法引用
User对象中有一个叫getInstance的静态方法

1
Supplier<User> s5 = User::getInstance;

多参数+返回
传入两个int值返回较大的一个

1
2
3
BiFunction<Integer, Integer, Integer> bf = (x, y) -> x > y ? x : y;
# 可以写成
BiFunction<Integer, Integer, Integer> bf1 = Math::max;

原则就是让编译器能识别,不产生歧义!

Lambda表达式序列化问题

一个Lambda能否序列化, 要以它捕获的参数以及target type能否序列化为准。lambda表达式是可以序列化的,但是就像内部类一样,强烈建议不要对lambda表达式进行序列化。

ps:经测试 使用方法引用时不能序列化

反对序列化内部类(包括局部类和匿名类)。当Java编译器编译某些构造时,比如内部类,它会创建合成构造;这些是在源代码中没有相应构造的类、方法、字段和其他构造。合成构造使Java编译器能够在不更改JVM的情况下实现新的Java语言特性。然而,合成构造可能因不同的Java编译器实现而不同,这意味着.class文件也可能因不同的实现而不同。因此,如果您序列化一个内部类,然后用不同的JRE实现反序列化它,您可能会有兼容性问题。有关编译内部类时生成的合成构造的更多信息,请参阅获取方法参数名称一节中的隐式和合成参数一节。



接口默认方法和静态方法

从Java 8 开始,接口中引入了 缺省方法(default method) 和 静态方法 (static method) 的特性。

注意:接口中的方法修饰符号只能是 { 抽象、默认、静态 } 中的一种

默认方法

默认方法就是接口可以有实现方法,不需要实现类主动去实现默认会自动继承,当接口中的默认方法不满足要求时实现类可以对其进行重写,调用时重写的方法优先于默认方法被调用。

默认方法用default关键字修饰,默认是public权限

添加此功能是为了实现向后兼容,默认方法不会破坏原有的接口实现还便于给程序添加新特性。比如某一天我们需要给线上某个接口增加一个方法,在 Java 8 之前,我们需要去改每一个实现类,就算这个实现根本用不到这个功能也得加一个空实现,否则编译不了,改动起来非常麻烦。Java 8 之后就只需要在接口上增加一个默认方法就可以了。

java不支持多继承但是可以实现多个接口,有了默认方法之后我们可以将方法的相关逻辑写到接口中这样也能解决部分多继承的问题。

继承特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface A {
// 默认方法
default void say() {
System.out.println("hello");
}
}

class C1 implements A {

}

public static void main(String[] args) {
C1 c1 = new C1();
// 自动继承
c1.say();
}

输出:

1
hello
子类方法优先

C1重写say方法

1
2
3
4
5
6
class C1 implements A {
@Override
public void say() {
System.out.println("C1 hello");
}
}

输出:

1
C1 hello

子类的子类会优先继承父类的方法,父类没有重写时才会使用接口中的方法

C2类继承C1类

1
2
3
4
5
6
7
8
class C2 extends C1{

}

public static void main(String[] args) {
C2 c2 = new C2();
c2.say();
}

输出:

1
C1 hello
实现多个接口中有相同的方法时需指定

如子类实现两个接口,两个接口中有相同的方法(参数和方法名相同),实现类需要重写该,否则编译器不知道该调用哪一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface A {
default void say() {
System.out.println("[interface A] say hello");
}
}

interface B {
default void say() {
System.out.println("[interface B] say hello");
}
}

class C1 implements A, B {
@Override
public void say() {
System.out.println("需要重写say方法,否则编译器不知道是调用 A.say 还是 B.say");
}
}
显示引用接口的默认实现

通过使用super,可以显式的引用被继承接口的默认实现,语法如下:InterfaceName.super.methodName()

1
2
3
4
5
6
class C1 implements A, B {
@Override
public void say() {
A.super.say();
}
}

输出:

1
[interface A] say hello

静态方法

接口中的静态方法和类中定义的静态方法一样,不属于特定对象,所以它们不是实现接口的api的一部分,必须使用InterfaceName.staticMethod来调用它们。

接口中的所有方法声明(包括静态方法)都是隐式的public,因此可以省略public修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface A {
static String STR = "静态字段可以被继承";
static void sayA() {
System.out.println("static sayA");
}
}

class C1 implements A {
}

//main
public static void main(String[] args) {
// 通过接口名称调用接口的静态方法
A.sayA();

// 不能通过子类实例调用 new C1().sayA()
// 也不能通过子类调用 C1.sayA()

//可以通过子类实例获取静态字段值
System.out.println(new C1().STR);
}

实现接口的类或者子接口不会继承接口中的静态方法,只能是静态方法所属的接口来调用。但是接口中静态字段可以被继承(默认用public static final修饰)。

在java8中很多接口中都使用默认方法和静态方法进行了增强,如:Comparator,接口静态方法适合于提供实用方法,例如空检查、集合排序等。



函数式接口

只有一个抽象方法的接口

可以有多个默认方法或者静态方法等

接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object类中的public方法,那么 也不算抽象方法,因为任何接口的实现都会从其父类Object或其它地方获得这些方法的实现。

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@FunctionalInterface
public interface FunctionalInterfaceT1<T> {

// 抽象方法
void doSomething(T t);

// Object类中的方法
boolean equals(Object obj);

// 默认方法
default void printT(T t) {
System.out.println(t);
}

// 默认方法2
default void printT2(T t) {
System.out.println(t);
}

// 静态方法
public static void print() {
System.out.println("FunctionalInterfaceT1.print");
}
}

@FunctionalInterface 注解

该注解不是必须的,如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。

默认方法不能覆盖Object中的方法

接口不能实现Object的toString、equals、hashCode等方法,因为接口多继承如果多个接口都实现了equals方法会不知道调用哪一个

编译过不了

内置的核心函数式接口

java8中内置的函数式接口位于包:java.util.function

4大常用的函数式接口

Consumer

消费型 接口

方法:void accept(T t)
用来消费 T 类型的对象

Supplier

供给型 接口

方法: T get()
提供 T 类型的对象

Function<T,R>

函数型 接口

方法: R apply(T t)
对类型为 T 的对象进行操作返回 R 类型的对象

Predicate

断言型 接口

方法: boolean test(T t)
判断 T 类型的对象是否满足某些约束

其他类型的函数式接口

也都在 java.util.function 包下,大体上都差不多,记住上面常用的4个就行了

BiFunction<T, U, R>

参数为 T,U,返回值为 R
方法为 R apply(T t, U u)

UnaryOperator (Function子接口)

参数为 T,对参数为T的对象进行一元操作,并返回T类型结果
方法为 T apply(T t)

BinaryOperator (BiFunction子接口)

参数为T,对参数为T得对象进行二元操作,并返回T类型得结果
方法为 T apply(T t1, T t2)

BiConsumer(T, U)

参数为 T,U 无返回值
方法为 void accept(T t, U u)

BiPredicate<T, U>

参数为 T,U 返回boolean值
方法为: boolean test(T t, U u)

ToIntFunction、ToLongFunction、ToDoubleFunction

参数类型为T,返回值分别为int,long,double
分别计算int,long,double的函数
方法为:int applyAsInt(T value);long applyAsLong(T t, U u)

IntFunction、LongFunction、DoubleFunction

参数分别为int,long,double,返回值为R。
方法为: R apply(int value); R apply(long value);



方法引用

方法引用是一个新特性,方法类似指针一样可以被直接引用。
新的操作符”::”(两个冒号)用来引用 或者 实例 的方法。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

静态方法引用

1
2
BiFunction<Integer, Integer, Integer> bf = Math::max;
System.out.println(bf.apply(1, 3));

实例方法引用

1
2
Consumer<String> c = System.out::println;
c.accept("hello");

任意实例引用

1
2
3
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
Arrays.stream(stringArray).forEach(System.out::println);

可以引用任意的一个类型的实例。等价的lambda表达式的参数列表为(String a, String b),方法引用会调用a.compareToIgnoreCase(b)。

构造函数引用

1
Supplier<User> s = User::new;

对构造函数的引用类似对静态方法的引用,只不过方法名是new。 一个类有多个构造函数, 会根据target type选择最合适的构造函数。

电脑连接小爱音箱后 无法通过电脑调节音箱的音量

系统:win10
版本:18362

Win+R –> regedit 打开注册表编辑器

找到下面的key

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Bluetooth\Audio\AVRCP\CT

DisableAbsoluteVolume 数值改成 1

十六进制值

Elasticsearch分片包含一个Lucene索引,因此我们可以使用Lucene的CheckIndex工具,该工具使我们能够扫描并修复有问题的片段,而且通常只会造成最小的数据丢失。

Lucene CheckIndex工具包含在默认的Elasticsearch发行版中,不需要额外的下载。

1
2
3
4
5
# change this to reflect your shard path, the format is
# {path.data}/{cluster_name}/nodes/{node_id}/indices/{index_name}/{shard_id}/index/

$ export SHARD_PATH=data/elasticsearch/nodes/0/indices/foo/0/index/
$ java -cp lib/elasticsearch-*.jar:lib/*:lib/sigar/* -ea:org.apache.lucene... org.apache.lucene.index.CheckIndex $SHARD_PATH

如果CheckIndex检测到问题并且其修复建议看起来很明智,则可以通过添加-fix命令行参数来告诉CheckIndex应用修补程序。

实际是用 -exorcise 命令


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
 java -cp lib/elasticsearch-*.jar:lib/*:lib/sigar/* -ea:org.apache.lucene... org.apache.lucene.index.CheckIndex

ERROR: index path not specified
Usage: java org.apache.lucene.index.CheckIndex pathToIndex [-exorcise] [-crossCheckTermVectors] [-segment X] [-segment Y] [-dir-impl X]

-exorcise: actually write a new segments_N file, removing any problematic segments
-fast: just verify file checksums, omitting logical integrity checks
-crossCheckTermVectors: verifies that term vectors match postings; THIS IS VERY SLOW!
-codec X: when exorcising, codec to write the new segments_N file with
-verbose: print additional details
-segment X: only check the specified segments. This can be specified multiple
times, to check more than one segment, eg '-segment _2 -segment _a'.
You can't use this with the -exorcise option
-dir-impl X: use a specific FSDirectory implementation. If no package is specified the org.apache.lucene.store package will be used.

**WARNING**: -exorcise *LOSES DATA*. This should only be used on an emergency basis as it will cause
documents (perhaps many) to be permanently removed from the index. Always make
a backup copy of your index before running this! Do not run this tool on an index
that is actively being written to. You have been warned!

Run without -exorcise, this tool will open the index, report version information
and report any exceptions it hits and what action it would take if -exorcise were
specified. With -exorcise, this tool will remove any segments that have issues and
write a new segments_N file. This means all documents contained in the affected
segments will be removed.

This tool exits with exit code 1 if the index cannot be opened or has any
corruption, else 0.

修复

当出现分片损坏时,应该是分片中的某些 segment 出问题了。

解决办法是删掉这些 segment 用新的代替,但是这些segment中保存的数据会丢失。

处理步骤:

  1. 关闭ES

  2. 执行

    1
    2
    $ export SHARD_PATH=data/elasticsearch/nodes/0/indices/foo/0/index/
    $ java -cp lib/elasticsearch-*.jar:lib/*:lib/sigar/* -ea:org.apache.lucene... org.apache.lucene.index.CheckIndex $SHARD_PATH

    会提示有几个坏的segment,会丢失多少数据

  3. 使用 -exorcise命令进行数据恢复

1
$ java -cp lib/elasticsearch-*.jar:lib/*:lib/sigar/* -ea:org.apache.lucene... org.apache.lucene.index.CheckIndex $SHARD_PATH -exorcise
  1. 完了启动es即可,只是会丢失上面所说的X条数据

当前在xxx分支上,然后执行rebase命令 master分支

1
git rebase master

可以理解为将xxx分支上的改动抽出来弄成一坨,然后将master分支的代码弄到xxx分支这边来,然后再将刚刚弄出来的代码堆上去,就像这一坨代码是接在master分支的末尾上写的一样,这样你再回到master将这一堆代码merge过来,提交日志就不会分叉,看提交日志就特别清晰明了。

如果这一坨代码中有多个提交,不想要这么多的提交记录,就要加一个-i参数

1
git rebase -i B 

就会让你挑选你想要的提交


……
不想写了
……


从master 检出 dev,然后分别修改 master 和 dev,然后 合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
git init

vi aaa.txt

git checkout -b dev

vi bbb.txt

git add .

git commit

git checkout master

vi aaa.txt

git add .

git commit

git checkout dev

git merge master

会导致提交日志里面出现分叉的merge信息,比较难看

1
2
3
4
5
6
7
8
$ git log --graph --pretty=oneline
* baba7341616a7fd6e6932bf76a90fca9782a8e54 (HEAD -> dev) Merge branch 'master' into dev
|\
| * 3c408871ffcc5cfc37a295ecf936a23aff808c68 (master) master modified aaa.txt
* | a9dc6221ce4b152b292cbcd4e242026edbb7d379 dev branch add bbb.txt file
|/
* 171e52a8cd9c96706cb0112013d556b62932ee39 first commit

使用 rebase 后

1
$ git rebase master
1
2
3
4
5
$ git log --oneline --graph
* 6879874 (HEAD -> dev) dev branch add bbb.txt file
* 3c40887 (master) master modified aaa.txt
* 171e52a first commit

在 rebase 的过程中,也许会出现冲突 conflict 。在这种情况, git 会停止 rebase 并会让你去解决冲突。在解决完冲突后,用 git add 命令去更新这些内容。

注意,你无需执行 git-commit,只要执行 continue

1
git rebase --continue

这样 git 会继续应用余下的 patch 补丁文件。

在任何时候,我们都可以用 –abort 参数来终止 rebase 的行动,并且分支会回到 rebase 开始前的状态。

1
git rebase —abort

切回master分支,并进行合并

1
2
3
4
5
6
$ git checkout master

$ git merge dev

$ git log --oneline --graph



rebase有冲突时

处理完冲突后,添加文件到暂存区

1
git add/rm <conflicted_files>

然后再继续

1
git rebase --continue

也可以跳过这次提交

1
git rebase --skip

要中止并回到“git rebase”之前的状态,请运行

1
2
git rebase --abort

在window平台安装了git之后,想模拟从远程仓库拉取文件推送文件等,测试merge、rebase等

创建本地git仓库

随便找一个目录作为 repository

在gitBash 中执行 初始化git仓库的命令,顺便也可以加一个文件

1
2
3
4
5
6
7
git init

vim aaa.txt

git add .

git commit -m "add a file"

将仓库中克隆到本地其他目录

在其他的目录中执行 git clone file:xxxx

1
git clone file file:///d/test/repository/git1/.git/

修改文件之后,push到仓库中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
git pull

git checkout -b dev

vim bbb.txt

git add .

git commit

git push

# 需要指定远程的分支
git push --set-upstream origin dev

当不能push时,

切换到master分支,推一个文件

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
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 297 bytes | 297.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: error: refusing to update checked out branch: refs/heads/dev
remote: error: By default, updating the current branch in a non-bare repository
remote: is denied, because it will make the index and work tree inconsistent
remote: with what you pushed, and will require 'git reset --hard' to match
remote: the work tree to HEAD.
remote:
remote: You can set the 'receive.denyCurrentBranch' configuration variable
remote: to 'ignore' or 'warn' in the remote repository to allow pushing into
remote: its current branch; however, this is not recommended unless you
remote: arranged to update its work tree to match what you pushed in some
remote: other way.
remote:
remote: To squelch this message and still keep the default behaviour, set
remote: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To file:///d/test/repository/git1/.git/
! [remote rejected] dev -> dev (branch is currently checked out)
error: failed to push some refs to 'file:///d/test/repository/git1/.git/'

这是由于git默认拒绝了push操作,需要进行设置,可以在服务器(就是本机)执行

1
$ git config receive.denyCurrentBranch ignore

数据库版本

使用 SELECT 语句

1
2
3
4
5
6
7
mysql> SELECT VERSION();
+------------+
| VERSION() |
+------------+
| 5.6.41-log |
+------------+
1 row in set (0.09 sec)

使用 SHOW VARIABLES

1
2
3
4
5
6
7
mysql> SHOW VARIABLES LIKE 'version';
+---------------+------------+
| Variable_name | Value |
+---------------+------------+
| version | 5.6.41-log |
+---------------+------------+
1 row in set (0.14 sec)

查看事务隔离级别

查看当前会话的事务隔离级别

1
2
3
4
5
6
7
mysql> SELECT @@SESSION.tx_isolation;
+------------------------+
| @@SESSION.tx_isolation |
+------------------------+
| READ-COMMITTED |
+------------------------+
1 row in set (0.07 sec)

读已提交 READ-COMMITTED

查看全局事务隔离级别

1
2
3
4
5
6
7
mysql> SELECT @@GLOBAL.tx_isolation;
+-----------------------+
| @@GLOBAL.tx_isolation |
+-----------------------+
| READ-COMMITTED |
+-----------------------+
1 row in set (0.06 sec)

使用 SHOW VARIABLES

1
2
3
4
5
6
7
mysql> SHOW VARIABLES LIKE 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.08 sec)

使用事务

1
2
3
4
5
6
7
8
9
10
# 开启事务
START TRANSACTION;

# 执行操作A...
# 执行操作B...

# 提交或回滚事务
COMMIT;
ROLLBACK;

查看事务

1
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

这条查询语句将返回一个表,显示所有当前活动的事务的信息,例如:

  • trx_id:事务 ID。
  • trx_state:事务状态(如 RUNNING、LOCK WAIT 等)。
  • trx_started:事务开始的时间。
  • trx_requested_lock_id:如果事务在等待锁定,则显示请求的锁定 ID。
  • trx_wait_started:如果事务在等待锁定,则显示等待开始的时间。
  • trx_mysql_thread_id:执行事务的 MySQL 线程 ID。

查看一个事务运行了多长时间:

1
SELECT TIMESTAMPDIFF(SECOND, t.trx_started, NOW()) AS trx_runtime_seconds,t.* FROM information_schema.INNODB_TRX t;

查看 INNODB_TRX 表的锁等待状态

INNODB_TRX 表包含当前正在执行的事务信息,通过它可以查看是否有事务处于等待锁的状态。

1
2
3
4
5
6
7
8
9
10
11
SELECT 
trx_id,
trx_state,
trx_started,
trx_wait_started,
TIMESTAMPDIFF(SECOND, trx_wait_started, NOW()) AS wait_time_seconds,
trx_requested_lock_id
FROM
INFORMATION_SCHEMA.INNODB_TRX
WHERE
trx_state = 'LOCK WAIT';
  • trx_state = ‘LOCK WAIT’ 表示正在等待锁的事务。
  • wait_time_seconds 显示事务等待锁的时间。

如果有长时间等待锁的事务,可以怀疑存在潜在的死锁。


手动制造一个死锁

现在有一个表 test,有Id 和 v 两个字段,里面有两条数据 1,1;2,2

确保wait_timeout 时间足够长

步骤:

  1. 在第一个会话中,开始一个事务并锁定记录 id=1
    1
    2
    START TRANSACTION;
    UPDATE test SET v = 11 WHERE id = 1;
  2. 在第二个会话中,开始另一个事务并锁定记录 id=2:
    1
    2
    START TRANSACTION;
    UPDATE test SET v = 22 WHERE id = 2;
  3. 回到第一个会话,尝试更新记录 id=2(此时这个记录已被第二个事务锁定,导致第一个事务无法继续):
    1
    UPDATE test SET value = 12 WHERE id = 2;
  4. 回到第二个会话,尝试更新记录 id=1(此时这个记录已被第一个事务锁定,导致第二个事务无法继续):
    1
    2
    UPDATE test SET v = 21 WHERE id = 1;

    此时会报错,Mysql会检测到一个死锁错误:
1
1213 - Deadlock found when trying to get lock; try restarting transaction

MySQL 会自动检测到这个死锁,并回滚其中一个事务(通常是后发起的事务),这是 MySQL 中的一个重要特性,它能有效地避免数据库的无限期阻塞。


查当前正在运行的 MySQL 线程

使用 SHOW PROCESSLIST

SHOW PROCESSLIST 命令用于显示当前 MySQL 服务器中所有连接的信息。默认情况下,它会显示所有会话的状态,包括线程 ID、用户、主机、数据库、命令、时间、状态和查询等信息。

1
2
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;

在 MySQL 5.6 及更高版本中,你可以使用 SHOW FULL PROCESSLIST 获取更详细的信息

使用 INFORMATION_SCHEMA.PROCESSLIST 视图

通过查询 INFORMATION_SCHEMA.PROCESSLIST 视图来实现更灵活的过滤

1
2
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE DB = 'test';

示例
显示所有运行时间超过 60 秒的查询:

1
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE TIME > 60;

显示所有正在等待锁的查询:

1
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%lock%';

只显示特定用户的会话:

1
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'your_user';

显示所有非空闲会话:

1
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND != 'Sleep';

Kill 命令

KILL 命令用于终止指定会话(连接)或线程。它可以强制关闭一个正在运行的会话或终止一个特定的查询。KILL 命令对于管理数据库的并发访问和处理意外情况(如死锁、长时间运行的查询或网络中断导致的挂起事务)非常有用。

KILL 命令的作用

  1. 终止指定的会话:当你执行 KILL 时,MySQL 会终止与该线程 ID 关联的会话。这意味着 MySQL 会关闭这个会话连接并释放它所持有的所有资源(例如锁、内存等)。
  2. 中断当前执行的查询:KILL 命令还可以用于中断一个正在执行的查询。如果一个查询运行时间过长或者出现了性能问题,使用 KILL 可以立即停止该查询。

KILL 命令的使用语法

1
KILL [CONNECTION | QUERY] thread_id;
  • KILL thread_id:默认操作是 KILL CONNECTION,它终止与给定线程 ID 关联的会话。会话中所有正在进行的操作都会被中止,该会话也会被关闭。
  • KILL CONNECTION thread_id:显式地终止一个会话,与 KILL thread_id 的效果相同。
  • KILL QUERY thread_id:仅中断给定线程 ID 的当前执行的查询,而不会关闭会话。如果你想停止某个特定查询但保持会话连接有效,可以使用这个命令。

示例:
假设你想要终止一个 ID 为 1234 的线程(会话)

1
KILL 1234;

如果你只是想中断 ID 为 1234 的线程正在执行的查询,但不关闭会话:

1
KILL QUERY 1234;

空闲超时(Idle Timeout)

MySQL 服务器有一个 wait_timeout 参数,定义了一个连接在空闲状态下的最大等待时间。如果一个事务在没有进行任何操作的情况下达到这个超时时间,MySQL 会关闭连接,未提交的事务将被自动回滚。

查看和修改 wait_timeout 设置:

1
2
3
4
5
6
7
8
9
10
11
12
-- 查看当前会话超时设置
SHOW VARIABLES LIKE 'wait_timeout';

-- 查看全局超时设置
SHOW VARIABLES LIKE 'interactive_timeout';

-- 修改会话超时(单位:秒)
SET @@SESSION.wait_timeout = 28800; -- 8小时

-- 修改全局超时(单位:秒)
SET @@GLOBAL.wait_timeout = 28800; -- 8小时

Lock wait timeout exceeded

锁等待超时(Lock Wait Timeout Exceeded):发生在一个事务在等待另一个事务持有的锁时,超过了设置的最大等待时间。默认情况下,MySQL 的 innodb_lock_wait_timeout 参数定义了事务等待锁的最长时间(默认是 50 秒)。如果超过了这个时间,MySQL 会中止等待,并返回 1205 错误。

查看和修改锁等待超时时间

1
2
3
4
5
6
7
8
9
# 查看,默认是50秒
show variables like 'innodb_lock_wait_timeout';

# 设置锁等待超时时间为 360 秒
set @@SESSION.innodb_lock_wait_timeout=360;

# 设置全局锁等待超时时间
SET GLOBAL innodb_lock_wait_timeout = 120;

要在 Excel 中实现根据 Sheet1 的值匹配 Sheet2 中的值并取出对应行中另一个单元格的内容,可以使用 VLOOKUP 或 INDEX+MATCH 函数组合。以下是两种方法的示例:

方法一:使用 VLOOKUP 函数

假设 Sheet1 中的值在 A 列,Sheet2 中要匹配的值也在 A 列,取出匹配行中的 B 列的值。

  1. 在 Sheet1 中,选择要放置匹配结果的单元格,例如 B2
  2. 输入以下公式:
    1
    =VLOOKUP(A2, Sheet2!A:B, 2, FALSE)
  • A2 是要匹配的值。
  • Sheet2!A:B 是要在 Sheet2 中查找的区域。
  • 2 是返回的列号,即 Sheet2 中的 B 列。
  • FALSE 表示精确匹配。

方法二:使用 INDEX 和 MATCH 函数组合

假设 Sheet1 中的值在 A 列,Sheet2 中要匹配的值在 A 列,取出匹配行中的 B 列的值。

  1. 在 Sheet1 中,选择要放置匹配结果的单元格,例如 B2。
  2. 输入以下公式:
    1
    =INDEX(Sheet2!B:B, MATCH(A2, Sheet2!A:A, 0))
  • INDEX(Sheet2!B:B, …) 表示返回 Sheet2 中 B 列的值。
  • MATCH(A2, Sheet2!A:A, 0) 查找 A2 的值在 Sheet2 A 列中的位置,0 表示精确匹配。
0%