<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="https://www.ishiguang.cn/feed/rss/tag/%E5%8E%9F%E6%96%87/">
<title>拾光 - 原文</title>
<link>https://www.ishiguang.cn/tag/%E5%8E%9F%E6%96%87/</link>
<description></description>
<items>
<rdf:Seq>
<rdf:li resource="https://www.ishiguang.cn/14398.html"/>
<rdf:li resource="https://www.ishiguang.cn/12061.html"/>
<rdf:li resource="https://www.ishiguang.cn/12059.html"/>
<rdf:li resource="https://www.ishiguang.cn/12058.html"/>
<rdf:li resource="https://www.ishiguang.cn/12056.html"/>
<rdf:li resource="https://www.ishiguang.cn/12057.html"/>
<rdf:li resource="https://www.ishiguang.cn/12055.html"/>
<rdf:li resource="https://www.ishiguang.cn/12054.html"/>
<rdf:li resource="https://www.ishiguang.cn/12053.html"/>
<rdf:li resource="https://www.ishiguang.cn/12051.html"/>
</rdf:Seq>
</items>
</channel>
<item rdf:about="https://www.ishiguang.cn/14398.html">
<title>减字木兰花（送赵令）</title>
<link>https://www.ishiguang.cn/14398.html</link>
<dc:date>2022-02-05T06:12:00+08:00</dc:date>
<description>减字木兰花（送赵令）宋代 · 苏轼春光亭下。流水如今何在也。岁月如梭。白首相看拟奈何。故人重见。世事年来千万变。官况阑珊。惭愧青松守岁寒。人生如细，岁月如梭。只叹今朝无能为力，心不甘，奈可何!看年年岁岁，比比皆是楼上楼，人上人。愿子能懂半是非。</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12061.html">
<title>Java 异步 I/O</title>
<link>https://www.ishiguang.cn/12061.html</link>
<dc:date>2022-01-22T19:43:27+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		Java 中的异步 I/O 简称 AIO， A 即 Asynchronous。AIO 在 JDK1.7 时引入，基于操作系统提供的异步 I/O 通信模型，封装了一些进行异步 I/O 操作的 API。1. 异步 I/O 模型学习 Java I/O 相关操作之前应该先了解其背后的 I/O 模型。Java 典型的基于流的文件操作和网络通信都是基于同步阻塞 I/O 模型，JDK1.4 引入的 NIO 基于多路复用 I/O 模型，而 AIO 则基于异步 I/O 模型。在 Linux 操作系统中，异步模型从 I/O 设备读取数据的流程如下图所示。应用程序内核aio_read数据未准备好程序继续执行等待数据数据已准备好复制完成复制数据到用户空间处理数据系统调用传递信号立即返回
  应用程序向内核发起 aio_read 系统调用，传递缓存区信息，要读取的文件信息； 
  内核接收请求之后立即返回，应用程序未阻塞； 
  内核等待 CPU 或者 DMA 设备将数据从 I/O 设备复制到内核缓冲区； 
  内核将数据复制到用户空间缓冲区； 
  内核发送一个信号给用户程序，告知数据已复制完成； 
  应用程序处理用户空间缓冲区中的数据。
 2. 异步通道基于异步 I/O 模型，JDK 提供了面向通道和缓冲区编程的 API。事实上，Java 为基于同步阻塞 I/O 模型的 “旧I/O” 和基于多路复用 I/O 模型的 “新I/O” 也提供了面向通道和缓冲区的 API。异步 I/O 的核心接口是 AsynchronousChannel，这个接口有文件 I/O 的实现和网络 I/O 的实现。java.nio.channelsAsynchronousChannelAsynchronousServerSocketChannelAsynchronousSocketChannelAsynchronousByteChannelAsynchronousFileChannel
  AsynchronousFileChannel 异步文件通道，用于异步操作文件； 
  AsynchronousSocketChannel 异步套接字通道，用于 TCP 通信； 
  AsynchronousServerSocketChannel 异步套接字监听通道，作为服务端，接收 TCP 连接并创建 AsynchronousSocketChannel。
 3 异步操作的两种形式异步通道 AsynchronousChannel 并没有显式提供一些必须实现的异步操作的抽象方法（事实上，这个接口仅提供了抽象方法 close()），但是它在注释中给出了异步操作 API 的两种形式。一种异步操作是返回一个 Future，另一种是往异步方法中传递一个回调函数，也就是一个 CompletionHandler 的对象，这两种形式一般的异步编程框架中很常见。3.1 返回 Future 形式Future operation(...)void operation(... A attachment, CompletionHandler handler)其中 operation() 代表异步操作，比如从 I/O 设备中读取数据 read，往 I/O 设备中写入数据 write。第一种是异步操作返回 Future，其中 V 是异步操作返回值的类型。开发人员可以调用 Future#isDone() 或者 Future#isCancelled() 查询异步操作的状态，也可以调用 Future#get()，阻塞当前线程，直到异步操作完成。读取数据Future future = readChan.read(buff); // 异步读取数据，并立即返回future.get(); // 阻塞，等到异步操作完成，效率低写入数据Future future = writeChan.write(buff, position); // 异步写入数据，并立即返回len = future.get(); // 阻塞等待异步操作完成，效率低当然，为了提高效率，开发过程中也可以不调用 Future#get() 方法来阻塞代码，可以通过轮询的方式检查 Future 是否已经完成，完成之后再调用 Future#get() 来获取结果。3.2 回调形式第二种操作是往异步函数中传递一个 A attachment 和 CompletionHandler。其中 A 表示附件的类型，附件通常用来往 CompletionHandler 对象中传入一些上下文信息，V 表示异步操作返回值类型。CompletionHandler 提供了两个抽象方法：completed(V result, A attachment) 和 failed(Throwable t, A attachment)。当异步操作成功，completed 会被调用；当异步操作失败，failed 会被调用。读取到一个数据块就会调用回调代码，不会阻塞。可以采用匿名内部类的方式去实现回调接口，也可以采用一般实现类，通过 attachment 传递上下文的形式实现回调逻辑。匿名内部类方式readChan.read(buff, 0, null, new CompletionHandler() { // 从位置 0 开始读取数据，数据读取到缓冲区 buff 中long readSize = 0; // 已经读取的字节数@Overridepublic void completed(Integer result, Object attachment) {// 打印读取到的数据System.out.println(Thread.currentThread() + new String(buff.array(), 0, result));try {if ( (readSize = readSize + result) < readChan.size()) { // 已读取字节数少于文件总字节数，继续读取buff.clear(); // 将 buff 的 position 移动到起始位置，使其变为可写状态readChan.read(buff, readSize, null, this); // 递归，继续读取，注意改变读取位置，Handler 直接使用 this。} else {semaphore.release();}} catch (IOException e) {e.printStackTrace();}}传递上下文(attachment)方式一般的调用逻辑。Context context = new Context();          // 自定义类，存放上下文信息，上下文信息可根据需要设定context.asyncFileChan = asyncFileChan;context.buffer = ByteBuffer.allocate(4);AsyncReadDataHandler callback = new AsyncReadDataHandler(); // 创建一个处理器对象asyncFileChan.read(context.buffer, 0, context, callback); // 执行异步读取数据AsyncReadDataHandler 和 Context 的实现。/** 定义上下文类 */class Context {AsynchronousFileChannel asyncFileChan;ByteBuffer buffer;}

/** 回调实现类 */class AsyncReadDataHandler implements CompletionHandler {

  private long readSize = 0;

  private Semaphore semaphore = new Semaphore(0);

  @Overridepublic void completed(Integer size, Context context) {System.out.print(new String(context.buffer.array(), 0, size));context.buffer.clear();try {if ( (readSize = readSize + context.buffer.limit()) < context.asyncFileChan.size()) {// 还有数据，继续读。数据放入到 context.buffer 中，从 readSize 位置开始读，附件是 context，处理器是当前对象context.asyncFileChan.read(context.buffer, readSize, context, this);} else {semaphore.release();}} catch (IOException e) {e.printStackTrace();semaphore.release();}}

  @Overridepublic void failed(Throwable cause, Context context) {cause.printStackTrace();semaphore.release();}

  // 等待结束public void waitForEnd() throws InterruptedException {semaphore.acquire();}}4. 异步文件通道异步文件通道和文件通道的大部分 API 相同，不同的是异步文件通道支持异步读取和写入数据。这里仅介绍这两类异步 API，其它 API 以及内存映射相关的内容可以参考Java NIO 文件通道 FileChannel 用法。public class AsyncFileChannel {

  public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {Path path = Paths.get("data.txt"); // 准备一些数据

    /* 异步写入数据 */byte[] data = "This is an example of AsynchronousFileChannel".getBytes(StandardCharsets.UTF_8);ByteBuffer buff = ByteBuffer.allocate(4); // 分配一个大小为 4 的字节缓冲区AsynchronousFileChannel writeChan = AsynchronousFileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);long position = 0; // 记录写入数据在文件中的起始位置for (int i = 0; i</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12059.html">
<title>JavaFx 实现按钮防抖</title>
<link>https://www.ishiguang.cn/12059.html</link>
<dc:date>2022-01-22T19:40:18+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		原文地址：JavaFx 实现按钮防抖 | Stars-One的杂货小窝Android平台的APP，一般是有需要进行设置按钮的防抖（即在短时间内无法多次点击），我想在JavaFx项目中也是实现防抖功能，便是研究了下实现原理点击按钮前，需要记录当前点击的时间，在按钮下一次点击的时候，与之前记录的点击时间进行计算，判断两者的间隔时间是否大于设定的条件值这里思路没有是嘛难度，主要是点击时间的历史记录该如何记录？有以下几种方法
  使用Map存储（按钮过多占用资源较大） 
  使用控件对象提供的某个无用字段进行存储
 在Android中，可以使用View中的tag来保存信息而在JavaFx中，所有的控件都有userData的字段，有了这个，我们即可去存储时间实现代码Kotlin版：kotlin版我是使用了扩展方法，对BUtton类进行了扩展，不太明白扩展方法的可以查下资料，简单来说即是给Button类新增了个方法//注意Button是javafx包的fun Button.isFastClick(): Boolean {val lastClickTime = userData as Long?val currentTime = System.currentTimeMillis()

    userData = currentTime//这里我设置为1s内多次点击无效，可以根据需要调整if (lastClickTime != null && currentTime - lastClickTime </description>
</item>
<item rdf:about="https://www.ishiguang.cn/12058.html">
<title>新手如何入门linux，linux原来还可以这么学</title>
<link>https://www.ishiguang.cn/12058.html</link>
<dc:date>2022-01-22T19:40:17+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		前言在这个只有cangls和小白两人的小房间中，展开了一次关于学习方法的讨论。小白：cangls啊，我想请教一个问题，您是如何记住那么多linux命令的。cangls：我啊，别人都看我的小电影，我也不知道啊！可能是举的例子多了，就记住了一些呗。此次写作灵感源于一本心理学方面的书籍，对话体的方式运用得当，确实很吸引人。灵魂拷问？新手如何学linux？如何从新手到熟手？如何玩转linux？linux大神如何掌握那么多命令？趣味学习linux，了解一下。基于实战演练，同时突出重点。2万5千字的长文，是否真材实料，不妨先收藏再评论。换个角度看待这个问题，linux大神都是从小白开始的，没有人一开始就是大神。只是别人运用的比较多，自然而然记住了更多的命令，从而更擅长总结学习方法。如果你是Linux运维人员，或者是刚入门的编程人员。根据自己的工作经历以及自学总结的内容，篇幅很长，加入了不少示例代码。但很详细哟！相信你一定有所收获的。正文7年前，我还是一个连linux是个啥都不知道的笨小孩，然而现在靠着自学积累的知识也能在日常工作中满足刚需，还教会了新来的同事不少小技巧。先上点趣味性的知识，俗称扫盲，拥有一颗爱学习（闷骚）的心。01 第一夜以linux为基础将知识串联起来，加入了一些个人经验总结，仅供参考哟！当然，你可以将此篇文章推送你的亲朋好友，当做是学习linux的入门课程。个人建议，如果感觉建议不到位，可以忽略掉。请直接看正文，相信会有收获的在给别人建议的时候，希望能从他人的角度去思考。不要上来直接甩一个教程或者视频过去，这样对新人是很不友好的。首先，我们应该养成自学的良好习惯。最优的方法往往是去官网查阅文档，其次通过各大论坛，再就是搜索引擎。但官方文档大体都是英文版的，小白往往也是心有余而力不足，记得多用词典查阅并积累。但是，现在linux有简体中文版支持，我们在搭建学习环境的时候可以选择简体中文。当你学到深处的时候，发现还是官方文档最靠谱。搭建环境，建议是真机配合虚拟机工具部署linux服务器(Redhat系列、Ubuntu、Fedora、Debian等等)使用，放心大胆的测试，再也不用担心服务器被自己弄崩溃了。终端管理工具推荐tabby（github上有），虽然目前终端不支持中文字符输入，但它是开源免费的。关于以何种linux的发行版进行学习，希望不要去跟风，听风就是雨，要根据自身实际情况而定。如果非要我推荐，那就是推荐Redhat系列的Centos或者Ubuntu系列，教程和资源多呗。给出我之前写的稀烂的教程linux养成达人之入门实践图文超详细（工欲善其事，必先利其器篇），希望对你有所帮助（基于centos6.5的）：https://blog.csdn.net/Tolove_dream/article/details/103823216关于centos7的可以参考这篇文章：https://blog.csdn.net/Tolove_dream/article/details/116085467接着说linux简体中文版，优势在于我看帮助命令的时候有一部分是中文的，这就对我们的学习有大大大的好处。当你提这个问题的时候，应该是对linux这个极具魅力的操作系统有很大的兴趣。有兴趣那就好办了，你会思考如何学习对自己更为有利。此时就会去翻阅文档，最后发现还是官方文档最为有用，学会积累经验。慢慢的从小白到老手，这之间有一段艰难的路需要独自走完，享受这一过程的美妙之处。曾经你是不是在各大论坛或者博客网站都能看到这样一些内容，从删库到跑路。全球绝大部分的服务器啊，基本上都是采用linux服务器的，没有权限你还想删库到跑路？当然只是开个玩笑，咱都是遵纪守法的五好青年。前面的删库到跑路，只是为了引出linux另一大魅力所在权限足够透明。如果在权限这方面玩的相当熟练，那你可以存不少cang老师的作品哟。我能自己欣赏，别人却看不到，想想就刺激。谈到cang老师，大家满眼放光聚精会神直呼内行。咱就皮一下，这不是为了引起你学习的兴趣吗。做了很多铺垫，这里就详细的聊聊我自己的学习过程。将以对话形式展示，小白与cangls日日夜夜的对话。cangls是啥？别问我，问就是不知道，只可意会不可言传。一、学习方法的探讨在这个只有cangls和小白两人的小房间中，展开了一次关于学习方法的讨论。小白：cangls啊，我想请教一个问题，您是如何记住那么多linux命令的。cangls：我啊，别人都看我的小电影，我也不知道啊！可能是举的例子多了，就记住了一些呗。小白：是这样啊！那能具体说说吗，我很感兴趣。cangls：好啊，那咱就互相探讨探讨。这这这，啥情况？我怀疑你两不仅在开车，而且还搞颜色，还超速了。好了，玩归玩闹归闹，言归正传。小白：我想查看一下以前放的学习资料(小电影)cangls：使用ls命令即可查看目录和文件。# 不带参数$ ls# -a参数，查询所有，包含带.隐藏的$ ls -a# -l参数，长格式显示：显示所属组、所有者，修改时间以及文件名$ ls -l小白：我想给文件夹改个名字，羞羞。cangls：好办，使用mv命令就能处理。$ mv cangls  bols小白：那我想移动到另一个文件夹呢？cangls：同样可以使用mv命令，但要接路径哟！$ mv /opt/cangls  /home/cangls/av小白：cangls呀，我目前存的文件过多，想集中分类处理。cangls：你是想，将多个文件存放到同一个目录吧。mkdir命令新建文件夹可以满足你，记得用上面的mv命令转移学习资料。$ mkdir  /home/cangls/av此时的小白看了看时间，已经记不起这是多少次来请教cangls了。cangls教了小白一个很鸡肋的但很实用的命令。cangls：小白啊，知道今天是今年的第多少天吗？小白：我不记得了，看看手机就知道了。cangls：不用那么麻烦，用linux自带的命令cal即可查看。$ cal -jycangls此时看小白兴趣不减反增，于是介绍了帮助命令help和man来方便小白自学。上面的对话形式，是不是很有趣。当你心烦意乱的时候，不妨静下心来试试。找一个自己感兴趣的方向，去验证这些命令。如果你感兴趣的话，我之前写的部分文章也许会对你有一定的帮助。cangls和小白的对话并没有结束，在这个只有两人的小房间中，到底发生了啥，请接着看。02 第二夜第一夜对学习方法进行了探讨，如何一步步提升自己学习的兴趣。第二夜cangls与小白继续展开关于linux基本命令的讨论。cangls：小白啊，你来了，看来还是有不少疑问吧！小白：是的，虽然上次你说了一些关于linux的帮助命令，我还是有些摸不着头脑。cangls：没关系，下面我给你带来了详细的帮助命令的讲解，学习方法很重要哟！小白此时拿出了自己的小本本，开始记录了起来...二、基本命令的探讨注意：#符号表示root用户登录，$符号表示普通用户登录。1、帮助命令（重点）这种方法是其中一种手段，将其输出到某个文件，然后总结起来。再通过scp命令传到本地记录到小本本上。[root@cnwangk ~]# ls --help > helpcmd.txt[root@cnwangk ~]# man ls >> helpcmd.txt#借助本地的终端管理工具，使用scp命令取到Windows本地桌面，即从远程传回本地$ scp root@192.168.245.131:/root/helpcmd.txt ~/Desktop/root@192.168.245.131's password:helpcmd.txt                                                                                              100%   21KB   3.8MB/s   00:00注意：>符号是重定向输入会覆盖原始文件的内容，>>符号也是重定向输入到指定文件，但是是追加进去。1.1、help命令如下所示，直接输入help命令就会输出很多提示，或者在使用的命令后面加上参数--help进行操作。$ help$ ls --help上面的第一条命令代表着直接输入help命令，也会反馈一些帮助文档出来。第二种方式，则是以具体的命令ls使用--help帮助命令获取指定命令的帮助文档。1.2、man命令1.2.1、man的级别作用 
   
    
    参数 
    作用 
    
   
   
    
    1 
    查看命令的帮助 
    
    
    2 
    查看可被内核调用的函数的帮助 
    
    
    3 
    查看函数和函数库的帮助 
    
    
    4 
    查看特殊件的帮助（主要是/dev目录下的文件） 
    
    
    5 
    查看配置文件的帮助 
    
    
    6 
    查看游戏的帮助 
    
    
    7 
    查看其它杂项的帮助 
    
    
    8 
    查看系统管理员可用命令的帮助 
    
    
    9 
    查看和内核相关文件的帮助 
    
   
 例如：查看passwd的配置文件帮助、查看null的特殊件的帮助、查看ifconfig系统管理员可用命令的帮助。$ man 5 passwd$ man 4 null$ man 8 ifconfigman 命令，获取指定命令的帮助，展示ls命令全部内容帮助手册。$ man ls查看命令拥有哪个级别的帮助,man -f 命令相当于whatis命令。$ man -f[root@cnwangk ~]# man -fwhatis 什么？$ whatis查看命令相关的所有帮助。man -k 命令，相当于apropos 命令。例如：$ man -k$ apropos#查看passwd的帮助命令$ apropos passwd1.2.2、man命令的详细展示直接在终端输入man命令，会提示您需要什么手册页？这里以查看ls命令的帮助手册为例子进行讲解示例说明，列举了部分示例。tips：输入q直接退出帮助手册。[root@cnwangk ~]# man您需要什么手册页？#进入ls命令的帮助文档$ man lsLS(1)                              General Commands Manual                                                   LS(1)NAMEls, dir, vdir - 列目录内容提要ls [选项] [文件名...]POSIX 标准选项: [-CFRacdilqrtu1]GNU 选项 (短格式):[-1abcdfgiklmnopqrstuxABCDFGLNQRSUX] [-w cols] [-T cols] [-I pattern] [--full-time] [--format={long,verbose,commas,across,verti‐cal,single-column}] [--sort={none,time,size,extension}] [--time={atime,access,use,ctime,status}]  [--color[={none,auto,always}]][--help] [--version] [--]描述（ DESCRIPTION ）程序ls先列出非目录的文件项，然后是每一个目录中的“可显示”文件。如果  没有选项之外的参数【译注：即文件名部分为空】出现，缺省为 "."（当前目录）。 选项“ -d ”使得目录与非目录项同样对待。除非“ -a ” 选项出现，文 件名以“.”开始的文件不属“可显示”文件。以当前目录为准，每一组文件（包括非目录文件项，以及每一内含文件的目录）分别按文件名比较顺序排序。如果“-l”选项存在，每组文件前显示一摘要行: 给出该组文件长度之和（以 512 字节为单位）。输出是到标准输出（stdout）。除非以“-C”选项要求按多列输出，输出将是一行一个。然而，输出到终端时，单列输出或多列输出是不确定的。可以分别 用选项“ -1 ” 或“ -C ”来强制按单列或多列输出。-C     多列输出，纵向排序。-F     每个目录名加“ / ”后缀，每个 FIFO 名加“ | ”后缀， 每个可运行名加“ * ”后缀。-R     递归列出遇到的子目录。-a     列出所有文件，包括以 "." 开头的隐含文件。以上就是man帮助命令的讲解，相信你会爱上linux中的帮助命令的。这回该明白了，linux大神是如何记住那么多命令的吧！2、常见目录作用的探讨 
   
    
    选项 
    作用 
    
   
   
    
    / 
    根目录 
    
    
    /bin 
    命令保存目录（普通用户就可以读取的命令） 
    
    
    /boot 
    启动目录，启动相关文件 
    
    
    /dev 
    设备文件保存目录 
    
    
    /etc 
    配置文件保存目录 
    
    
    /home 
    普通用户的家目录 
    
    
    /lib 
    系统库保存目录 
    
    
    /mnt 
    系统挂载目录 
    
    
    /media 
    挂载目录 
    
    
    /root 
    超级用户的家目录 
    
    
    /tmp 
    临时目录 
    
    
    /sbin 
    命令保存目录（超级用户才能使用的目录） 
    
    
    /proc 
    直接写入内存 
    
    
    /sys 
     
    
    
    /usr 
    系统软件资源目录 
    
    
    /usr/bin 
    系统命令（普通用户） 
    
    
    /usr/sbin 
    系统命令（超级用户） 
    
    
    /var 
    系统相关文档内容 
    
   
 3、最常用的命令总结3.1、学习方法小结最常用的命令往往也是最基本的命令，这里也同样以增删改查（CURD）进行讲解。如果要人为的细分，这里给出一种学习的思路，可以按照如思维导图所示：当然也可以按照如下方式去总结：列举一些常用的命令，先做简单的介绍，在脑海中有个印象。下面继续做详细介绍。$ ls #查看文件和目录$ ll #等价于ls -l$ cat #查看具体内容$ cd #切换目录$ mkdir # 新建文件夹$ touch # 新建文件$ cp #复制文件$ mv #移动或者重命名文件$ vim #linux下的一种编辑文件的手段，文中会详细介绍。$ rm #删除文件$ chmod #赋予权限$ chown #改变文件所有者3.2、命令详细介绍ls命令，查看目录以及文件命令，下面不会全部展示出来，只展示一部分内容。#不带任何参数[root@cnwangk ~]# lsanaconda-ks.cfg  av  cangls.av  history.txt  scp_test#加上参数-l，使用较长格式列出信息[root@cnwangk ~]# ls -ldrwxr-xr-x  2 root root    23 1月   4 20:21 av-rw-r--r--  1 root root    10 1月   4 20:16 cangls.av# -a参数，不隐藏任何以. 开始的项目[root@cnwangk ~]# ls -a.  .bash_history  .bash_profile  .cache  .config ..  av  .bash_logout   .bashrc   cangls.av  .ssh  .viminfoll命令，是ls -l的缩略形式，相当于起了别名。以长格式列出信息，包含权限、文件所有者、日期、文件名。$ lldrwxr-xr-x  2 root root    23 1月   4 20:21 av-rw-r--r--  1 root root    10 1月   4 20:16 cangls.av-rwxr-xr-x  1 root root    78 1月  19 21:23 hello.shcat命令，查看文件的内容，新建了一个hello.sh脚本作为演示，展示脚本的内容。[root@cnwangk ~]# cat hello.sh#!/bin/bashecho "hello cangls"echo hello linuxecho create btrfs filesystemcd命令，这个就不用做过多介绍，大家都很熟悉这个命令了。#切换到opt目录下$ cd /opt#返回上一层$ cd ..#进入当前用户家目录$ cd ~mkdir命令，新建目录，新建一个cangls的合集目录。[root@cnwangk ~]# mkdir canglsList[root@cnwangk ~]# lsanaconda-ks.cfg  cangls.av  canglsList  hello.shtouch命令，新建一个cangls.avi文件$ touch cangls.avicp命令，复制命令，可以是单个文件也可以是目录。将cangls.avi文件复制到新建的canglsList目录中。[root@cnwangk ~]# cp cangls.avi /root/canglsList/[root@cnwangk ~]# ls /root/canglsList/ #查看复制后cangls文件集合目录cangls.avimv命令，移动或者重命名。当文件路径相同时，我们就会修改重命名；不同路径时，则为剪切。我将cangls.avi文件重命名为acngls.mp4。然后将cangls.mp4文件移动到canglsList目录下。[root@cnwangk ~]# mv cangls.avi cangls.mp4[root@cnwangk ~]# lsanaconda-ks.cfg  av  cangls.av  canglsList  cangls.mp4  hello.sh[root@cnwangk ~]# mv cangls.mp4 /root/canglsList/[root@cnwangk ~]# lsanaconda-ks.cfg  av  cangls.av  canglsList  hello.sh  history.txt  scp_test[root@cnwangk ~]# ls /root/canglsList/cangls.avi  cangls.mp4最终查看在/root/目录下cangls.mp4部件了，此时已经被我移动到canglsList集合目录中了。vim命令，这里做简单演示，下面会做详细的说明。输入hello cangls，使用cat展示内容。[root@cnwangk ~]# vim /root/canglsList/cangls.avi[root@cnwangk ~]# cat /root/canglsList/cangls.avihello canglsrm命令，删除命令。演示，删除cangls.av文件。[root@cnwangk ~]# ls #查看我有cangls.av这个文件anaconda-ks.cfg  av  cangls.av  canglsList  hello.sh[root@cnwangk ~]# rm cangls.av #删除，需要输入确认rm：是否删除普通文件 "cangls.av"？y[root@cnwangk ~]# rm -rf cangls.av  #强制删除，并递归删除，不需要确认[root@cnwangk ~]# lsanaconda-ks.cfg  av  canglsList  hello.shchmod命令，简单的介绍赋予权限命令，一般755和644比较常用的。给cangls.sh输入点内容，然后赋予权限。[root@cnwangk ~]# echo echo "hello cangls" > cangls.sh[root@cnwangk ~]# cat cangls.avhello cangls[root@cnwangk ~]# ll #查看cangls.sh脚本权限-rw-r--r--  1 root root    13 1月  19 22:50 cangls.sh[root@cnwangk ~]# chmod 755 cangls.sh[root@cnwangk ~]# ll #对比权限变为了rwx-rx-rx，对应数字就是755-rwxr-xr-x  1 root root    13 1月  19 22:50 cangls.sh#执行脚本cangls.sh[root@cnwangk ~]# ./cangls.shhello canglschown命令，改变文件所有者，将cangls.sh文件所以者从root改为test用户。[root@cnwangk ~]# chown test cangls.sh[root@cnwangk ~]# ll-rwxr-xr-x  1 test root    18 1月  19 22:55 cangls.sh个人根据多年经验总结，认为工作中最最最常用的一些命令，以上就列举这么多了。还有其它常用命令，请接着往下阅读。4、其它常用命令4.1、 挂载命令格式mount [-t 文件系统] [-o 特殊选项] 设备文件名 挂载点 
   
    
    参数 
    作用 
    
   
   
    
    -t 
    文件系统，加入系统文件类型来指定挂载的类型，可以是ext3、ext4、iso9660、xfs、btrfs等文件系统 
    
    
    -o 
    特殊选项，可以指定挂载的额外选项 
    
   
 4.2、查询与挂载查询系统中已经挂载的设备，mount命令。#查询系统中已经挂载的设备$ mount#列举我自己测试环境下已经挂载的部分设备，Redhat7系列#我测试使用是btrfs文件系统/dev/sdb2 on /data type btrfs (rw,relatime,space_cache,subvolid=5,subvol=/)#系统默认挂载所使用文件系统格式xfs/dev/sda2 on /home type xfs (rw,relatime,attr2,inode64,noquota)/dev/sda1 on /boot type xfs (rw,relatime,attr2,inode64,noquota)上面列举我自己测试环境下已经挂载的部分设备，Redhat7系列。顺带一提，Redhat7开始推荐使用xfs文件系统，我所演示的也包含了xfs文件系统挂载的，同样也有上面介绍过的btrfs文件系统。部分参数说明，如下表格所示： 
   
    
    参数 
    作用 
    
   
   
    
    mount -a 
    依据配置文件/etc/fstb的内容，自动挂载 
    
    
    atime/noatime 
    更新访问时间/不更新访问时间。访问分区文件时，是否更新文件的访问时间，默认为更新。 
    
    
    async/sync 
    异步/同步，默认为异步 
    
    
    auto/noauto 
    自动/手动，执行mount -a命令时，是否会自动安装/etc/fstb文件内容挂载，默认自动。 
    
    
    defaults 
    定义默认值，相当于rw，suid，dev，exec，auto，nouser，async这七个选项。 
    
    
    exec/noexec 
    执行/不执行，设定是否允许在文件系统中执行可执行文件，默认exec允许。 
    
    
    remount 
    重新挂载已挂载的文件系统，一般用于指定修改特殊权限。 
    
    
    rw/ro 
    读写/只读，文件系统挂载时，是否具有读写权限，默认rw。 
    
    
    suid/nosuid 
    具有/不具有suid权限，设定文件系统是否具有suid和sgid的权限，默认具有。 
    
    
    user/nouser 
    允许/不允许普通用户挂载，设定文件系统是否允许普通用户挂载，默认不允许，只有root可以挂载分区。 
    
    
    usrquota 
    写入代表文件系统支持用户磁盘配额，默认不支持。 
    
    
    grpquota 
    写入代表文件系统支持组磁盘配额，默认不支持。 
    
   
 关于磁盘挂载，如果感兴趣的话，可以参考我在github或者gitee上整理的文章。在代码库中的linux文件夹中，同样整理了PDF文件格式的文章便于阅读，目前还在整理完善中。个人github仓库地址，一般会先更新PDF文件，然后再上传markdown文件。如果访问github太慢，可以访问gitee进行克隆。https://github.com/cnwangk/SQL-study4.2.1、挂载光盘首先建立挂载点，命令如下：$ mkdir /mnt/cdrom/挂载光盘，这里说明下：只是习惯在mnt下建立，media下建立也行。简单介绍：/dev/sr0是要挂载的文件，/mnt/cdrom是挂载存储的磁盘路径$ mount -t iso9660 /dev/cdrom /mnt/cdrom/$ mount /dev/sr0  /mnt/cdrom/卸载命令，设备文件名或者挂载点，比如卸载新增磁盘挂载的sdb$ umount /dev/sdb4.2.2、挂载U盘查看U盘设备文件名，fdisk -l查看磁盘列表$ fdisk -l$ mount -t vfat /dev/sdb1 /mnt/usb/4.3、用户登录查看命令查看用户登录信息$ w[root@cnwangk ~]# w21:31:12 up  1:39,  1 user,  load average: 0.00, 0.04, 0.05USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHATroot     pts/0    192.168.245.1    19:52    0.00s  0.28s  0.02s w如上所示，输入w命令查看到我的登录信息。只有1个用户，我用ssh登录的，本机虚拟机中并没有登录。命令输出如下所示：4.3.1、命令输出参数说明，作用如下表格所示： 
   
    
    参数 
    作用 
    
   
   
    
    USER 
    登录的用户名 
    
    
    TTY 
    登录终端 
    
    
    FROM 
    从哪个IP地址登录 
    
    
    LOGIN@ 
    登录时间 
    
    
    DILE 
    用户闲置时间 
    
    
    JCPU 
    与该终端连接的所有进程占用的时间。这个时间里并不包括过去的后台作业时间，但包括当前正在运行的后台作业占用时间 
    
    
    PCPU 
    当前进程所占用时间 
    
    
    WHAT 
    当前正在运行的命令 
    
    
    w 
    查询登录用户，显示系统时间和运行时间，用户个数以及平均负载。 
    
   
 4.3.2、查看登录用户信息命令输出：用户名，登录终端，登录时间（登录来源IP地址）#查看用户信息$ who[root@cnwangk ~]# who  #查看当前用户信息root     pts/0        2022-01-19 19:52 (192.168.245.1)#查看当前用户$ whoami #查看当前用户身份是root[root@cnwangk ~]# whoamiroot查看到当前用户为root，登录终端pts/0，登录时键与IP：2022-01-19 19:52 (192.168.245.1)，虚拟机搭建的环境。查询当前登录和过去登录的用户信息last命令默认读取/var/log/wtmp文件数据 。命令输出：用户名，登录终端，登录IP，登录时间，退出时间（在线时间）$ lastroot     tty1                          Sun Jan  5 21:47 - 21:50  (00:02)reboot   system boot  3.10.0-514.el7.x Sun Jan  5 21:44 - 21:59 (7+00:15)可以看到记录的我最久远的一次登录信息，时间确实有点久了，基本上很晚才使用的。查看所有用户最后一次登录时间#lastlog命令默认读取/var/log/lastlog文件内容#命令输出：用户名，登录终端，登录IP，最后一次登录时间$ lastlog[root@cnwangk ~]# lastlog用户名           端口     来自               最后登陆时间root            pts/0   192.168.245.1      三 1月 19 22:52:46 +0800 2022bin                                        **从未登录过**上面的中文显示，我在安装的时候选择了简体中文版，对于初学者来说简直太友好了。查看网络状态 ，一般比较关注的是ESTABLISHED状态$ netstat -an | grep ESTABLISHED[root@cnwangk ~]# netstat -an | grep ESTABLISHEDtcp        0      0 192.168.245.131:22      192.168.245.1:3579      ESTABLISHED4.4、解压缩命令只介绍一些常用的，比如压缩命令zip、gzip；解打包命令tar。4.4.1、压缩命令例如：zip、gzip。将canglsAVList压缩成canglsAVList.zip格式，将bolsAVList压缩成bolsAVList.gz格式。zip -r canglsAVList > cangls.zipgzip -c bolsAVList > bolsAVList.gz4.4.2、解打包命令tar解压一个redis的源码包$ tar -zxvf redis-6.0.8.tar.gz打包命令tar -zcvf，将redis-6.0.8-bak打包成tar包$ tar -zcvf redis-6.0.8-bak > redis-6.0.8-bak.tar然后再将redis-6.0.8-bak.tar压缩成.gz格式$ gzip redis-6.0.8-bak.tar > redis-6.0.8-bak.tar.gz4.5、搜索命令4.5.1、locate命令locate命令后面只能接文件名，例如，咱搜索一下cangls的文件。嚯，还不少啊：locate cangls[root@cnwangk opt]# locate cangls/root/cangls.av/root/cangls.sh/root/canglsList/root/canglsList/cangls.avi/root/canglsList/cangls.mp4locate命令所搜索的后台命令，不是及时更新，这时可以使用updatedb命令更新：$ updatedblocate命令配置文件/etc/updatedb.conf配置文件
  PRUNE_BIND_MOUNTS：开启搜索限制 
  PRUNEFS=""：不搜索的系统文件 
  PRUNENAMES=""：不搜索的文件类型 
  PRUNEPAEHS=""：不搜索的路径
 4.5.2、命令搜索命令命令搜索命令，比如wheris、which以及find命令。此处，着重讲一下find命令的使用：不区分大小写，搜索cangls.sh脚本$ find /root -iname cangls.sh按照所有者搜索$ find /root -user root查找10天前修改的文件find /var/log  -mtime +10查找/etc目录下大于1M的文件find /etc -size +1M查找i节点为26267295的文件，直呼内行，啥时候新增了个bols的小电影。[root@cnwangk ~]# find . -inum 26267295./bolsList查找/etc/目录下大于100KB且小于200KB的文件find /etc -size +100k -a -size -200k
  -a相当于and，逻辑与，两个条件都满足 
  -o相当于or，逻辑或，两个条件满足一个即可
 查找/etc/目录下大于100KB且小于200KB的文件，并且显示详细信息#-exec/-ok 命令#{}\;对搜索结果执行操作find /etc -size +100k -a -size -200k -exec ls -lh {} \;grep字符串搜素命令
  grep [选项] 字符串 文件名，在文件当中匹配符合的字符串 
  -i，忽略大小写 
  -v，排除指定字符串
 根据文件大小匹配，anaconda-ks.cfg文件时Redhat系列安装就自带的文件。$ grep "size" anaconda-ks.cfgpart swap --fstype="swap" --ondisk=sda --size=2000part /boot --fstype="xfs" --ondisk=sda --size=200part / --fstype="xfs" --ondisk=sda --size=16278part /home --fstype="xfs" --ondisk=sda --size=2000find与grep的区别
  find命令：在系统当中搜索符合条件的文件名，如需匹配，使用通配符，通配符是完全匹配。 
  grep命令：在文件当中搜索符合条件的字符串，如需匹配，使用正则表达式进行匹配，正则表达式是包含匹配。
 5、关机与重启命令5.1、关机命令一般而言关机和重启命令都不会赋予权限给普通用户，只有root用户才有权限执行。$ shutdown# shutdown -h now #立即关机 
   
    
    参数 
    作用 
    
   
   
    
    -c 
    取消前一个关机命令 
    
    
    -h 
    关机 
    
    
    -r 
    重启 
    
   
 其它关机命令：halt，poweroff，init 0注意：使用服务器时，不要随便去使用关机命令。一旦使用了，会造成不必要的麻烦。5.2、重启命令一般而言关机和重启命令都不会赋予权限给普通用户，只有root用户才有权限执行。#重启命令1,立即重启，同样可以接指定世界以及间隔多久重启$ shutdown -r now#重启命令2,立即重启$ reboot注意：使用logout命令登出shell，养成良好的习惯退出登录其它重启命令：reboot，init 603 第三夜第二夜的知识有点多，小白还有点没消化过来。cangls：小白，你来啦。我白吗？我大吗？我好看吗？别走了，我这里...小白：啥？一脸懵逼...此时小白的内心真实想法：不要以为我不懂，咱为学习忍了。真的又大又白，天天诱惑我。cangls：不逗你玩了，咱回到正题，昨天的知识点有点多，希望下去好好消化。今天会带来linux进阶方面的小技巧。小白：点了点头，认真的聆听着。三、进阶常用1、scp命令1.1、语法usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file][-l limit] [-o ssh_option] [-P port] [-S program][[user@]host1:]file1 ... [[user@]host2:]file21.2、使用方法简单来看：scp [可选参数] 本地文件 目标目录scp /root/av/local_file.av  remote_username@ip:/root/avscp [可选参数] 本地目录 目标目录scp -r /root/av/  remote_username@ip:/root/命令格式介绍#复制文件格式,本地到远程服务器scp local_file remote_username@remote_ip:remote_directory#或者scp local_file remote_username@remote_ip:remote_file#或者scp local_file  remote_ip:remote_directory#或者scp local_file remote_ip:remote_file复制目录命令格式#复制命令格式,本地到远程服务器scp -r local_directory remote_username@remote_ip:remote_directory#或者scp -r local_directory remote_ip:remote_directory详细操作，请参考的博文：【SCP命令】安全又快捷的linux小技巧scp命令2、路由命令以下是对一些常用的路由命令（网络配置工具）进行简单的介绍。2.1、ifconfig命令，展示内容如下：tips：我们判断网络环境的时候，dropped参数值是很重要的，一般正常状态是0，如果掉包数字则会上升。[root@cnwangk ~]# ifconfigdocker0: flags=4099  mtu 1500inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255ether 02:42:38:38:ab:fe  txqueuelen 0  (Ethernet)RX packets 0  bytes 0 (0.0 B)RX errors 0  dropped 0  overruns 0  frame 0TX packets 0  bytes 0 (0.0 B)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens33: flags=4163  mtu 1500inet 192.168.245.131  netmask 255.255.255.0  broadcast 192.168.245.255inet6 fe80::b314:8248:917a:d808  prefixlen 64  scopeid 0x20ether 00:0c:29:47:be:5f  txqueuelen 1000  (Ethernet)RX packets 14160  bytes 1053042 (1.0 MiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 7652  bytes 713027 (696.3 KiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73  mtu 65536inet 127.0.0.1  netmask 255.0.0.0inet6 ::1  prefixlen 128  scopeid 0x10loop  txqueuelen 1  (Local Loopback)RX packets 1474  bytes 91198 (89.0 KiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 1474  bytes 91198 (89.0 KiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0ifconfig最常见的作用就是看设置的ip地址以及dns和网关，其实就是看网卡设置的参数。当你看到docker的时候，没错，我安装了docker环境。2.2、ip命令使用，如下所示：[root@cnwangk ~]# ip addr list1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever2: ens33:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether 00:0c:29:47:be:5f brd ff:ff:ff:ff:ff:ffinet 192.168.245.131/24 brd 192.168.245.255 scope global noprefixroute ens33valid_lft forever preferred_lft foreverinet6 fe80::b314:8248:917a:d808/64 scope link noprefixroutevalid_lft forever preferred_lft forever3: docker0:  mtu 1500 qdisc noqueue state DOWN group defaultlink/ether 02:42:38:38:ab:fe brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft forever#ip命令同样可以配合route命令使用[root@cnwangk ~]# ip route listdefault via 192.168.245.2 dev ens33 proto static metric 100172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1192.168.245.0/24 dev ens33 proto kernel scope link src 192.168.245.131 metric 100ip命令同样可以配合route命令使用，单独使用route命令同样可以起到配置作用。下图是我之前制作的一个简单的思维导图，本来是要放在防火墙知识里面的，现在同样适用。没有放原图，原图太大了，缩小了一点也同样能看清楚哟！3、防火墙命令这里，我只介绍firewalld命令行模式，关于详细操作说明请参考博文：【Redhat系列linux防火墙工具】firewalld与iptables防火墙工具的激烈碰撞1.1、区域选择当前操作系统安装完成后，防火墙会设置一个默认区域，将接口加入到默认区域中。用户配置防火墙的第一步是获取默认区域并修改，关于操作如下：查看当前系统中所有区域firewall-cmd --get-zones查看当前默认的区域firewall-cmd --get-default-zone查看当前已激活的区域firewall-cmd --get-active-zones获取接口ens33所属区域firewall-cmd --get-zone-of-interface=ens33修改接口所属区域firewall-cmd --permanent --zone=internal --change-interface=ens331.2、firewalld服务管理重新加载防火墙配置firewall-cmd --reload重启防火墙(redhat系列)systemctl restart firewalld.service临时关闭防火墙systemctl stop firewalld.service开机启用防火墙systemctl enable firewalld.service开机禁止防火墙systemctl disable firewalld.service查看firewalld的运行状态firewall-cmd --state1.3、firewalld开放端口公共区域（public）设置开放21端口永久生效并写入配置文件（参数：--permanent）#参数：--permanent，设置即立刻生效并且写入配置文件firewall-cmd --zone=public --add-port=21/tcp --permanent查询防火墙端口21是否开放firewall-cmd --zone=public --query-port=21/tcp移除开放的端口21firewall-cmd --zone=public --remove-port=21/tcp --permanent1.4、区域规则修改查询防火墙规则列表firewall-cmd --zone=public --list-all新增一条区域规则httpd服务firewall-cmd --permanent --zone=internal --add-service=http验证规则firewall-cmd  --zone=internal --list-all4、进程相关命令进程相关命令主要介绍四个
  ps -aux | grep [服务名] 
  ps -ef | grep [服务名] 
  ps -le | grep [服务名] 
  top
 如果没有安装httpd服务，Redhat系列可以使用yum命令进行安装，在Ubuntu系列可以通过apt install。apt 是 Debian 和 Ubuntu 中的 Shell 前端软件包管理器。$ yum -y install httpd查看进程常用的ps命令，以httpd进程进行演示。这里只介绍工作中比较实用的。#使用-ef参数查看httpd进程$ ps -ef | grep httpd[root@cnwangk ~]# ps -ef | grep httpdroot      1329     1  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2216  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2218  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2219  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2220  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2221  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2222  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDroot      2276  2226  0 13:38 pts/0    00:00:00 grep --color=auto httpd#使用-aux参数查看httpd进程$ ps -aux | grep httpd[root@cnwangk ~]# ps -ef | grep httpdroot      1329     1  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2216  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2218  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2219  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2220  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2221  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDapache    2222  1329  0 13:37 ?        00:00:00 /usr/sbin/httpd -DFOREGROUNDroot      2276  2226  0 13:38 pts/0    00:00:00 grep --color=auto httpd#以长格式查询httpd进程$ ps -le | grep httpd[root@cnwangk ~]# ps -le | grep httpd4 S     0  1329     1  0  80   0 - 104198 poll_s ?       00:00:00 httpd5 S    48  2216  1329  0  80   0 - 70677 poll_s ?        00:00:00 httpd5 S    48  2218  1329  0  80   0 - 105278 SYSC_s ?       00:00:00 httpd5 S    48  2219  1329  0  80   0 - 105278 ep_pol ?       00:00:00 httpd5 S    48  2220  1329  0  80   0 - 105278 SYSC_s ?       00:00:00 httpd5 S    48  2221  1329  0  80   0 - 105278 SYSC_s ?       00:00:00 httpd5 S    48  2222  1329  0  80   0 - 105278 SYSC_s ?       00:00:00 httpd查看进程，当然top命令也应该了解，不带任何参数就能看到一些进程相关的。比如服务器当前时间、运行天数、用户数量、负载均衡、任务总数、多少进程在运行和休眠、停止以及僵尸进程zombie、cpu的利用率、内存占用情况以及缓存、缓冲的情况。查看直接使用top即可，退出按q键。$ toptop - 13:41:24 up 5 min,  1 user,  load average: 0.06, 0.28, 0.16Tasks: 193 total,   1 running, 192 sleeping,   0 stopped,   0 zombie%Cpu(s):  0.3 us,  0.7 sy,  0.0 ni, 98.7 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 stKiB Mem :  1877588 total,   940396 free,   481804 used,   455388 buff/cacheKiB Swap:  2047996 total,  2047996 free,        0 used.  1235960 avail Mem查看进程，pstree命令也必不可少，以树状结构展示出了我部署的vsftpd以及监控系统服务zabbix。$ pstree├─vsftpd├─zabbix_agentd───5*[zabbix_agentd]├─zabbix_proxy└─zabbix_server───33*[zabbix_server]进程实在无法正常结束，那就采取暴力手段kill命令，强行关闭。$ kill -1 3033 #重启进程$ kill -9 3034   #强制杀死进程关于进程的就讲这么多，讲太多了不好消化，更多详细描述可以参考本人的历史博文。5、系统权限系统权限，如果非要分类，大致可分为：基本权限、特殊权限。权限分配原则：对文件来讲：最高权限为x（执行）；对目录来讲：最高权限为w（写）。接着以cangls这个文件进行演示，分别带你看权限用数字的代表含义，rwx加起来就是7：
  r 对应的数字权限为：4，读权限 
  w 对应的数字权限为：2， 写权限 
  x 对应的数字权限为：1，执行权限
 [root@cnwangk ~]# chmod 711 cangls.av[root@cnwangk ~]# ll cangls.av-rwx--x--x 1 root root 13 1月  19 22:49 cangls.av[root@cnwangk ~]# chmod 722 cangls.av[root@cnwangk ~]# ll cangls.av-rwx-w--w- 1 root root 13 1月  19 22:49 cangls.av[root@cnwangk ~]# chmod 744 cangls.av[root@cnwangk ~]# ll cangls.av-rwxr--r-- 1 root root 13 1月  19 22:49 cangls.av通过上面的演示对cangls.av这个文件赋予权限711、722、744进行测试。711对应的权限-rwx--x--x、722对应的权限-rwx-w--w-、744对应的权限：-rwxr--r--，当然这样设置是没有意义的，为了演示进行测试演示数字代表的含义。tips：还有一种方式是ugo模式，作为了解就行。04 第四夜cangls：还记得前三天我们探讨了哪些linux方面的知识吗？小白：当然记得，我都记在笔记本上了，下面进行了复述：
  学习方法； 
  linux基本命令，最重要的是帮助命令的运用； 
  linux进阶的小技巧，比如：scp安全文件传输命令、路由命令、firewalld防火墙命令等等； 
  linux进程相关命令：ps -ef、ps -aux、top； 
  linux系统权限命令：chmod。
 cangls：接下来会有一点小插曲，对服务器部署项目的一些知识进行讲解，比如Javaweb项目。小白：好耶，我很感兴趣！四、Java相关基于实际工作中的运用，介绍一些web项目和服务器相关的知识。当你看到我的文章或多或少会出现Java相关的知识的时候，请不要惊讶。我其实是一个蹩脚Java码农，就是这么神奇。好吧，我承认自己连半吊子都算不上，只是有一段时间的CURD经验。而在Linux上操作的经验反而比我主学的Java经验还要丰富，得益于多年的自学以及与服务器和虚拟机打交道。1、jar包服务和war包服务将Java程序通过中间件在后台运行，&符号就是将程序放入后台执行$ java -jar demo-1.0.jar &jar包或者war包在中间件后台运行，优化版本，将日志输出到指定文件demo-1.0.log。jvm在client模式下运行，默认Xmx大小为64M，而在server模式下默认Xmx大小为1024M，默认Xms大小为1M，而在server模式下默认Xms大小为128M。$ nohup java -server -Xms256M -Xmx2048M -jar demo-1.0.jar &> demo-1.0.log &当你遇到控制台日志输出乱码的时候，此时不要慌，请冷静思考。当然有解决方案，那就是在控制台执行Java -jar命令时指定固定的编码，比如utf-8编码。$ java -jar -Dfile.encoding=utf-8 demo-1.0.jar &$ nohup java -server -Xms256M -Xmx2048M -jar -Dfile.encoding=utf-8 demo-1.0.jar &> demo-1.0.log &个人建议：基于实际工作处理。再怎么去优化，机器始终是机器，内存始终要消耗。如果不能释放，需要采取人为的干预手段，比如定期重启服务器。很多问题找了很多原因依旧解决不掉，但是重启服务器就迎刃而解了，就是这么神奇。2、tomcat中间件优化限制堆内存，具体根据服务器和真机的内存计算优化，下面知识给出示例值。$ set JAVA_OPS = -Xms800m -Xmx1024m -XX:PermSize=800m -XX:MaxPermSize=1024mhttps自签证书配置谈到tomcat中间件，一般自然而然的就联想到nginx中间件。一般不建议直接在tomcat中直接配置，反而使用nginx做一层反向代理，然后在nginx中设置ssl。nginx中间件配置简单介绍负载均衡，可以通过加权重实现轮询。   upstream tomcat {server 192.168.0.233:8080;server 192.168.0.233:8888;server 192.168.0.233:9999;}配置ssl参考server{listen 80;listen 443 ssl;server_name 192.168.245.130;#ssl set begin#优雅的编写rewrite规则#rewrite ^ https://www.nginx.org$request_uri?;#重定向转发到https#proxy_redirect http:// $scheme://;#301重定向#return  301 https://$server_name$request_uri;#http请求重定向到https请求,非标准433端口采用#error_page 497  https://$host$uri?$args;#ssl 设置off或者屏蔽ssl off;ssl_certificate ssl/server.crt;#服务端证书ssl_certificate_key ssl/server.key;#服务端私钥ssl_session_cache shared:SSL:1m;#设置共享会话缓存大小ssl_session_timeout 5m;#配置session有效时间5分钟ssl_prefer_server_ciphers on;#优先采取服务器算法ssl_protocols TLSv1 TLSv1.1 TLSv1.2;#启用指定协议#加密算法ssl_ciphers  EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;#ssl_verify_client on;# 开启客户端证书校验#ssl_client_certificate ssl/ca.crt;#设置验证客户端证书#ssl_verify_depth 6; #校验深度#ssl_trusted_certificate ssl/ca.crt;#设置CA为受信任证书#ssl set endlocation / {#配置proxy_set_header请求头proxy_pass_header User-Agent;proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto https;proxy_pass http://tomcat;proxy_redirect http:// https://;}3、国产中创中间件优化解决JDK不完整的两种方案：
  第一种：下载完整版的JDK； 
  第二种：使用as内部自带的编译器，如下所示进行调整。
 找到java-config配置那一栏，在加入如下参数。-Dorg.apache.jasper.compiler.disablejsr199=true或者修改as/domains/domain1/config/目录下的domain.xml，将false修改为true。-Dorg.apache.jasper.compiler.disablejsr199=false05 第五夜经过前四夜的深入探讨，此时的小白已经具备了一些linux基本知识的运用，对于项目上线和维护也有了一定的了解。cangls：相信小白同学现在已经对linux基本知识有了一定的了解，并能够运用到工作中。小白：cangls，这还是得感谢您的细心教导，是有那么一丢丢的成就感。cangls：学习就是要有这种劲头，好样的！今天再给你传授我多年珍藏的独家秘笈：vim工具的使用。小白：好耶，独家秘笈？莫非是九阳神功，还是玉女心经？表现出满怀期待的样子。cangls：想啥呢？是linux中的编辑神器，用好了vim对你的工作有大大大的好处哟！小白：原来如此，开始拿出了自己的小本本记录...五、vim的使用1、vim简单使用接着上面的例子hello.sh脚本继续讲。$ vim hello.sh  #开始编辑脚本在hello.sh脚本中写入一段内容：tips：进入后按 i 键进行插入内容。#!/bin/bashecho "hello cangls"echo hello linuxecho create btrfs filesystem按ESC，输入:wq保存退出，然后执行脚本：[root@cnwangk ~]# ./hello.shhello canglshello linuxcreate btrfs filesystem执行脚本，会发现刚刚通过vim输入的hello cangls已经生效了。如果没有权限，通过root用户赋予权限：#赋予读和执行权限chmod 755 /hello.sh2、玩转vim凭个人使用经验总结一些常用到的快捷键命令 
   
    
    参数 
    作用 
    
   
   
    
    i 
    进行编辑，插入内容 
    
    
    :wq 
    保存并退出 
    
    
    :q! 
    不保存并退出 
    
    
    shirt + pgup 
    上翻页 
    
    
    shift + pgdown 
    下翻页 
    
    
    / 
    搜索内容 
    
    
    :set number 
    显示行数 
    
    
    ESC 
    退出编辑 
    
   
 更多命令参数可以参考，man vim，强大的帮助命令man。附上一个vim的键盘图，来自菜鸟教程，可以去菜鸟教程下载原图。06 第六夜经过前五夜的连续战斗，小白依旧斗志昂扬。cangls：小白同学啊，看你今天似乎遇到什么难题了吧！小白：是的，我最近阅读了linux shell相关的文章，但是有很多疑惑。cangls：能具体描述一下吗？小白：是这样的，对基本知识和用法有些困惑。cangls：没关系，今天正是要给你传授shell方面的基本知识，希望对你有所帮助。小白：此时拿出了小本本开始记录着...六、shell脚本1、shell概述
  shell的两种主要语法类型有Bourne和C，这两种语法彼此不兼容。Bourne家族主要包括：sh、ksh、Bash、psh、zsh； 
  C家族主要包括：csh、tcsh。
 Bash中其它特殊符号，如下表格所示： 
   
    
    选项 
    符号含义 
    
   
   
    
    ' ' 
    在单引号中所有特殊符号，如"$"和"`"(反引号)都没有特殊含义 
    
    
    " " 
    双引号。在双引号中所有特殊符号除"$"、"、"、"\"外都无特殊含义。"$"、"、"、""拥有"调用变量的值"、"引用命令"和"转义符"的含义 
    
    
    `` 
    反引号括起来的是系统命令，在Bash中会优先执行它。和$()作用一样，推荐使用$()，反引号容易误导。 
    
    
    $() 
    与反引号作用相同，用来引用系统命令。 
    
    
    # 
    在shell脚本中，#代表注释。 
    
    
    $ 
    用于调用变量的值，如果需要调用name的值时，需要使用$name获取变量的值。 
    
    
    \ 
    转义符，跟在\之后的特殊符号将失去特殊含义，变为普通字符。例如：$将输出"$"符号，则不会作为变量引用。 
    
   
 2、shell脚本基本编写#编写一个简单的linux脚本，使用vim命令vim /home/hello.sh#注意一个标准的shell脚本必须加上：#!/bin/bash#!/bin/bashecho "hello world"  >> /root/hello.log #将hello world追加到hello.log这个文件中#赋予读和执行权限chmod 755 /hello.sh#使用 sh hello.sh 命令执行sh hello.sh && ./hello.sh3、别名与快捷键3.1、查看与设定别名alias 别名 = '原命令'，设定命令别名，当然这样设置只会临时生效。alias 命令，查看系统命令中所有的命令别名，例如我个人安装的系统别名查看如下：alias cp='cp -i'alias egrep='egrep --color=auto'alias fgrep='fgrep --color=auto'alias grep='grep --color=auto'alias l.='ls -d .* --color=auto'alias ll='ls -l --color=auto'alias ls='ls --color=auto'alias mv='mv -i'alias rm='rm -i'alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'别名永久生效与删除别名写入环境变量配置文件，永久生效。#写入当前用户的环境变量，Ubuntu下可以这样设置$ vi ~/.bashrc#Redhat7系列[root@cnwangk ~]# vi ~/.bash_profile上面分别介绍了Ubuntu下的环境变量和Redhat7系列的当前用户环境变量修改。我之前也有写过博文，在这篇文章中：【linux环境变量】秒懂linux配置全局与当前用户环境变量，同样也上传到了我的github和gitee仓库，微信公众号也有发布哟。删除别名$ unalias 接别名命令生效顺序
  第一顺位执行用绝对路径或相对路径执行的命令 
  第二顺位执行别名 
  第三顺位执行Bash的内部命令 
  第四顺位执行按照$PATH环境变量定义的目录查找顺序找到的第一个命令
 4、 历史命令直接在终端输入history命令，就可以看到自己输入的历史命令。$ historyhistory [选项][历史命令保存文件]
  -c：清空历史命令 
  -w：把缓存中的历史命令写入历史命令保存文件~/.bash_history
 历史命令的调用
  使用上、下箭头调用以前的历史命令 
  使用"!n"重复执行第n条命令 
  使用"!!"重复执行上一条命令 
  使用"!字符串"重复执行最后一条以该字符串开头的命令
 5、输出重定向最基本的echo用法演示，将hello world输出到hello.sh脚本中，如果对echo命令不熟悉，可以使用我上面介绍过的man帮助命令进行查找。例如：$ man echo-e参数介绍：支持反斜线控制的字符转换$ echo "hello world" > hello.sh[root@cnwangk ~]# cat hello.shhello world#输入一段字符串到hello.sh脚本[root@cnwangk ~]# echo -e "echo "hello linux"\necho "create btrfs filesystem"" > hello.sh[root@cnwangk ~]# chmod 755 hello.sh  #赋予755权限[root@cnwangk ~]# sh hello.sh  #执行脚本hello linuxcreate btrfs filesystem控制字符作用，如下表格所示： 
   
    
    参数 
    作用 
    
   
   
    
    \a 
    输出警告音 
    
    
    \b 
    退格键，向左删除 
    
    
    \n 
    换行符 
    
    
    \r 
    回车键 
    
    
    \t 
    制表符，TAB键 
    
    
    \v 
    垂直制表符 
    
    
    \0nnn 
    按照八进制ASCII码输出字符。其中0为数字零，nnn为三位八进制数。 
    
    
    \xhh 
    按照十六进制ASCII码输出字符。hh是两位十六进制数。 
    
   
 例如，表示以追加形式将苍老师输出到av文件中。嘿嘿，咱就骚一下。echo "cangls" >> av.avi标准输出重定向，作用如下表格所示： 
   
    
    命令格式 
    作用 
    
   
   
    
    命令 > 文件 
    以覆盖的方式，把命令的正确输出到指定的文件或设备当中 
    
    
    命令 >> 文件 
    以追加的方式，把命令的正确输出到指定的文件或设备当中 
    
    
    错误命令 2> 文件 
    以覆盖的方式，把命令的错误输出到指定的文件或设备当中 
    
    
    错误命令 2>> 文件 
    以追加的方式，把命令的错误输出到指定的文件或设备当中 
    
   
 正确输出和错误输出同时保存，作用如下表格所示： 
   
    
    命令格式 
    作用 
    
   
   
    
    命令 > 文件 2>&1 
    以覆盖的方式，把命令的正确和错误输出保存在同一个文件中 
    
    
    命令 >> 文件 2>&1 
    以追加的方式，把命令的正确和错误输出保存在同一个文件中 
    
    
    命令 &> 文件 
    以覆盖的方式，把命令的正确和错误输出保存在同一个文件中 
    
    
    命令 &>>文件 
    以追加的方式，把命令的正确和错误输出保存在同一个文件中 
    
    
    命令 >> 文件1 2>> 文件2 
    把正确的输出到文件1中，错误的输出到文件2中 
    
   
 wc命令wc [选项][文件名]，输出文件中的行数、单词数、行数示例，统计hello.sh的行数，统计有两行，与上面的演示对应起来了。$ wc -l[root@cnwangk ~]# wc -l hello.sh  #统计hello.sh的行数，统计有两行，与上面的演示对应起来了。2 hello.sh最后总结出实用的几种，以追加的形式把错误和正确的结果输出到文件中：
  命令 >> file 2>&1 
  命令 &>> file 
  命令 >> file1 2>> file2
 6、管道符6.1、命令格式，如下表格所示： 
   
    
    命令格式 
    作用 
    
   
   
    
    命令1 | 命令2 
    命令1的正确输出作为命令2的操作对象 
    
    
    ;，格式1：命令2 
    多个命令顺序执行，命令之间没有任何逻辑关系 
    
    
    &&，命令1&&命令2 
    逻辑与，当命令1正确执行，命令2才会执行；命令1无法正确执行，命令2不会执行 
    
    
    ||，命令1||命令2 
    逻辑或，当命令1非正确执行，命令2才会执行；命令1正确执行，命令2不会执行 
    
   
 6.2、linux中的通配符，部分整理如下表格所示： 
   
    
    参数 
    作用 
    
   
   
    
    * 
    匹配任意内容 
    
    
    ? 
    匹配任意一个字符 
    
    
    [] 
    匹配任意一个中括号内的字符，例如[abc]代表匹配一个字符，可能是a，也可能是b或c。 
    
    
    [-] 
    匹配中括号里的任意一个字符，-代表一个范围，例如：[a-z]代表匹配一个小写字母。 
    
    
    [ ^ ] 
    逻辑非，匹配不是中括号里的一个字符，例如：[^0-9]代表匹配一个非数字的字符。 
    
   
 续更新优化中...总结能看到这里的，都是帅哥靓妹。以上就是此次文章的所有内容的，希望能对你的工作有所帮助。感觉写的好，就拿出你的一键三连。如果感觉总结的不到位，也希望能留下您宝贵的意见，我会在文章中进行调整优化。原创不易，转载也请标明出处和作者，尊重原创。本文会不定期上传到gitee或者github以及发布到微信公众平台。我的微信公众号与其他平台昵称同样是龙腾万里sky。认准龙腾万里sky，如果看见其它平台不是这个ID发出我的文章，就是转载的。linux系列文章：linux小技巧scp命令、linux磁盘管理已经上传至github和gitee。个人github仓库地址，一般会先更新PDF文件，然后再上传markdown文件。如果访问github太慢，可以访问gitee进行克隆。https://github.com/cnwangk/SQL-study个人gitee仓库地址，一般会先更新PDF文件，然后再上传markdown文件。https://gitee.com/dywangk/SQL-studycangls和小白的对话并没有结束，在这个只有两人的操作间之中，到底发生了啥，请接着看。by 龙腾万里sky
		     (adsbygoogle = window.adsbygoogle || []).push({});
		新手如何入门linux，linux原来还可以这么学的</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12056.html">
<title>【Alibaba中间件技术系列】「Nacos技术专题」服务注册与发现相关的原理分析</title>
<link>https://www.ishiguang.cn/12056.html</link>
<dc:date>2022-01-22T19:40:16+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		背景介绍前几篇文章介绍了Nacos配置中心服务的能力机制，接下来，我们来介绍Nacos另一个非常重要的特性就是服务注册与发现，说到服务的注册与发现相信大家应该都不陌生，在微服务盛行的今天，服务是非常重要的，而在 Nacos 中服务更被称为他的一等公民。Nacos 支持几乎所有主流类型的 “服务” 的发现、配置和管理。服务 (Service)服务是指一个或一组软件功能（例如特定信息的检索或一组操作的执行），其目的是不同的客户端可以为不同的目的重用（例如通过跨进程的网络调用）。Nacos 支持主流的服务生态，如 Kubernetes Service、gRPC|Dubbo RPC Service 或者 Spring Cloud RESTful Service。nacos的架构图所示(dubbo) RPC微服务的基础架构图中的6个步骤的含义解释如下：
  服务容器负责启动，加载，运行服务提供者。 
  服务提供者在启动时，向注册中心注册自己提供的服务。 
  服务消费者在启动时，向注册中心订阅自己所需的服务。 
  注册中心返回服务提供者地址列表给消费者，如果有变更，注册中心将基于长连接推送变更数据给消费者。 
  服务消费者，从提供者地址列表中，基于软负载均衡算法，选一台提供者进行调用，如果调用失败，再选另一台调用。 
  服务消费者和提供者，在内存中累计调用次数和调用时间，定时每分钟发送一次统计数据到监控中心。
 服务注册中心 (Service Registry)上图中Registry就是注册中心，负责服务的注册与发现，Dubbo服务体系之前使用Zookeeper或者自己的Registry 实现，而 Nacos 则是另一种 Registry的实现。服务注册中心，它是服务，其实例及元数据的数据库（Dubbo3已经将源数据中心、配置服务全部提取独立出来了），服务实例在启动时注册到服务注册表，并在关闭时注销。服务和路由器的客户端查询服务注册表以查找服务的可用实例，服务注册中心可能会调用服务实例的健康检查 API 来验证它是否能够处理请求。服务元数据 (Service Metadata)服务元数据是指包括服务端点(endpoints)、服务标签、服务版本号、服务实例权重、路由规则、安全策略等描述服务的数据。逻辑架构及其组件介绍
  服务管理：实现服务CRUD，域名CRUD，服务健康状态检查，服务权重管理等功能 
  配置管理：实现配置管CRUD，版本管理，灰度管理，监听管理，推送轨迹，聚合数据等功能 
  元数据管理：提供元数据CURD 和打标能力 
  插件机制：实现三个模块可分可合能力，实现扩展点SPI机制 
  事件机制：实现异步化事件通知，sdk数据变化异步通知等逻辑 
  日志模块：管理日志分类，日志级别，日志可移植性（尤其避免冲突），日志格式，异常码+帮助文档 
  回调机制：sdk通知数据，通过统一的模式回调用户处理。接口和数据结构需要具备可扩展性 
  寻址模式：解决ip，域名，nameserver、广播等多种寻址模式，需要可扩展 
  推送通道：解决server与存储、server间、server与sdk间推送性能问题 
  容量管理：管理每个租户，分组下的容量，防止存储被写爆，影响服务可用性 
  流量管理：按照租户，分组等多个维度对请求频率，长链接个数，报文大小，请求流控进行控制 
  缓存机制：容灾目录，本地缓存，server缓存机制。容灾目录使用需要工具 
  启动模式：按照单机模式，配置模式，服务模式，dns模式，或者all模式，启动不同的程序+UI 
  一致性协议：解决不同数据，不同一致性要求情况下，不同一致性机制 
  存储模块：解决数据持久化、非持久化存储，解决数据分片问题 
  Nameserver：解决namespace到clusterid的路由问题，解决用户环境与nacos物理环境映射问题 
  CMDB：解决元数据存储，与三方cmdb系统对接问题，解决应用，人，资源关系 
  Metrics：暴露标准metrics数据，方便与三方监控系统打通 
  Trace：暴露标准trace，方便与SLA系统打通，日志白平化，推送轨迹等能力，并且可以和计量计费系统打通 
  接入管理：相当于阿里云开通服务，分配身份、容量、权限过程 
  用户管理：解决用户管理，登录，sso等问题 
  权限管理：解决身份识别，访问控制，角色管理等问题 
  审计系统：扩展接口方便与不同公司审计系统打通 
  通知系统：核心数据变更，或者操作，方便通过SMS系统打通，通知到对应人数据变更 
  OpenAPI：暴露标准Rest风格HTTP接口，简单易用，方便多语言集成 
  Console：易用控制台，做服务管理、配置管理等操作 
  SDK：多语言sdk 
  Agent：dns-f类似模式，或者与mesh等方案集成 
  CLI：命令行对产品进行轻量化管理，像git一样好用
 Nacos 的服务注册与发现服务提供方 (Service Provider)是指提供可复用和可调用服务的应用方。模拟服务注册服务注册最重要的就是将服务注册到哪里，在注册中心服务端，肯定有一个用来管理服务的容器，他保存着所有服务的实例。不需要知道该容器具体的实现细节，只需要知道有这样一个概念。
  将同一个服务的两个实例注册到 Nacos 中：
 
  双注册模式注入进入
 
  维持服务在线状态
 demo代码如下：通过 NamingService 接口的 registerInstance 方法就可以将服务进行注册了，该方法有很多重载的方法，这里我们选择一个简单的来调用就好了。注册完成后，通过调用 getAllInstances 方法，立即获取所有可用的实例，然后让主线程等待，打印如下：可以发现naming客户端成功获取到了两个实例。服务消费方 (Service Consumer)服务注册到注册中心后，服务的消费者就可以进行服务发现的流程了，消费者可以直接向注册中心发送获取某个服务实例的请求，这种情况下注册中心将返回所有可用的服务实例给消费者，但是一般不推荐这种情况。另一种方法就是服务的消费者向注册中心订阅某个服务，并提交一个监听器，当注册中心中服务发生变更时，监听器会收到通知，这时消费者更新本地的服务实例列表，以保证所有的服务均是可用的。Nacos消费服务机制是指会发起对某个服务调用的应用方。服务注册之后，服务的消费者就可以向注册中心订阅自己所需要的服务了，注册中心会将所有服务的实例“推送”给消费者，实际上获取服务是客户端主动轮询的，跟客户端获取配置中心的配置项的原理一样。现在我创建一个服务消费者，然后向注册中心订阅一个服务，当接收到注册中心返回的服务列表之后，执行5次 select 服务实例的操作，相当于进行一个模拟的服务请求，具体的代码如下图所示：其中的 printInstances 方法主要是打印出所有服务的实例，将 ServiceConsumer 类启动之后，打印出如下的日志：Nacos机制负载均衡负载均衡有很多中实现方式，包括轮询法，随机方法法，对请求ip做hash后取模等等，从负载的维度考虑又分为：服务端负载均衡和客户端负载均衡。Nacos 的客户端在获取到服务的完整实例列表后，会在客户端进行负载均衡算法来获取一个可用的实例，模式使用的是随机获取的方式。Nacos 服务注册与订阅的完整流程
  Nacos客户端进行服务注册有两个部分组成，一个是将服务信息注册到服务端，另一个是像服务端发送心跳包，这两个操作都是通过NamingProxy 和服务端进行数据交互的。 
  Nacos客户端进行服务订阅时也有两部分组成，一个是不断从服务端查询可用服务实例的定时任务，另一个是不断从已变服务队列中取出服务并通知 EventListener 持有者的定时任务，更新服务订阅列表。
 参考资料https://nacos.io/zh-cn/docs/feature-list.html
		     (adsbygoogle = window.adsbygoogle || []).push({});
		【Alibaba中间件技术系列】「Nacos技术专题」服务注册与发现相关的原理分析的</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12057.html">
<title>轻量级orm框架——gzero指南</title>
<link>https://www.ishiguang.cn/12057.html</link>
<dc:date>2022-01-22T19:40:16+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		开发过web系统人一定对大量的curd不陌生，为了提高效率我们通常会使用一些orm框架做辅助，而不会直接操作数据库。但是现有的orm框架往往有两个通病（各种语言的都一样）：1. API复杂：即使是有经验的开发人员在使用前还是需要先写出原始的SQL语句，再调用api。效率不高，排查问题也不够透明。如果使用原生SQL，通常就需要自己再写代码来处理结果集。2. 使用orm框架对数据库的操作粒度比较粗，有时候为了提高数据库的查询效率，明明一条语句能够完成的工作，通过框架会发送多条语句。这样也无形中增加了系统的负载，降低了系统的并发吞吐量。所谓我才想能够自己做一个框架，既能够让开发人员自由编写sql，同时又保持了orm的特性，将查询的结果集自动处理成我预先定义好的格式。关键，要使用方便，无外部依赖。经过了大概半个月的尝试，我终于写出了gzero。一、如何引入go get gitee.com/learnhow/gzero@v0.8.1目前的最新版本是v0.8.1，源码只有400行，做了一些简单的单元测试。后面也许会根据大家的反馈意见在这个版本的基础上进一步完善。二、开始使用1. 定义模型// 定义员工结构体，内部包含一个身份证信息和登录信息type Emp struct {ID        uint `zero:"primaryKey"`Name      stringJobNumber *stringILogin    Login         `zero:"prefix:login_"`IdCard    *IdentityCard `zero:"prefix:idcard_"`}

// 登录信息type Login struct {ID    uintCode  stringEmpFk uint}

// 身份证信息type IdentityCard struct {Code string}既然是orm就应该在我们的结构体内部体现出模型之间的关联关系，gzero通过primaryKey标识主键，在处理结果集的时候会根据主键判断，同时支持复合主键。主键字段不支持指针类型。2. 创建连接ctx := Open("mysql", "root:123456@tcp(127.0.0.1:13306)/helloworld?charset=utf8&parseTime=True&loc=Local", Cfg{})gzero内部调用database/sql，Ctx不是单例对象，你可以反复调用Open方法。但是*sql.DB只会被创建一次，目前我只是做了简单处理。3. 编写sql并安装进对象ctx.Sql("SELECT name, job_number FROM t_emp WHERE id = 1").Install(&emp)gzero默认结构体字段是驼峰类型，映射为表结构的蛇形字段。例如：JobNumber在数据库中对应job_number。你也可以通过“column”重新定义映射的字段名。如果多个结构体都包含同名的字段，你完全可以使用"prefix“为内部的结构体添加统一前缀（这个特点参考了gorm）。结果示例：三、获取多条结果集编写sql并安装进Slicevar emps []Empctx.Sql("SELECT id, name FROM t_emp").Install(&emps)多条结果集需要使用数组或切片来接收，结果示例：四、根据对象的层次结构处理数据代码：var emp []Empctx.Sql("SELECT e.id, e.name, e.job_number, l.emp_fk, l.code AS login_code FROM t_emp e, t_login l WHERE e.id = l.emp_fk").Install(&emp)查询出来的数据，gzero会根据结构体的层次对数据进行自动处理五、根据主键自动合并数据定义结构体：type Dept struct {ID   uint `zero:"primaryKey"`Name stringEmps []Emp `zero:"prefix:emp_"`}查询并安装数据：var depts []Deptctx.Sql("SELECT d.id, d.name, e.name AS emp_name, l.code AS login_code FROM t_dept d, t_emp e, t_login l WHERE d.id = e.dept_fk AND l.emp_fk = e.id").Install(&depts)结构体的前缀能够在sql语句中通过别名指定，查询结果如下：六、总结目前gzero功能非常简单，就是根据开发人员预先定义好的层次关系将查询的结果集进行处理。之后，我打算增加对象到sql生成的功能，进一步提升crud的开发效率。
		     (adsbygoogle = window.adsbygoogle || []).push({});
		轻量级orm框架——gzero指南的</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12055.html">
<title>Markdown最新使用说明</title>
<link>https://www.ishiguang.cn/12055.html</link>
<dc:date>2022-01-22T19:40:15+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		Markdown基本语法说明markdown 和 typora关系：typora是一款实时预览markdown的文本编辑器本文推荐使用的Markdown编辑器为：Typora (用了多款编辑器，觉得还是Typora更加简洁和实用)Typora下载地址在文章末尾，有需要的伙伴自取哦~整篇文章说明：
   若要使用markdown的标记符号则需在前加上一个反斜杠符号 
   符号和文本之间基本都需要一个空格来分开 
   全文的符号都必须是英文状态下的才行
  基本语法标题格式：#+空格+文字##+空格+文字###+空格+文字……【最多支持六个#，一个#相当与html中h1的大小，两个##相当与html中h2的大小，以此类推】粗体格式：**文本**斜体格式：*文本*若要斜体加粗则用三个星号 例：***文本***引用格式：>文本注意是一个大于号列表有序列表格式：
  A 
  B 
  C【数字+.+空格+文本】
 无序列表格式：
  first 
  second 
  third【减号+空格+文本】
 自定义列表格式：冒号+自定义的标记符例：:apple+文本onetwo任务列表格式：三个点号+test+回车 再在文本框内输入：- [] 文本例子：- [x] Write the press release- [√] Update the website- [ ] Contact the media代码单行代码格式：一个点号+单行代码+一个点号【点号是英文输入下的tab键上的那个键】例：代码有时候可以用单行代码的格式作为注释方式多行代码格式：
  三个点号+多行代码+三个点号 
  三个点号+代码语言（java or python or and so on) +回车
 【点号是英文输入下的tab键上的那个键】例：
  多行代码 
   ```java
 分割线格式：三个减号例：---超链接格式：[标题](网址)图片格式：![图片名字](图片的本地路径 or 网络路径)图片网络路径获取方法：
   对网页上的图片右击选择复制 ” 图像链接 “ 
   对网页上的图片右击选择 “ 审查元素 ” 从中找到所要的图片地址
  拓展语法表格格式：
  | 文本|文本||-- |-- || 文本|文本|| 文本|文本|
 第二行的--是为了分割第一行的标题行和下面的子行
  直接在typora中右键选择所要的表格规格
 删除线格式：两个波浪线+文本+两个波浪线例：~~文本~~ 效果：文本Emoji表情格式：：英文：例子：自动网址链接在默认情况下，markdown会自动将你输入的网址变成url链接禁用自动url链接方式：用反引号来保住这个链接http://www.example.com【这里的反引号就是前文所说的点号】Typora下载路径多台设备测试进入Typora官网 https://typora.io/ 下载发现已经进不去了，而且前不久就宣布1.0版本开始要收费所以就连忙下载了最新的免费版本。想要下载免费版本的小伙伴可自行下载：https://blog.csdn.net/ityoukown/article/details/122126625
		     (adsbygoogle = window.adsbygoogle || []).push({});
		Markdown最新使用说明的</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12054.html">
<title>Flink State Rescale性能优化</title>
<link>https://www.ishiguang.cn/12054.html</link>
<dc:date>2022-01-22T19:40:13+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		背景今天我们来聊一聊flink中状态rescale的性能优化。我们知道flink是一个支持带状态计算的引擎，其中的状态分为了operator state和 keyed state两类。简而言之operator state是和key无关只是到operator粒度的一些状态，而keyed state是和key绑定的状态。而Rescale，意味着某个状态节点发生了并发的缩扩。在任务不修改并发重启的情况下，我们只需要按照task，将先前job的各个并发的state handle重新分发处理下载远程的持久化的state文件即可恢复。而发生rescale时，状态的数据分布将发生变化，因此存在一个reshuffle的过程，那么我们就来看看这个rescale的实现是怎么做的，以及其问题和优化手段。​Rescale的实现2017年社区有一篇博客就比较深入的介绍了Operator 和 keyed state的rescale的实现，感兴趣的话可以去了解下。 这两张图对比了是否基于keyGroup来划区的一个差别，社区中的版本使用的是基于keygroup的版本实现的，可以看到可以减少对于数据的random的访问。但是从B中我们看到，以rescale后的subtask为例:​
  subtask-0: 需要将原先subtask-0的dfs文件下载后将KG-3的数据剔除掉。这里需要剔除的原因是: 虽然我们任务启动后由于keyshuffle的原因，subtask-0不会再接收到KG-3的数据，但是后续如果继续做checkpoint，会导致这部分数据重新被上传到DFS文件中，而如果继续发生rescale，就可能导致和其他subtask-1上的KG-3的数据发生冲突导致数据问题 
  subtask-1: 需要download原先subtask-0和subtask-1的数据dfs文件，并将subtask-0中的KG-1和KG-2的数据删除，以及原先subtask-1中的 KG-5 和 KG-6删除，并将其导入到新的RocksDB实例中。
 因此我们可以总结出rescale的大致流程中，首先会将当前task所涉及的db文件恢复到本地，并从中挑选出属于当前keygroup的数据重新构建出新的db。​从理论上分析，在不同的并发调整场景下，其rescale的代价也不尽相同并发翻倍​1.5倍扩并发​并发减半​接下来，我们在代码中确认相关的逻辑（代码基于Flink1.15版本）。根据stateHandle元信息判断是否是rescale我们可以看到当restoreStateHandles的数量大于1，或者stateHandle的keyGroupRange和当前task的range不一致时就是rescale的过程在不是rescale的场景下，恢复的流程只需要将相应IncrementalRemoteKeyedStateHandle对应的文件下载到本地或者是直接使用local recovery中的 IncrementalLocalKeyedStateHandle所对应的本地文件的目录，直接执行 RocksDB.open()就可以将db数据恢复。initialDB首先根据keygroup的重叠比较，挑选出和当前keygroup有最大重叠范围的stateHandle作为initial state handle。这样的好处是可以尽可能利用最大重叠部分的数据，减少后续数据遍历的过程。在挑选出initial state handle 创建db之后，首先需要将db中不属于当前的task的keygroup的数据进行遍历删除。因为flink中存储的keyed state的数据已经按照keygroup作为前缀作为排序，所以只需要删除头部和尾部的数据即可，这样就不用遍历全量的数据。在当前的deleteRange的实现中是依赖遍历db，通过writeBatch的方式进行批量执行删除，这种方式当需要删除的key的基数较大时会比较耗时，并且都会触发io和compaction的开销，而rocksdb提供了deleteRange的接口，可以通过指定start和end key来进行快速的删除，经过测试下来基本只要ms级别就可以完成。参考 FLINK-21321Bulk load在完成base db裁剪之后，就需要将其他db的数据导入到base db中，目前的实现还是通过writeBatch来加速写入在 FLINK-17971 中作者提供了sst ingest 写入的实现，本质上是利用rocksdb 的sst writer的工具，通过sst writer能直接构建出sst 文件，避免了直接写的过程中的compaction的问题，然后通过 db.ingestExternalFile直接将其导入db中。实际测试的过程中这样的写入性能有2-3倍的提升。Rescale的优化应该迭代优化了很多次，最开始的实现应该是将所有的statehandle的数据download下来，将其遍历写入新的db，在 FLINK-8790 中首先将其优化成 base db + delete Range + bulk load的方式，后续的两个pr又通过Rocksdb提供的deleteRange + SSTIngest 特性加速。虽然这些优化应用上只有rescale的提速很明显，但是当我们遇到key的基数非常大时，就会出现我们遍历原先的db next调用和 写入的耗时也非常的大，因此rescale的场景可能还需要继续优化。​关于RocksDB中deleteRange和SST Ingest功能笔者也做了一些研究，在后续的文章中会陆续更新出来，敬请期待参考https://blog.csdn.net/Z_Stand/article/details/115799605 sst ingest 原理http://rocksdb.org/blog/2017/02/17/bulkoad-ingest-sst-file.htmlhttps://rocksdb.org/blog/2018/11/21/delete-range.html delete range原理
		     (adsbygoogle = window.adsbygoogle || []).push({});
		Flink State Rescale性能优化的</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12053.html">
<title>Mybatis插件，能做的事情真的很多</title>
<link>https://www.ishiguang.cn/12053.html</link>
<dc:date>2022-01-22T19:40:12+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		大家好，我是架构摆渡人。这是实践经验系列的第九篇文章，这个系列会给大家分享很多在实际工作中有用的经验，如果有收获，还请分享给更多的朋友。Mybatis是我们经常用的一款操作数据库的框架，它的插件机制设计的非常好，能够在很多需求场景下派上用场。如果你还没用过Mybatis的插件（Mybatis 插件实际是一种拦截器），那么需要仔细阅读这篇文章。SQL监控埋点说句大实话，大部分性能问题都发生在存储层。当然对于优化我们需要有足够的样本，这些样本也就是慢SQL。数据库本身就有慢SQL的日志，但不方便我们跟具体的接口和trace进行关联。如果要跟trace进行关联那么就必须自己进行埋点上报性能数据，像我们之前用Cat做监控的时候，就是基于Mybatis的插件进行埋点，这样可以在Cat中看到每次请求下执行了哪些SQL，以及SQL的执行时间。SQL校验如果你们的表做了水平拆分，也就是分库分表。当然有可能是用开源框架实现的，也有可能是自研的框架。对于SQL的写法没有过多要求，但是如果是分库分表，而你的查询语句中没有带分片的字段，这个时候一般都是会进行所有表的查询，然后合并结果返回。假如你想打破这个规则，查询的SQL中必须带分片的字段，否则就直接报错。当然可以对你们的分库分表框架进行改造，如果是开源的改起来比较麻烦，那是否可以简单点实现呢？可以的，答案就是用Mybatis插件进行扩展，拿到执行的SQL进行分析，然后做校验。SQL改写SQL改写相对来说用的比较少，主要是改写是个很危险的事情，稍有不慎，线上就要炸锅了。那么改写会有哪些场景下需要呢？之前有遇到过的场景就是，我们接了一个新的分库分表的框架，老框架是支持分表场景下update分片字段的。比如你user表的分片字段是id，那么update语句中可以带上这个id，只不过值还是原来的，不影响数据，这种也经常会在用一些自动生成SQL的场景下会有。自从接了新框架后，对SQL更新有要求啦，分片字段是不允许更新的，不能出现在update的SQL中，如果有就直接报错。所以这个时候改写SQL就排上用场了，当然为了稳定性，我们还是采用了最原始的方式，将所有SQL都改了一遍。SQL中透传信息SQL中透传信息这个很实用，问题在于透传的信息给谁使用呢？其实这个要归根于你们有没有使用Proxy方式的分库分表中间件，如果有的话就需要透传信息。比如读写分离场景，Proxy怎么知道你的SQL要走主库还是走从库呢？比如在做压测的时候，Proxy怎么知道你的SQL要走正常库还是影子库呢？当然这个你也可以把影子库控制放在客户端。那么如何通过SQL进行信息透传呢？如下：/*master:true*/ SELECT * FROM table其实就是在SQL的前面加一些特殊的信息，然后中间件去解析做对应的处理。
		     (adsbygoogle = window.adsbygoogle || []).push({});
		Mybatis插件，能做的事情真的很多的</description>
</item>
<item rdf:about="https://www.ishiguang.cn/12051.html">
<title>花了半年时间，我把Pink老师的HTMLCSS视频课程，整理成了10万字的Markdown笔记！</title>
<link>https://www.ishiguang.cn/12051.html</link>
<dc:date>2022-01-22T19:40:11+08:00</dc:date>
<description>
		     (adsbygoogle = window.adsbygoogle || []).push({});
		说明：本文内容真实！！！不是推广！！！学习前端的同学应该都或多或少听说过 Pink 老师，我个人觉得 Pink 老师的前端视频教程应该说是目前B站上最好的了，没有之一！Pink老师 HTML CSS B站视频课程链接我花了整整半年的时间细致认真的学习完了 Pink 老师的 HTML CSS 教程，受益匪浅！我总结整理了一份包含该视频课程 全部知识点 近10万字 的 Markdown 笔记！笔记中包含所有的知识点归纳！并且配套有视频中对应的代码案例，最重要的是：每个代码案例都配套对应的效果图及批注，而且对于动画等页面效果所配套的都是GIF动态图片！！！，而且文档经过了精美的排版，同时加入了许多重要的知识点补充，更NB的是所有知识点都配套对应的思维导图！！！整理这份资料花了我半年所有的业余时间！！！如果只看视频，不做记录的话，效率非常低，看完就忘了！希望我提供的这份资料能帮助到大家！！！感谢！！！Markdown文档思维导图制作不易，希望大家可以去 GitHub 收藏一下！这对我有非常大的帮助！感谢大家！
		     (adsbygoogle = window.adsbygoogle || []).push({});
		花了半年时间，我把Pink老师的HTMLCSS视频课程，整理成了10万字的Markdown笔记！的</description>
</item>
</rdf:RDF>