首页 文章 精选 留言 我的

精选列表

搜索[编译原理],共10000篇文章
优秀的个人博客,低调大师

Kubernetes API server工作原理

作为Kubernetes的使用者,每天用得最多的命令就是kubectl XXX了。 kubectl其实就是一个控制台,主要提供的功能: 1. 提供Kubernetes集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更; 2. 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd) 也就是说,我们在终端里输入的每个kubectl命令,实际上都是一个发往Kubernetes API server的Restful API调用。 我们可以做个实验: kubectl get secret -v=9, 通过-v=9设置最高级别的trace: 从输出观察到为了取回所有的secret而进行的API server的调用url:https://xxxx/api/v1/

优秀的个人博客,低调大师

java NIO 运行原理介绍

开篇 回想研究生期间在H3C做项目的时候第一次接触epoll的异步事件,心血来潮看了下java的NIO的实现,希望同样感兴趣的人一起看看。Netty是java NIO的集大成者,一定要看看。 java NIO server demo socket server端工作标准流程 创建socket: 创建ServerSocketChannel,通过ServerSocketChannel.open()方法。 绑定socket:ServerSocketChannel绑定端口,通过serverSocketChannel.bind()方法。 前置准备: 创建selector对象,通过Selector.open()方法。 前置准备: 注册Channel到selector并绑定事件,通过serverSocketChannel.register()。 监听端口号: 通过listen()方法开始进入监听。 处理事件: while循环中等待select操作返回区分连接还是数据进行不同处理。 public class NIOServer { private Selector selector; public void initServer(int port) throws IOException { // 获得一个ServerSocketChannel通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 设置通道为非阻塞 serverSocketChannel.configureBlocking(false); // 将该通道对应的ServerSocket绑定到port端口 serverSocketChannel.bind(new InetSocketAddress(port)); // 获得一个通道管理器 this.selector = Selector.open(); // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后, // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } public void listen() throws IOException { System.out.println("服务端启动成功!"); // 轮询访问selector while (true) { // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞 selector.select(); // 获得selector中选中的项的迭代器,选中的项为注册的事件 Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator(); while (ite.hasNext()) { SelectionKey key = (SelectionKey) ite.next(); // 删除已选的key,以防重复处理 ite.remove(); if (key.isAcceptable()) {// 客户端请求连接事件 ServerSocketChannel server = (ServerSocketChannel) key.channel(); // 获得和客户端连接的通道 SocketChannel channel = server.accept(); // 设置成非阻塞 channel.configureBlocking(false); // 在这里可以给客户端发送信息哦 channel.write(ByteBuffer.wrap(new String("向客户端发送了一条信息") .getBytes("utf-8"))); // 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。 channel.register(this.selector, SelectionKey.OP_READ); } else if (key.isReadable()) {// 获得了可读的事件 read(key); } } } } public void read(SelectionKey key) throws IOException { // 服务器可读取消息:得到事件发生的Socket通道 SocketChannel channel = (SocketChannel) key.channel(); // 创建读取的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(512); channel.read(buffer); byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("服务端收到信息:" + msg); ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes("utf-8")); channel.write(outBuffer);// 将消息回送给客户端 } public static void main(String[] args) throws IOException { NIOServer server = new NIOServer(); server.initServer(8000); server.listen(); } } ServerSocketChannel和Selector初始化过程 在java NIO Server的标准过程中,有两个核心的操作需要深入分析一下,分别是ServerSocketChannel.open() 和 Selector.open()两个过程,这里针对这两个对象的初始化流程进行下细致的分解。 // ServerSocketChannel的初始化过程 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // Selector的初始化过程 selector = Selector.open(); 通用逻辑抽取 ServerSocketChannel.open()=SelectorProvider.provider().openServerSocketChannel() Selector.open()=SelectorProvider.provider().openSelector() 两者有共同点在于都调用了SelectorProvider.provider()方法,所以先把相同部分进行分析。 public abstract class ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannel { protected ServerSocketChannel(SelectorProvider provider) { super(provider); } public static ServerSocketChannel open() throws IOException { return SelectorProvider.provider().openServerSocketChannel(); } } public abstract class Selector implements Closeable { protected Selector() { } public static Selector open() throws IOException { return SelectorProvider.provider().openSelector(); } } SelectorProvider对象创建 SelectorProvider.provider()方法会在内部创建唯一的SelectorProvider对象,通过锁来保证创建唯一对象。 SelectorProvider对象通过DefaultSelectorProvider.create()方法进行创建。 DefaultSelectorProvider.create()方法内部根据实际系统创建不同的对象,以linux环境中EPollSelectorProvider对象为例继续分析。 public abstract class SelectorProvider { private static final Object lock = new Object(); private static SelectorProvider provider = null; public static SelectorProvider provider() { synchronized (lock) { if (provider != null) return provider; return AccessController.doPrivileged( new PrivilegedAction<SelectorProvider>() { public SelectorProvider run() { if (loadProviderFromProperty()) return provider; if (loadProviderAsService()) return provider; provider = sun.nio.ch.DefaultSelectorProvider.create(); return provider; } }); } } } public class DefaultSelectorProvider { public static SelectorProvider create() { String osname = AccessController.doPrivileged( new GetPropertyAction("os.name")); if ("SunOS".equals(osname)) { return new sun.nio.ch.DevPollSelectorProvider(); } // use EPollSelectorProvider for Linux kernels >= 2.6 if ("Linux".equals(osname)) { String osversion = AccessController.doPrivileged( new GetPropertyAction("os.version")); String[] vers = osversion.split("\\.", 0); if (vers.length >= 2) { try { int major = Integer.parseInt(vers[0]); int minor = Integer.parseInt(vers[1]); if (major > 2 || (major == 2 && minor >= 6)) { return new sun.nio.ch.EPollSelectorProvider(); } } catch (NumberFormatException x) { // format not recognized } } } return new sun.nio.ch.PollSelectorProvider(); } } EPollSelectorProvider的操作过程 SelectorProvider.provider().openServerSocketChannel()调用EPollSelectorProvider的openServerSocketChannel()方法返回EPollSelectorImpl对象。 SelectorProvider.provider().openSelector()调用EPollSelectorProvider的openSelector()方法返回ServerSocketChannelImpl对象。 继续分析ServerSocketChannelImpl对象和EPollSelectorImpl对象。 public class EPollSelectorProvider extends SelectorProviderImpl { public AbstractSelector openSelector() throws IOException { return new EPollSelectorImpl(this); } public Channel inheritedChannel() throws IOException { return InheritedChannel.getChannel(); } } public abstract class SelectorProviderImpl extends SelectorProvider { public DatagramChannel openDatagramChannel() throws IOException { return new DatagramChannelImpl(this); } public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException { return new DatagramChannelImpl(this, family); } public Pipe openPipe() throws IOException { return new PipeImpl(this); } public abstract AbstractSelector openSelector() throws IOException; public ServerSocketChannel openServerSocketChannel() throws IOException { return new ServerSocketChannelImpl(this); } public SocketChannel openSocketChannel() throws IOException { return new SocketChannelImpl(this); } } EPollSelectorImpl对象 EPollSelectorImpl构造函数创建内部通信的socket对IOUtil.makePipe(false)。 EPollSelectorImpl的doSelect方法负责返回事件到来的fds。 EPollSelectorImpl的fdToKey的map保存fd和SelectionKey的映射。 class EPollSelectorImpl extends SelectorImpl { // File descriptors used for interrupt protected int fd0; protected int fd1; // The poll object EPollArrayWrapper pollWrapper; // Maps from file descriptors to keys private Map<Integer,SelectionKeyImpl> fdToKey; // True if this Selector has been closed private volatile boolean closed = false; // Lock for interrupt triggering and clearing private Object interruptLock = new Object(); private boolean interruptTriggered = false; EPollSelectorImpl(SelectorProvider sp) { super(sp); long pipeFds = IOUtil.makePipe(false); fd0 = (int) (pipeFds >>> 32); fd1 = (int) pipeFds; pollWrapper = new EPollArrayWrapper(); pollWrapper.initInterrupt(fd0, fd1); fdToKey = new HashMap<Integer,SelectionKeyImpl>(); } protected int doSelect(long timeout) throws IOException { if (closed) throw new ClosedSelectorException(); processDeregisterQueue(); try { begin(); // 等待事件到来,收集事件到来的socket的fd并用来处理 pollWrapper.poll(timeout); } finally { end(); } processDeregisterQueue(); // 更新需要写入的keys int numKeysUpdated = updateSelectedKeys(); if (pollWrapper.interrupted()) { // Clear the wakeup pipe pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0); synchronized (interruptLock) { pollWrapper.clearInterrupted(); IOUtil.drain(fd0); interruptTriggered = false; } } return numKeysUpdated; } private int updateSelectedKeys() { int entries = pollWrapper.updated; int numKeysUpdated = 0; for (int i=0; i<entries; i++) { int nextFD = pollWrapper.getDescriptor(i); SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD)); // ski is null in the case of an interrupt if (ski != null) { int rOps = pollWrapper.getEventOps(i); if (selectedKeys.contains(ski)) { if (ski.channel.translateAndSetReadyOps(rOps, ski)) { numKeysUpdated++; } } else { ski.channel.translateAndSetReadyOps(rOps, ski); if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) { // selectedKeys保存ski也就是事件到的socket连接 // ski的对象数据结构需要好好研究一下 selectedKeys.add(ski); numKeysUpdated++; } } } } return numKeysUpdated; } } ServerSocketChannelImpl对象 ServerSocketChannelImpl extends ServerSocketChannel ServerSocketChannel extends AbstractSelectableChannel ServerSocketChannelImpl对象提供bind()&accept()方法 ServerSocketChannelImpl的accept方法内部创建新连接的SocketChannelImpl对象返回 class ServerSocketChannelImpl extends ServerSocketChannel implements SelChImpl { private final Object stateLock = new Object(); private SocketAddress localAddress; ServerSocket socket; ServerSocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.serverSocket(true); this.fdVal = IOUtil.fdVal(fd); this.state = ST_INUSE; } ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_INUSE; if (bound) localAddress = Net.localAddress(fd); } @Override public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { // 省略相关代码 } public SocketChannel accept() throws IOException { // 省略相关代码 } } public abstract class AbstractSelectableChannel extends SelectableChannel { protected AbstractSelectableChannel(SelectorProvider provider) { this.provider = provider; } public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { synchronized (regLock) { if (!isOpen()) throw new ClosedChannelException(); if ((ops & ~validOps()) != 0) throw new IllegalArgumentException(); if (blocking) throw new IllegalBlockingModeException(); SelectionKey k = findKey(sel); if (k != null) { k.interestOps(ops); k.attach(att); } if (k == null) { // New registration synchronized (keyLock) { if (!isOpen()) throw new ClosedChannelException(); k = ((AbstractSelector)sel).register(this, ops, att); addKey(k); } } return k; } } } select过程 select执行过程 执行selector.select()操作时实际是调用了子类实现的doSelect()方法。 进一步跟进子类的doSelect()方法。 abstract class SelectorImpl extends AbstractSelector { // 保存事件到来的keys protected Set<SelectionKey> selectedKeys; protected HashSet<SelectionKey> keys; private Set<SelectionKey> publicKeys; // Immutable private Set<SelectionKey> publicSelectedKeys; // Removal allowed, but not addition protected abstract int doSelect(long timeout) throws IOException; private int lockAndDoSelect(long timeout) throws IOException { synchronized (this) { if (!isOpen()) throw new ClosedSelectorException(); synchronized (publicKeys) { synchronized (publicSelectedKeys) { return doSelect(timeout); } } } } public int select(long timeout) throws IOException { if (timeout < 0) throw new IllegalArgumentException("Negative timeout"); return lockAndDoSelect((timeout == 0) ? -1 : timeout); } public int select() throws IOException { return select(0); } public Set<SelectionKey> selectedKeys() { if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException(); return publicSelectedKeys; } } pollWrapper.poll(timeout)以超时等待的形式等待epoll的消息通知。 通过updateSelectedKeys方法收集有事件到达的fds保存到selectedKeys。 class EPollSelectorImpl extends SelectorImpl { protected int doSelect(long timeout) throws IOException { if (closed) throw new ClosedSelectorException(); processDeregisterQueue(); try { begin(); // 等待事件到来,收集事件到来的socket的fd并用来处理 pollWrapper.poll(timeout); } finally { end(); } processDeregisterQueue(); // 更新需要写入的keys int numKeysUpdated = updateSelectedKeys(); if (pollWrapper.interrupted()) { // Clear the wakeup pipe pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0); synchronized (interruptLock) { pollWrapper.clearInterrupted(); IOUtil.drain(fd0); interruptTriggered = false; } } return numKeysUpdated; } private int updateSelectedKeys() { int entries = pollWrapper.updated; int numKeysUpdated = 0; for (int i=0; i<entries; i++) { int nextFD = pollWrapper.getDescriptor(i); SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD)); // ski is null in the case of an interrupt if (ski != null) { int rOps = pollWrapper.getEventOps(i); if (selectedKeys.contains(ski)) { if (ski.channel.translateAndSetReadyOps(rOps, ski)) { numKeysUpdated++; } } else { ski.channel.translateAndSetReadyOps(rOps, ski); if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) { // selectedKeys保存ski也就是事件到的socket连接 // ski的对象数据结构需要好好研究一下 selectedKeys.add(ski); numKeysUpdated++; } } } } return numKeysUpdated; } } accept过程 accept的过程很简单就是accept新socket并创建SocketChannelImpl返回即可。 SocketChannelImpl对象后面需要注册到Selector当中所以需要进一步分析。 public SocketChannel accept() throws IOException { // 省略相关代码 try { // 省略相关代码 // 新accept的socket放在newfd当中 n = accept0(this.fd, newfd, isaa); } } IOUtil.configureBlocking(newfd, true); InetSocketAddress isa = isaa[0]; // 通过SocketChannelImpl包装newfd对象 sc = new SocketChannelImpl(provider(), newfd, isa); // 省略相关代码 return sc; } } SocketChannelImpl对象 SocketChannelImpl可以理解为普通Socket的封装,包括read/write等方法 SocketChannelImpl extends SocketChannel extends AbstractSelectableChannel AbstractSelectableChannel提供register到selector对象的方法 class SocketChannelImpl extends SocketChannel implements SelChImpl { SocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.socket(true); this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; } SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; if (bound) this.localAddress = Net.localAddress(fd); } SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress remote) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_CONNECTED; this.localAddress = Net.localAddress(fd); this.remoteAddress = remote; } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { // 读数据的逻辑 } public int write(ByteBuffer buf) throws IOException { // 写数据的逻辑 } } register过程 register过程并没有调用epollCtl方法添加fd到selector当中 register过程真正是保存fd到待绑定的列表当中 在SelectorImpl中执行pollWrapper.poll(timeout)方法先把fd列表执行epollCtl添加selector当中,在通过epollWait获取事件到来 public abstract class AbstractSelectableChannel extends SelectableChannel { public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { synchronized (regLock) { if (!isOpen()) throw new ClosedChannelException(); if ((ops & ~validOps()) != 0) throw new IllegalArgumentException(); if (blocking) throw new IllegalBlockingModeException(); SelectionKey k = findKey(sel); if (k != null) { k.interestOps(ops); k.attach(att); } if (k == null) { // New registration synchronized (keyLock) { if (!isOpen()) throw new ClosedChannelException(); k = ((AbstractSelector)sel).register(this, ops, att); addKey(k); } } return k; } } } abstract class SelectorImpl extends AbstractSelector { protected final SelectionKey register(AbstractSelectableChannel ch, int ops, Object attachment) { if (!(ch instanceof SelChImpl)) throw new IllegalSelectorException(); SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this); k.attach(attachment); synchronized (publicKeys) { implRegister(k); } k.interestOps(ops); return k; } } abstract class AbstractPollSelectorImpl extends SelectorImpl { protected void implRegister(SelectionKeyImpl ski) { synchronized (closeLock) { if (closed) throw new ClosedSelectorException(); // Check to see if the array is large enough if (channelArray.length == totalChannels) { // Make a larger array int newSize = pollWrapper.totalChannels * 2; SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize]; // Copy over for (int i=channelOffset; i<totalChannels; i++) temp[i] = channelArray[i]; channelArray = temp; // Grow the NativeObject poll array pollWrapper.grow(newSize); } channelArray[totalChannels] = ski; ski.setIndex(totalChannels); // 核心的将channel添加到pollWrapper当中 pollWrapper.addEntry(ski.channel); totalChannels++; keys.add(ski); } } } class EPollArrayWrapper { int poll(long timeout) throws IOException { updateRegistrations(); updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd); for (int i=0; i<updated; i++) { if (getDescriptor(i) == incomingInterruptFD) { interruptedIndex = i; interrupted = true; break; } } return updated; } void updateRegistrations() { synchronized (updateList) { Updator u = null; while ((u = updateList.poll()) != null) { SelChImpl ch = u.channel; if (!ch.isOpen()) continue; // if the events are 0 then file descriptor is put into "idle // set" to prevent it being polled if (u.events == 0) { boolean added = idleSet.add(u.channel); // if added to idle set then remove from epoll if registered if (added && (u.opcode == EPOLL_CTL_MOD)) epollCtl(epfd, EPOLL_CTL_DEL, ch.getFDVal(), 0); } else { // events are specified. If file descriptor was in idle set // it must be re-registered (by converting opcode to ADD) boolean idle = false; if (!idleSet.isEmpty()) idle = idleSet.remove(u.channel); int opcode = (idle) ? EPOLL_CTL_ADD : u.opcode; epollCtl(epfd, opcode, ch.getFDVal(), u.events); } } } } }

优秀的个人博客,低调大师

Java常用算法原理剖析

用Java实现的所有算法(用于教育) 这些只是为了演示的目的。在Java标准库中有许多不同类型的实现,由于性能原因这些要好得多。 排序算法 气泡 从维基百科气泡排序,叫做下沉排序,是一种简单的排序算法,反复遍历要排序的列表,比较每一对相邻的项目,并在排序错误的情况下交换。遍历列表将被重复,直到不需要交换,这表明列表已被排序。 特性 最差情况下的性能O(n^2) 最佳案例表现O(N) 平均病例性能O(n^2) 查看算法行动 插入 从维基百科插入排序是一种简单的排序算法,每次构建最终排序数组(或列表)。在大型列表中,效率要比更高级的算法(如快速排序、堆排序或合并排序)低得多。 特性 最差情况下的性能O(n^2) 最佳案例表现O(N) 平均病例性能O(n^2) 查看算法行动 合并 合并排序(通常也是拼写合并)是一种高效的、通用的、基于比较排序算法。大多数实现都会产生稳定的排序,实现在排序的输出中保留相同元素的输入顺序。Mergesort是由JohnvonNeumann于1945年发明的分而治之的算法。 特性 最坏的情况性能O(N Log N)(典型) 最佳情况性能O(N Log N) 平均情况性能O(N Log N) 查看算法行动 速战速决 从维基百科快速排序(有时称为分区-交换排序)是一种有效的排序算法,是一种系统的方法,用于排列数组的元素。 特性 最差情况下的性能O(n^2) 最佳情况下O(N Log N)或O(N)具有三向分区 平均病例性能O(n^2) 查看算法行动 选择 将输入列表分为两个部分:已经排序项的子列表(在列表的前面(左)从左到右建立)和占据列表其余部分的待排序项的子列表。最开始排序子列表是空的,未排序子列表是整个输入列表。该算法通过查找未排序子列表中最小的(或最大的,取决于排序顺序)元素,将其与最左边的未排序元素交换(按排序顺序排列),并将子列表边界向右移动。 特性 最差情况下的性能O(n^2) 最佳案例性能O(n^2) 平均病例性能O(n^2) 查看算法行动 壳 ShellSort是插入排序的一种推广,允许交换相距很远的项。思路是安排元素列表,以便从任何地方开始,考虑到每个第n个元素都会给出一个排序列表。这样的列表叫做h排序。等效地,可以被认为是h交错列表,每个元素都是单独排序的。 特性 最坏的性能O(Nlog 2 2n) 最佳情况性能O(N Log N) 平均病例性能取决于间隙序列 查看算法行动 时间紧图 比较排序算法(气泡排序、插入排序、选择排序)的复杂性 复杂性图 搜索算法 线性 线性搜索或顺序搜索是在列表中查找目标值的一种方法。会依次检查列表中的每个元素的目标值,直到找到匹配或搜索所有元素为止。线性搜索在最坏的线性时间运行,最多进行n个比较,其中n是列表的长度。 特性 最坏的性能O(N) 最佳案例表现O(1) 平均个案表现O(N) 最坏情况下空间复杂度O(1)迭代 二进制 此算法也叫半间隔搜索或对数搜索算法,查找目标值在排序数组中的位置。将目标值与数组的中间元素进行比较;如果不相等,则消除目标数组的一半,并在其余的一半上继续搜索,直到成功为止。 特性 最坏的性能O(Log N) 最佳案例表现O(1) 平均案例性能O(Log N) 最坏情况空间复杂度O(1) ShellSort是插入排序的一种推广,允许交换相距很远的项。思路是安排元素列表,便于任何地方开始,考虑到每个第n个元素都会给出一个排序列表。这样的列表叫做h排序。等效地,可以被认为是h交错列表,每个元素都是单独排序的。 特性 最坏的性能O(Nlog 2 2n) 最佳情况性能O(N Log N) 平均病例性能取决于间隙序列 查看算法行动 与其他算法的链接 转换 动态规划 密码 杂类 任何基地到任何基地 硬币兑换 凯撒沙拉 堆排序 任何基到十进制 蛋滴 柱状转位密码 回文素校验器 二进制到十进制 斐波纳契 RSA 很快.。 二进制到十六进制 Kadane算法 更多的很快就会到来.。 二进制到八进制 背包 十进制到任意基 最长公共子序列 十进制到二进制 最长增长子序列 十进制到十六进制 棒材切割 还有更多.。 还有更多.。 数据结构 图 堆 列表 排队 BFS 空堆异常 圆链表 通用数组列表队列 外勤部 堆 双链表 排队 图 堆元素 单链表 Kruskals算法 最大堆 矩阵图 民堆 PrimMST 堆叠 树 节点堆栈 AVL树 链表堆栈 二叉树 堆叠 还有更多.。 袋 缓冲器 HashMap 矩阵

优秀的个人博客,低调大师

linux系统分区原理

windows系统 如图: 概念: 硬盘本身并不存在分区的说法,分区是操作系统的逻辑概念。 1、挂载:操作系统目录 与 硬盘分区建立联系的过程。 2、挂载点,被挂载的操作系统目录 就是挂载点 例如:C/D/E 等目录 3.、挂载类型:自动、手动 windows系统的挂载类型都是自动的 4、根目录:有多个(C/D/E等都是) 5、文件占据磁盘空间 各自挂载点目录下文件占据对应挂载点本身的磁盘空间 Linux系统 如图: 1、 挂载:操作系统目录 与 硬盘分区建立联系的过程。 2、 挂载点:被挂载的操作系统目录 就是挂载点 例如: /根目录、/Efile目录、/Cfile目录、/video目录 3、挂载类型:自动、手动 自动:系统安装创建的挂载点,后期使用会自动与硬盘分区建立联系。 手动:系统运行过程中,临时添加的U盘、移动硬盘不会被系统应用起来,需要手动创建一个文件目录并使其与该硬件进行联系挂载。 4、根目录:只有一个,名称是“/”根目录 5、 文件占据分区空间:会占据与其上边挨着最近挂载点对应的分区空间 6、与新硬件形成联系挂载 ① 把挂载点目录内部的旧的文件释放出去 ② 再进行挂载操作 7、文件存储占用空间 Dfile,/file根目录,存储的资源占用的是根目录的空间 viedo目录,Efile目录,Cfile目录,/根目录存储的资源占各自挂载所在的空间资源。

优秀的个人博客,低调大师

Docker(一)Docker基础原理

1 2 3 4 一、虚拟化技术分类 二、容器基础概念 三、Docker入门 四、docker层级概念 一、虚拟化技术分类 1.传统虚拟化Xen或者Kvm [vm.user] [vm.kern]....//这种虚拟化技术隔离效果最好,但是性能消耗也高 =========== VMM ====== 硬件 vm的user进程需要发起system call的时候,需要调用vm.kernel但是真正执行的是host.kernel 使用BT,或者HVM,加速转换。 内存虚拟化:shadow MMU CPU虚拟化:tagged TLB 2.容器技术: lxc:linux container openvz: [us1][us2].... //userspace,用户空间进行隔离,这就是一个容器 =========== kernel =========== 硬件 xen或者kvm隔离效果比较好, 容器技术:隔离的是user space 3.库虚拟化: wine cywin 4.应用级别虚拟化: jvm ... 二、容器基础概念: CGroup + NameSpace + AUFS 1.容器虚拟化依赖到的NS:name space pstree: PID 1:用户和内核交互的进程 假如us1中的进程,需要使用root权限和内核交互,它是否能够看到id号为1的进程,并且各us又是隔离的? yum -y install psmisc //安装该包 内核级别,环境隔离;类似chroot机制 PID NameSpace: kernel 2.6.24虚拟出各种pid,每一个用户空间都可以虚拟一个pid为1的进程 PID隔离 Network NameSpace: kernel 2.6.29 实现网络隔离 网路设备,网络栈,端口号等网络资源隔离 User NameSpace:用户隔离,每一个userspace可有同样的用户名的用户 用户和yoghurt组资源隔离,kernel 3.8 + IPC NameSpace:进程间通信 kernel 2.6.79 信号量,消息队列和共享内存等隔离 UTS NameSpace: kernel 2.6.19 主机名和域名的隔离 Mount NameSpace: us1能看到的fs一定是自己能够看到的fs,us2挂载的专有设备,fs是us1不能看到的 挂载点隔离(FS)隔离;kernel 2.4.19 为了对不同namespace访问 API:clone(),setns(),unshare(); clone:实现线程的系统调用,来实现新线程的。 setns:设定namespace的属性,假如某个进程到某个NS unshare:非共享机制,进程脱离一个NS,关联到另一个NS 查看: mount //可以查看挂载情况 lssubsys -m //查看各个名称空间的挂载情况 2.各容器的资源限制:CGroup 一个NS一个占用整个 userspace 的100%,其他NS就没资源用了 因此CGroup CGroup: linux control group:控制组 内核级别:限制,控制与一个进程组群的资源; 可以限制:内存,cpu等 kernel 2.6.24 收入内核 资源:CPU,内存,IO CGroup的功能: Resource limitation:资源限制 Prioritization:优先级控制;哪一个NS更优先获得CPU和资源 Account:统计和审计,主要为了计费 Control:挂起和恢复 进程 /sys/fs/cgroup 进程启用在哪里,代表只能使用多少资源 倒置的树状结构。 每一资源都是一棵树,cpu是一个,内存是一个,io也是一个,..也可以内存和cpu一棵树 还有其他很多的资源等。有的是重合的,有的是独立的。 术语集: task(任务):cgroups的术语中,task就表示系统的一个进程。 cgroup(控制组):cgroups 中的资源控制都以cgroup为单位实现。cgroup表示按某种资源控制标准划分而成的任务组,包含一个或多个子系统。 一个任务可以加入某个cgroup,也可以从某个cgroup迁移到另外一个cgroup。 subsystem(子系统):cgroups中的subsystem就是一个资源调度控制器(Resource Controller)。比如CPU子系统可以控制CPU时间分配,内存子系统可以限制cgroup内存使用量。 hierarchy(层级树):hierarchy由一系列cgroup以一个树状结构排列而成, 每个hierarchy通过绑定对应的subsystem进行资源调度。 hierarchy中的cgroup节点可以包含零或多个子节点,子节点继承父节点的属性。 整个系统可以有多个hierarchy。 [C,C,C,C] //CPU [16G] //内存 [io....] //io等其他资源 [c][c][c,c] [2G][2G][12G] //上级可以使用所属的所有资源 / \ [c][c] [4G][8G] CGroup的子系统(subsystem): blkio// 块设备的io资源分配,disk cpu //设定cpu的限制 ,仅能使用40% cpuacct //报告cgroup中所使用的cpu资源 cpuset //为cgroup中的任务分配cpu和内存资源, 分配你使用哪一个cpu 和memory,分配可以分配整个 memory //设定内存的使用限制 限制内存使用的空间,例如分配的是1个核心,但是仅运行使用40% devices //控制cgroup中的任务对设备的访问; freezer //挂起和回复cgroup中的任务; net_cls(classid),使用等级级别标识符来标记网络数据包,以实现基于tc完成对不同的cgroup中产生的流量的控制; perf_event:使用后使cgroup中的任务可以进行统一的性能测试 hugetlb;大的tlb,大内存页,hugetlb让大内存页提高命中率,对HugeTLB系统进行限制; Cgroup的通俗术语: task:任务,进程或线程 cgroup:一个独立的资源控制单位,可以包含一个或多个子系统 subsystem:子系统, hierarchy: 层级,可以再次划分。 一个子系统可以附加到多个层级//例如一个cpu可以在多个层级上附加 3.AUFS: union FS Union FS:它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下 Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像) 另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率 UnionFS:把不同的物理位置的目录,合并到同一个目录中 假如有两个文件或者目录名一样? 叠加:先后顺序,最前面的才是可写的 AUFS:Another UnionFS 、Alternative UFS、Advanced UFS 但是AUFS不是内核的版本,但是ubuntu是没有的, Docker 依赖于AUFS,用于提高性能 Docker目前支持的 Union 文件系统种类包括 AUFS, btrfs, vfs 和 DeviceMapper 原因: 之前复制bin,sbin等程序到一个目录中,chroot后可以执行 ns1和ns2一个需要ls,一个需要cat命令,但是ls和cat命令有重复使用的库,可以把该库做成一个联合库(只读) 可以把公共部分做成一个目录,ns1只放ls独有的,ns2只放cat独有的,用ls或者cat独有的联合底层公共的库即可 目的:减少disk占用 centos 不支持AUFS但是支持UNIONFS//UNIONFS没有AUFS强悍 还有另外一种方案:Device mapper 4.Device Mapper: 多系统机制 md:multi disks http://www.tldp.org/HOWTO/Multi-Disk-HOWTO-1.html dm:device mapper Kernel 2.6 引入的最重要的技术之一,用于在内核中支持逻辑卷管理的通用设备的映射机制; 从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的管理策略, 当前比较流行的 Linux 下的逻辑卷管理器如 LVM2(Linux Volume Manager 2 version) EVMS(Enterprise Volume Management System) dmraid(Device Mapper Raid Tool)等都是基于该机制实现的。 它包含三个重要的对象概念,mapped device、映射表、target device mapped device:可以理解成为内核向外提供的逻辑设备,它通过映射表描述的映射关系和 target device 建立映射 target device:逻辑设备映射到的一个物理设备 https://www.ibm.com/developerworks/cn/linux/l-devmapper/ 为底层块设备提供抽象设备, Mapped Device:映射的设备 Mapping table:虚拟设备到物理设备的映射 Target Device:被映射的设备 lVM就依赖于device mapper机制。但是不建议device mapper在docker技术中使用,因为有诸多不稳定性。 三、Docker入门: 程序的发布,需要依赖各种环境 一个docker中应该运行几个程序?只能运行一个应用程序? docker容器是为单一目的而实现的,为一个应用程序而实现的 LAMP:基于docker,要启用是三个容器,http,php,mysql 三者之间进行通信即可 //其实是可以把LAMP坐在一个容器内部的 [] ===================== [kernel] [hardware] 运行了三个Nginx容器 第一个cn(conainer) 使用80port,第二个cn也是用80 port,但是内核之有一个80端口 方法:映射, kernel: 8080 -> cn2.80 kernle: 888 -> cn1.80 ... 容器启动:创建,关闭:删除 //基于某个cn创建的文件没有了怎么办?让数据持久化 按需创建,运行在容器云环境,n个物理节点 [cn1] //cn1第一次启动在host1上,第二次可能启动在host2上 ======================== //资源抽象层 host1,host2,........... //物理主机 //容器的路径映射 \\\ ======================= 云存储//数据持久化 //容器使用的路径,关联到容器云的某个路径,保存数据。容器关联到该路径即可访问原有的数据 volume 技术:实现数据持久化,可以进行实时迁移 Docker的核心概念:2013,Go,apache 2.0协议 C/S架构 Docker client:发起请求的node docker server:容器运行的node, docCloud公司研发 https://www.docker.com/ ========================= dockerfiles[dockerHUB] \ / [images] \ \[backup] 【containers】 ============= linux OS ============================== 启动docker容器,需要加载images,server从dockerHUB上下载images 把所依赖到的多个images,叠加为一个UnionFS,然后在该容器中运行 可以从公共dockerhub下载,也可以自制 可以共享让别人访问。 可以创建私有hub dockerfile:创建dockerfile 创建docker映像文件。 四、docker层级概念 Linux内核是第0层-->Docker镜像,是一个只读的镜像,位于第1层,它不能被修改或不能保存状态。 一个Docker镜像可以构建于另一个Docker镜像之上,这种层叠关系可以是多层的。 第1层的镜像层我们称之为基础镜像(Base Image),其他层的镜像(除了最顶层)我们称之为父层镜像(Parent Image)。 这些镜像继承了他们的父层镜像的所有属性和设置,并在Dockerfile中添加了自己的配置。 Docker镜像通过镜像ID进行识别。镜像ID是一个64字符的十六进制的字符串。 但是当我们运行镜像时,通常我们不会使用镜像ID来引用镜像,而是使用镜像名来引用。 可以用同一个镜像启动多个Docker容器,这些容器启动后都是活动的,彼此还是相互隔离的。对其中一个容器所做的变更只会局限于那个容器本身。 附件1:进程间通信常用的方式: C方法包括管道(PIPE)、消息排队、旗语、共用内存以及套接字(Socket) 本文转自MT_IT51CTO博客,原文链接:http://blog.51cto.com/hmtk520/1946339,如需转载请自行联系原作者

优秀的个人博客,低调大师

vSphere网络原理及vSwitch

在一个物理网络拓扑中,通常都是路由器-交换机-PC机的连接,不同的服务器和PC机,通过交换机的连接而相互连通。 在VMware vSphere架构下服务器会虚拟出交换机来供ESX Host虚拟机来使用,虚拟交换机有两种,vSwitch虚拟交换机和vNetwork分布式虚拟交换机。 首先看下VMware提供的vSwitch的架构图,每个ESX Host均有一个标准vSwitch 一、ESXI的网络组成: 1.物理网卡在ESXi中,物理网卡名称都叫vmnic,第一片物理网卡为vmnic0,第二片vmnic1,依此类推,如上图片所示的俩片网卡则为vmnic0和vmnic1。在安装完ESXI后,默认会添加第一片网卡vmnic0。vSphere的高级功能,必须通过多片网卡来实现。 2.虚拟交换机vSwitch 由ESXI内核提供,为一个虚拟的交换机,用于连接不同的虚拟机及管理界面。vSwitch可由一块或多块vmnic组成,不同的vSwitch无法使用同一vmnic。默认会安装第一台虚拟交换机vSwitch0,用于主控台,虚拟机联机等功能。 3.通信端口(组) port/port group,主要用于提供Service Console,VmKernel,虚拟端口通信端口组功能 ESX的所有网络操作都是基于port/port group与vmnic,vSwitch之间。 4.NIC Team 将不同网卡集成到同个信道上,用于增加速度,failover,负载均衡以及其它功能。 二、vSwitch配置 VMware vSphere虚拟出一个或者多个虚拟交换机vSwitch,vSwitch提供多个虚拟端口提供给虚拟机来进行联网,同时vSwitch通过VMware vSphere服务器上的物理网卡来与外部的物理网络进行连接。 在VMware vSphere Client管理esx的配置(configuration)--网络属性(Properties)中可以看到虚拟交换机的状况,如下图esx服务器中只建立一个虚拟交换机vSwitch0,在vSwitch0下有 一个Vm Network,并且有一台虚拟机连接在这个Vm Network下,另外还有一个Service Console,是这台esx的管理IP地址。 查看vSwitch0的属性,可以看到这个vSwitch配置了120个虚拟端口。 通过编辑我们可以修改vSwitch0的端口数量,最大可以支持到4088个虚拟端口。 可以查看VM Network虚拟机端口组的属性,如下图所示 Service Console端口必须配置IP地址,第一个Service 默认名称为vswiff0,依此类推; VMKernel通信端口同样必须配置IP地址,主要用于vMotion,连接存储设备的iSCSI或NFS以及Fault Tolerance log表项等功能。 虚拟机通信端口组(Virtual Machine)用于让ESXI的虚拟机与switch连接,可以是物理switch或vSwitch 1. 如下图所示,之前安装ESX的IP地址设置,也可以在这里图形化界面设置。 2.在这里可以配置网卡的vMotion,VLAN ID,FT等信息 3.网卡流量限制 4.有多块网卡的情况下可以设置网络的负载均衡 5.添加或者删除虚拟交换机所连接的物理网卡 添加的虚拟交换机有3中,一种就是前面我们提到的为虚拟机提供端口的交换机;一种是VMkernel,用来连接iSCSI和NFS存储,或者用来做vMotion;还有一种是Service Console服务控制台,用来配置IP管理esx主机。 看一下添加VMkernel的流程 1)连接类型选择VMkernel使用的vSwitch; 2)选择要加入vSwitch0的网卡,此处由于只有一个vSwitch,因此默认为vSwitch0; 3)输入名称及VLAN ID; 4)配置VMkernel的IP地址及网关; 5)确认添加VMkernel配置即可。 6.除了默认的vSwitch外我们还可自己添加vSwitch,但是注意,同一块物理网卡vmnic只能配置到一个vSwitch上面。选择新建虚拟交换机使用的网卡虚拟交换机的名称及VLan ID确认配置即可,此处省略截图。完成添加之后可以看到esx服务器的网络中多了一个vswitch1的虚拟交换机。 除了标准的虚拟交换机(Standard Switches)外,VMware还有分布式交换机(Distributed Switches),分布式vSwitch可以横跨多个ESX Host。使用Distributed vSwitch后,多个ESX Host中的VM如同连接在同一vSwitch上一样,vm可以在任意ESX Host之间迁移。如下图所示,我们建立一个横跨俩个ESX Host的Distributed vSwitch。 总结:理解vSphere的网络结构是后续所有高级功能的关键,vSwitch标准交换机将同一ESX HOST上的不同VM连接在一起,而Distributed vSwitch则将不同ESX HOST上的不同VM连接在同一个虚拟交换机上,使得这些VM在不同ESX HOST迁移时,就如同一直在同一vSwitch端口上一样。 本文转自 bilinyee博客,原文链接: http://blog.51cto.com/ericfu/1662620 如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册