一.linux查看日志的几种方法
linux 日志查看
tail、head、 cat、tac、sed、less、echo
1、命令格式: tail [必要参数] [选择参数] [文件]
-f 循环读取
-q 不显示处理信息
-v 显示详细的处理信息
-c<数目> 显示的字节数
-n<行数> 显示行数
-q, –quiet, –silent 从不输出给出文件名的首部
-s, –sleep-interval=S 与-f合用,表示在每次反复的间隔休眠S秒
tail -n 100 catalina.out 查询日志尾部最后100行的日志;
tail -n +100 catalina.out 查询100行之后的所有日志;
tail -fn 100 catalina.out 循环实时查看最后100行记录(最常用的)
配合着grep用, 例如 : tail -fn 100 catalina.out | grep — ‘关键字’
如果一次性查询的数据量太大,可以进行翻页查看,
例如:tail -n 6000 catalina.out |more -100 可以进行多屏显示(ctrl + f 或者 空格键可以快捷键)
————————————————————————————————————————–
2、head
$ cat filename // 一次显示整个文件
$ cat > filename //从键盘创建一个文件
$cat -n textfile1 > textfile2 //将一个日志文件的内容追加到另外一个 :
$cat : >textfile2 // 清空一个日志文件
注意: >意思是创建, >>是追加。
cat其他参数与tail 类似
4.tac
tac 则是由最后一行到第一行反向在萤幕上显示出来
5.sed
这个命令可以查找日志文件特定的一段 , 也可以根据时间的一个范围查询
linux日志文件说明
/var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日志之一
/var/log/secure 与安全相关的日志信息
/var/log/maillog 与邮件相关的日志信息
/var/log/cron 与定时任务相关的日志信息
/var/log/spooler 与UUCP和news设备相关的日志信息
/var/log/boot.log 守护进程启动和停止相关的日志消息
/var/log/wtmp 该日志文件永久记录每个用户登录、注销及系统的启动、停机的事
附录3
tomcat运行日志
1、先切换到:cd usr/local/tomcat3/logs
2、tail -f catalina.out
3、这样运行时就可以实时查看运行日志了
Ctrl+c 是退出tail命令。 alt+E+R重置
二.mysql索引失效的几种情况(总结)
索引并不是时时都会生效的,比如以下几种情况,将导致索引失效:
1.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)
注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
2.对于多列索引,不是使用的第一部分,则不会使用索引
3.like查询是以%开头
4.如果列类型是字符串,那一定要在条件中将数据使用引 引用起来,否则不使用索引
5.如果mysql估计使用全表扫描要比使用索引快,则不使用索引
此外,查看索引的使用情况
show status like ‘Handler_read%’;
大家可以注意:
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数
handler_read_rnd_next:这个值越高,说明查询低效
1) 没有查询条件,或者查询条件没有建立索引
2) 在查询条件上没有使用引导列
3) 查询的数量是大表的大部分,应该是30%以上。
4) 索引本身失效
5) 查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等) 错误的例子:select * from test where id-1=9; 正确的例子:select * from test where id=10;
6) 对小表查询
7) 提示不使用索引
8) 统计数据不真实
9) CBO计算走索引花费过大的情况。其实也包含了上面的情况,这里指的是表占有的block要比索引小。
10)隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20),但在查询时把该字段作为number类型以where条件传给Oracle,这样会导致索引失效. 错误的例子:select * from test where tu_mdn=13333333333; 正确的例子:select * from test where tu_mdn=’13333333333′;
12) 1,<> 2,单独的>,<,(有时会用到,有时不会)
13,like “%_” 百分 在前.
4,表没分析.
15,单独引用复合索引里非第一位置的索引列.
16,字符型字段为数字时在where条件里不添加引 .
17,对索引列进行运算.需要建立函数索引.
18,not in ,not exist.
19,当变量采用的是times变量,而表的字段采用的是date变量时.或相反情况。
20,B-tree索引 is null不会走,is not null会走,位图索引 is null,is not null 都会走
21,联合索引 is not null 只要在建立的索引列(不分先后)都会走, in null时 必须要和建立索引第一列一起使用,当建立索引第一位置条件是is null 时,其他建立索引的列可以是is null(但必须在所有列 都满足is null的时候),或者=一个值; 当建立索引的第一位置是=一个值时,其他索引列可以是任何情况(包括is null =一个值),以上两种情况索引都会走。其他情况不会走。
三、谈谈swoole的进程架构模型
swoole的强大之处就在与其进程模型的设计,既解决了异步问题,又解决了并行。
主线程MainReactor
swoole启动后主线程会负责监听server socket,如果有新的连接accept,主线程会评估每个Reactor线程的连接数量。将此连接分配给连接数最少的reactor线程。这样的好处是
- 每个reactor线程持有的连接数是非常均衡的,没有单个线程负载过高的问题
- 解决了惊群问题,尤其是拥有多个listen socket时,节约了线程唤醒和切换的开销
主线程内还接管了所有信 signal的处理,使Reactor线程运行中可以不被信 打断。
管理进程Manager
swoole运行中会创建一个单独的管理进程,所有的worker进程和task进程都是从管理进程Fork出来的。管理进程会监视所有子进程的退出事件,当worker进程发生致命错误或者运行生命周期结束时,管理进程会回收此进程,并创建新的进程。
管理进程还可以平滑地重启所有worker进程,以实现程序代码的重新加载。
异步Reactor线程
swoole拥有多线程Reactor,所以可以充分利用多核,开启CPU亲和设置后,Reactor线程还可以绑定单独的核,节约CPU Cache开销。
swoole的Reactor线程是全异步非阻塞的,即使你的worker进程用了同步模式,依然不影响reactor线程的性能。在worker进程组很繁忙的状况下,reactor线程完全不受影响,依然可以收发处理数据。
TCP是流式的,没有边界,所以处理起来很麻烦。Reactor线程可以根据EOF或者包头长度,自动缓存数据,组装数据包。等一个请求完全收到后,再投递给Worker进程。
同步或异步Worker进程
与传统的半同步半异步服务器不同,Swoole的worker进程可以是同步的也可以异步的,这样带来了最大的灵活性。当你的Server需要很高性能,业务逻辑较为简单时你可以选择异步模式。当业务逻辑复杂多变,可以选择同步模式。
这里要比Node.js强大太多了。
TaskWorker进程池
swoole除了Reactor线程,Worker进程外还提供了TaskWorker进程池,目的是为了解决在业务代码中,有些逻辑部分不需要马上执行。利用task进程池,可以方便的投递一个异步任务去执行,在Worker进程空闲时再去捕获任务执行的结果。
四、redis哨兵介绍 – 概念 、原理、部署
哨兵
在一个典型的一主多从的Redis系统中,当主数据库遇到异常中断服务后,需要手动选择一个从数据库升级为主数据库,整个过程需要人工介入,难以自动化。
Redis2.8提供了哨兵2.0(2.6提供了1.0,但是问题较多),哨兵顾名思义就是监控Redis系统的运行状况。它的功能包括一下两个:
监控主数据库和从数据库是否正常运行;
主数据库出现故障时自动将从数据库升级为主数据库;
哨兵是一个独立的进行,在一个一主多从的Redis系统中,可以使用多个哨兵监控整个Redis系统,哨兵之间也会互相监控。
配置
基于前面的一主两从架构,为他们加入哨兵。
可以在三个redis节点的redis目录下找到sentinel.conf文件,这个文件就是哨兵的配置文件,修改配置如下:
sentinel monitor mymaster 192.168.2.101 6379 3
其中mymaster是要监控的主数据库名字,可以自定义;
接下来是主数据库的ip和端口;
最后一个3是指哨兵最低通过票数;
如果你需要后台启动,则修改daemonize参数:
daemonize yes
配置后如果有防火墙,不要忘记打开哨兵的端口,默认是26379。
最后,开启哨兵:
redis-sentinel /yourpath/sentinel.conf
做个测试,关闭主数据库(192.168.2.101)后,等待30秒(默认30秒):
哨兵将从数据库中的一个节点升级成主数据库(192.168.2.102);
将另一个从数据库(192.168.2.103)的主数据库(192.168.2.101)切换到新的主数据库(192.168.2.102);
随后启动刚才关闭的主数据库(192.168.2.101)
哨兵自动将其转为从数据库;
原理
监控过程
哨兵启动后,会与要监控的主数据库建立两条连接:
一条用来用来订阅__sentinel__:hello频道以获取其他哨兵节点的信息;
另一条用来定期向主数据库发送INFO等命令来获取主数据库本身的信息;
在和主数据库建立连接后,哨兵会定时执行下面3个操作:
每10秒哨兵会向主数据库和从数据库发送INFO命令;
每2秒哨兵会向主数据库和从数据库的__sentinel__:hello频道发送自己的信息;
每1秒哨兵会向主数据库和从数据库和其他哨兵发送PING命令;
第一个操作是发送INFO命令,目的是获取主数据库的信息,以及主数据库的从数据库的信息,从而实现新节点的自动发现,并对从数据库也建立两条连接。
第二个操作是订阅__sentinel__:hello频道,并发送哨兵本身的信息,与同样监控该数据库的其他哨兵分享自己的信息,同时也能识别哨兵是否是新哨兵。哨兵与哨兵之间也会建立一个链接,用来发送PING命令;
第三个操作是发送PING命令,在发现了从数据库和其他哨兵后,要做的就是定时监控Redis服务是否停止,时间间隔与配置文件中的down-after-milliseconds有关,当这个值小于1秒时,哨兵会每隔该值的时间发送PING命令,当这个值大于1秒时,哨兵会每隔1秒发送一次PING命令。
配置方式是在sentinel.conf文件中加入:
sentinel down-after-milliseconds mymaster 600 # 600毫秒发送一个PING
当超过down-after-milliseconds时,如果PING的数据库未回复,则哨兵认为其主观下线。主观下线可以理解为当前的哨兵认为该节点下线了。
如果该节点是主数据库,则哨兵们会进一步判断是否需要对其进行故障修复:
哨兵会发送SENTINEL is-master-down-by-addr命令询问其他哨兵,判断他们是否也认为该主数据库下线,如果达到quorum参数,也就是我们在配置哨兵时的命令:
sentinel monitor mymaster 192.168.2.101 6379 3
的最后一个参数3,哨兵们会认为这个主数据库客观下线,并选举一个领头哨兵对主从系统发起故障恢复。
领头哨兵选举
要进行故障恢复,则需要选举出一个领头哨兵,领头哨兵的选择算法是Raft算法,具体过程如下:
发现主数据库客观下线的哨兵节点(A节点)想每个哨兵节点发送命令,要求对方选择自己成为领头哨兵;
如果目标哨兵节点没有选择过其他人,则会同意将A设置成领头哨兵;
如果A发现超过半数且超过quorum参数个哨兵节点同意选择自己,则A成功成为领头哨兵;
当有多个哨兵同时参选,则会出现没有任何节点当选的可能,此时每个参选节点将等待一个随即时间重新发起竞选,直到选举成功。
故障恢复
选择出领头哨兵后,会把从数据库中的一个挑选出来升级为主数据库:
所有先线的从数据库中,选择优先级最高的,优先级可以通过slave-priority来设置;
如果有多个一样优先级的从数据库,则复制的命令偏移量越大,越优先(与down掉的主数据库最接近);
如果还有多个备选,则选择运行ID较小的(运行ID不会重复);
选择好节点后,领头哨兵将想这个节点发送slaveof no one,升级他为主数据库。
然后想其他从数据库发送slaveof命令切换主数据库。
最后更新内部的记录,将已经停止服务的旧的主数据库更新为新的主数据库的从数据库,当其回复后自动以从数据库的身份加入到主从架构中。
哨兵部署
哨兵的推荐部署方案:
为每个节点(无论是主数据库还是从数据库)都部署一个哨兵;
使每个哨兵与其对应的节点的 络环境相同或相近;
设置quorum的值为N/2+1,这样使得只有当大部分哨兵统一后才会选择领头哨兵进行故障恢复;
五、Redis分布式锁的实现原理
一、写在前面
现在面试,一般都会聊聊分布式系统这块的东西。通常面试官都会从服务框架(Spring Cloud、Dubbo)聊起,一路聊到分布式事务、分布式锁、ZooKeeper等知识。
所以咱们这篇文章就来聊聊分布式锁这块知识,具体的来看看Redis分布式锁的实现原理。
说实话,如果在公司里落地生产环境用分布式锁的时候,一定是会用开源类库的,比如Redis分布式锁,一般就是用Redisson框架就好了,非常的简便易用。
大家如果有兴趣,可以去看看Redisson的官 ,看看如何在项目中引入Redisson的依赖,然后基于Redis实现分布式锁的加锁与释放锁。
下面给大家看一段简单的使用代码片段,先直观的感受一下:
怎么样,上面那段代码,是不是感觉简单的不行!
此外,人家还支持redis单实例、redis哨兵、redis cluster、redis master-slave等各种部署架构,都可以给你完美实现。
二、Redisson实现Redis分布式锁的底层原理
好的,接下来就通过一张手绘图,给大家说说Redisson这个开源框架对Redis分布式锁的实现原理。
(1)加锁机制
咱们来看上面那张图,现在某个客户端要加锁。如果该客户端面对的是一个redis cluster集群,他首先会根据hash节点选择一台机器。
这里注意,仅仅只是选择一台机器!这点很关键!
紧接着,就会发送一段lua脚本到redis上,那段lua脚本如下所示:
为啥要用lua脚本呢/p>
因为一大坨复杂的业务逻辑,可以通过封装在lua脚本中发送给redis,保证这段复杂业务逻辑执行的原子性。
那么,这段lua脚本是什么意思呢/p>
KEYS[1]代表的是你加锁的那个key,比如说:
RLock lock = redisson.getLock(“myLock”);
这里你自己设置了加锁的那个锁key就是“myLock”。
ARGV[1]代表的就是锁key的默认生存时间,默认30秒。
ARGV[2]代表的是加锁的客户端的ID,类似于下面这样:
8743c9c0-0795-4907-87fd-6c719a6b4586:1
给大家解释一下,第一段if判断语句,就是用“exists myLock”命令判断一下,如果你要加锁的那个锁key不存在的话,你就进行加锁。
如何加锁呢简单,用下面的命令:
hset myLock
8743c9c0-0795-4907-87fd-6c719a6b4586:1 1
通过这个命令设置一个hash数据结构,这行命令执行后,会出现一个类似下面的数据结构:
上述就代表“8743c9c0-0795-4907-87fd-6c719a6b4586:1”这个客户端对“myLock”这个锁key完成了加锁。
接着会执行“pexpire myLock 30000”命令,设置myLock这个锁key的生存时间是30秒。
好了,到此为止,ok,加锁完成了。
(2)锁互斥机制
那么在这个时候,如果客户端2来尝试加锁,执行了同样的一段lua脚本,会咋样呢/p>
很简单,第一个if判断会执行“exists myLock”,发现myLock这个锁key已经存在了。
接着第二个if判断,判断一下,myLock锁key的hash数据结构中,是否包含客户端2的ID,但是明显不是的,因为那里包含的是客户端1的ID。
所以,客户端2会获取到pttl myLock返回的一个数字,这个数字代表了myLock这个锁key的剩余生存时间。比如还剩15000毫秒的生存时间。
此时客户端2会进入一个while循环,不停的尝试加锁。
(3)watch dog自动延期机制
客户端1加锁的锁key默认生存时间才30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢/p>
简单!只要客户端1一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。
(4)可重入加锁机制
那如果客户端1都已经持有了这把锁了,结果可重入的加锁会怎么样呢/p>
比如下面这种代码:
这时我们来分析一下上面那段lua脚本。
第一个if判断肯定不成立,“exists myLock”会显示锁key已经存在了。
第二个if判断会成立,因为myLock的hash数据结构中包含的那个ID,就是客户端1的那个ID,也就是“8743c9c0-0795-4907-87fd-6c719a6b4586:1”
此时就会执行可重入加锁的逻辑,他会用:
incrby myLock
8743c9c0-0795-4907-87fd-6c71a6b4586:1 1
通过这个命令,对客户端1的加锁次数,累加1。
此时myLock数据结构变为下面这样:
大家看到了吧,那个myLock的hash数据结构中的那个客户端ID,就对应着加锁的次数
(5)释放锁机制
如果执行lock.unlock(),就可以释放分布式锁,此时的业务逻辑也是非常简单的。
其实说白了,就是每次都对myLock数据结构中的那个加锁次数减1。
如果发现加锁次数是0了,说明这个客户端已经不再持有锁了,此时就会用:
“del myLock”命令,从redis里删除这个key。
然后呢,另外的客户端2就可以尝试完成加锁了。
这就是所谓的分布式锁的开源Redisson框架的实现机制。
一般我们在生产系统中,可以用Redisson框架提供的这个类库来基于redis进行分布式锁的加锁与释放锁。
(6)上述Redis分布式锁的缺点
其实上面那种方案最大的问题,就是如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。
但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。
接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。
此时就会导致多个客户端对一个分布式锁完成了加锁。
这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。
所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。
六、使用Redis如何保证多个操作的原子性/h1>
1.1方案一
利用setnx和expire命令实现加锁。当一个线程执行setnx返回1,说明key不存在,该线程获得锁;当一个线程执行setnx返回0,说明key已经存在,则获取锁失败。expire就是给锁加一个过期时间。伪代码如下:
该方案有一个致命问题,由于setnx和expire是两条Redis命令,不具备原子性,如果一个线程在执行完setnx()之后突然崩溃,导致锁没有设置过期时间,那么将会发生死锁。
1.2方案二
利用setnx命令加锁,其中key是锁,value是锁的过期时间,1.通过setnx()方法尝试加锁,如果当前锁不存在,返回加锁成功。2. 如果锁已经存在则获取锁的过期时间,和当前时间比较,如果锁已经过期,则设置新的过期时间,返回加锁成功。伪代码如下:
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!