首页 文章 精选 留言 我的

精选列表

搜索[core],共9763篇文章
优秀的个人博客,低调大师

.Net Core微服务系列--理论篇

微服务的由来 微服务最早由Martin Fowler与James Lewis于2014年共同提出来的,但是微服务也不是一个全新的概念,它是由一系列在实践中获得成功并流行起来的概念中总结出来的一种模式,一种概念。而这一系列的概念大体上有这些:领域驱动设计(DDD),持续交付,按需虚拟化,基础设施自动化,小型的自治团队,大型集群系统。 领域驱动设计(DDD) DDD中我们关心了三个概念:领域建模,限界上下文,职责。这三个概念能很好的帮我们在微服务中按照业务分割出足够小且高内聚低耦合的服务, 这也是Evans 在《领域驱动设计》一书中的比喻 “细胞之所以会存在,是因为细胞膜定义了什么在细胞内,什么在细胞外,并且确定了什么物质可以通过细胞膜”,我们每个服务都应该是有自己的职责或者可以说要满足单一原则,要尽量保证内聚,并且要定义好与外部的交互。 持续交付 以往也包括现在的很多公司,生产环境的发布几乎总是痛苦的事情,凌晨或者周末加班加点进行发布而且很可能一出问题就是全部回滚到上一个版本。但是现在, 因为实行了持续交付,团队在一天内都可能在生产环境发布很多次。 持续集成,持续交付已经是现代软件很重要的一个特性,对软件产业产生了深远的影响,当然这一特性也跟微服务紧密的结合在一起了。 当然单体架构在持续交付方面的问题太显著了,但是微服务在这一方面确实优势明显。 微服务系统设计开始就是拆分为独立自治的一些服务的集合,每次的持续交付我们只需要关注某个或者某些微服务的交付,从而在很大程度上减少了持续交付的工作量和风险。当然这就要保证各个服务之间的低耦合,在一个服务更改的时候不会带消费方带来影响。 按需虚拟化 系统在高并发的时候总是会遇到性能瓶颈,但是瓶颈一般不是存在在整个系统而是在某几个特有的模块比如说订单,也不是说会一直存在瓶颈比如双11。所以按需进行扩展是必要解决的问题。而对于微服务,我们借助虚拟化平台,可以单独的为某个服务按需创造机器并调整大小。 基础设施自动化 这个其实跟按需虚拟化可以一起的,当我们需要水平扩展的时候,不可能为每次创造的机器进行一番部署,所以我们需要基础设施的自动化来帮组我们完成方便快捷的扩展 小型的自治团队 自治团队,可以对应到自治服务。一个独立的服务,可以语言自由,架构自由,集成自由,部署自由,我们只需要保证团队做出来的东西满足一定的条件就可以完全作为一个独立的单元来进行开发管理维护。 什么是微服务 微服务就是一些协同工作的小而自治的服务。 小,专注于一件事 这个就是我们常常说的职责单一。 在我的职业生涯中,不乏会接手其他人的项目,每每总是会抱怨这个项目代码量太多了,业务逻辑太分散,常常有牵一发而动全身的时候。而微服务则是把职责单一原则应用到服务上,根据业务来划分限界上下文,进而划分出不同的服务,这样每个服务都只用关注到某个限界上下文中,从而很大程度上避免了代码库过大而难以维护的问题。 自治 这是微服务的优点,也一定程度上导致了微服务的复杂性。 自治,代表每个服务是独立个体,所以我们可以自由的进行技术选型,服务之间通信用语言无关的api进行网络通信。也是因为自治,所以我们要保证每个服务能够独立的升级部署而不会对消费者产生影响,避免一个问题出现导致整个系统功能不可用的情况。 协同 虽然我们是一系列不同的个体,但是我们还是一个整体,所以就需要我们各个服务之间有交互有通信,并且需要用某些技术来解决分布式带来的新的问题。 微服务的好处 微服务是分布式的,所以具有分布式的所有好处,而且明确定义了界限上下文,也带来了更多的好处。 技术异构 弹性好(处理服务不可用和功能降级) 扩展方便,成本低 简化部署 与组织结构相匹配 可组合 易于重用完整的功能 对技术替代性的优化 微服务的缺点 当然微服务不是银弹,不是整个软件行业的终极解决方案,总是会存在不可忽视的缺点。同样大部分的缺点也是分布式带来的 性能(内存处理转化为远程调用) 可靠性 (远程调用失败的可能性) 最终一致性 操作的复杂性 因为还没有在实际中使用过微服务,但是对分布式还是有不少实践,所以结合一些书籍,写下了这篇文章做了一下总结。

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

《Core Java 2》读书笔记(一)

1,一个线程可以调用interrupt方法来请求终止另一个线程的运行,也就是说线程的 run方法应该不时检查一下它是否应该退出。 线程不应该连续不断地工作,应该偶尔进入睡眠或等待状态,以便其他线程由机会得以执行。但当一个线程进入睡眠状态时,它就无法检查自己是否应该终止运行。当另一个线程对当前被中断运行的线程对象调用interrupt方法时,中断调用(sleep或wait)将被InterruptedException终止。但还有种情况要考虑,若线程并未处于睡眠或等待状态,则另一个线程对其调用interrupt方法,则不会产生InterruptedException,对于此,线程应该在下一轮工作之前通过interrupted方法来确认它最近是否被其他线程给请求终止了。整体的框架如下: 复制代码 public void run() { while (!interrupted()) { try { …… sleep(50); } catch(InterruptedException ex) { Thread.currentThread.interrupt(); } } } 复制代码 Interrupted方法是个静态方法,用来检查当前线程是否已经被中断,此外,它会清除线程的“中断”状态。isInterrupted方法是个实例方法,用来检查任何一个线程是否已经被中断,它不会改变线程的“中断”状态。 2,Sleep对应于经过规定的毫秒数才退出中断状态。如果一个当前已经中断的线程上再次调用sleep,则会抛出IllegalThreadStateException。wait和notifyAll是一对,是Object类的方法。 3,守护线程则是用来服务用户线程的,如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去。Java垃圾回收线程就是一个典型的守护线程,当我们的程序中不再有任何运行中的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。 4,下面这段代码在本地线程机制下不会有什么问题,但若是在绿色线程机制下,则会发现利己线程会占据整个应用程序。 复制代码 public void run() { try { for (int i = 1; i <= 1000; i++) { b.move(); if (selfish) { // busy wait for 5 milliseconds long t = System.currentTimeMillis(); while (System.currentTimeMillis() < t + 5) ; } else sleep(5); } } catch (InterruptedException exception) { } } 复制代码 5,银行账户这个例子中,当账户中没有足够的金额时,我们必须等待,直到另外某个线程增加了金额为止。但transfer已经进行了同步,当前线程已经获得了对银行对象的专用访问权,因此没有其他线程有机会进行存款操作。因此我们想在synchronized方法中等待,就可以使用Object类的wait方法。于是当前线程将被中断运行,并且放弃对该对象的锁,这可以使另一个线程启动。当该线程在等待过程中被中断运行时,wait方法会抛出一个InterruptedException异常,此时,可以使用interrupt去打开“中断”标志,也可以传递该异常,这由调用线程来决定如何处理,所以在例子中给transfer 方法加入了throws InterruptedException。wait方法是Object类的一个方法,而不是Thread类的方法,当调用它时,银行对象打开自己的锁,并且中断当前线程的运行。 复制代码 public synchronized void transfer(int from, int to, int amount) throws InterruptedException { while (accounts[from] < amount) wait(); accounts[from] -= amount; accounts[to] += amount; ntransacts++; notifyAll(); if (ntransacts % NTEST == 0) test(); } 复制代码 等待进入synchronized方法的线程和已经调用了wait方法的线程之间有根本区别。一旦线程调用了wait方法,便进入了该对象的等待列表。此时线程被中断,在该线程没有从等待列表中删除之前,调度程序将忽略该线程,并且该线程将没有机会继续运行。要从等待列表中删除该线程,其他线程必须调用同一个对象上的notifyAll或notify方法。前者是将对象等待列表中的所有线程全部删除,后者是删除任意一个选择的线程。当线程从等待列表中删除后,它们就再次成为可运行的线程,并且调度程序最终会重新激活它们。然后,它们会试图重新进入该对象。一旦可以使用该对象锁时,其中的一个线程将锁定该对象,并且从它上次调用wait方法后的位置开始继续运行。 调用notifyAll方法的原则是每当一个对象的状态改变对各个等待线程有利时,就可以调用.例如在例子中,当完成资金转账时,就调用notifyAll方法,使得等待线程有机会查看其余额。若此时足够用于资金转账,则执行转账,否则再次调用wait进入等待列表。 调用notifyAll方法并不会立即激活某个等待线程,而只是撤消等待线程的中断状态,使其在当前线程退出synchronized方法后,与其他线程进行竞争,争取进入该对象。 如果一个线程必须等待某个对象的状态出现变更,那么它应该在对象的内部等待,而不是在外边等待,这通过进入一个synchronized方法,并且在其中调用wait方法来实现。 6,调用一个同步静态方法将会锁定类对象,如下例所示,将会锁定Singleton.class,因此,如果一个线程调用一个类的静态synchronized方法,那么该类的所有静态synchronized方法将会被锁定,直到第一个调用返回为止。 复制代码 public class Singleton { private static Singleton instance = null; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 复制代码 7,stop方法来停止线程不安全,当一个线程被停止时,它会立即释放它锁定的所有对象的锁,这会使各个对象处于不一致的状态之中。例如,在取款后和存款前,线程在将资金从一个账户转入另一个账户的中间停止了运行,则此时银行对象就损坏了。 如果需要安全地停止一个线程的运行,可以让该线程定期检查一个变量,此变量负责指明是否有停止线程的请求。还有种特殊情况要考虑,若线程处于封锁状态(比如调用了wait方法),则线程只有在解除封锁状态后才能终止运行,我们可以通过interrupt方法来强制线程退出封锁状态,基本框架如下: 复制代码 public class MyThread extends Thread { private boolean isStop; public void run() { while (!isStop) { try { wait(); } catch(InterruptedException ex) { if (isStop == true) return; } } } public void requestStop() { isStop = true; interrupt(); } } 复制代码 8,suspend方法也被废弃了,它不会损坏对象,但如果挂起了一个拥有某个对象锁的线程,则在该线程恢复之前,将无法使用该对象。如果调用suspend方法的线程试图在调用resume方法之前获得同一个对象的锁,那么程序会死锁。因为被挂起的线程要等待恢复运行,并且挂起的线程要等待该对象被撤销锁定状态。 如果想要安全地暂停线程的运行,应该使用变量suspendrequested,并且在run方法中一个安全的位置上检查此变量。框架如下代码: 复制代码 class SuspendRequestor { private boolean suspendrequested; public synchronized void set(boolean flag) { suspendrequested = flag; notifyAll(); } public synchronized void waitForResume() throws InterruptedException { while (suspendrequested) wait(); } } class MyThread extends Thread { private SuspendRequestor suspender = new SuspendRequestor(); public void requestSuspend() { suspender.set(true); } public void requstResume() { suspender.set(false); } public void run() { try { while (more work to do) { suspender.waitForResume(); do work; } } catch(InterruptedException ex) { } } } 复制代码 也可以像下面这样使用一个无用对象作为同步机制 复制代码 class MyThread extends Thread { private boolean suspendRequested; private Integer dummy = new Integer(1); public void reuqestSuspend() { suspendRequested = true; } public void requestResume() { suspendRequested = false; synchronized(dummy) { dummy.notifyAll(); } } public void waitForResume() { synchronized(dummy) { while (suspendRequested) dummy.wait(); } } public void run() { try { while (more work to do) { waitForResume(); do work; } } catch(InterruptedException ex) { } } } 复制代码 9,有两个wait方法带有超时参数,当wait方法返回时,若你需要知道是因为超时还是得到了通知,可以计算调用wait方法前后的时间差。 long before = System.currentTimeMills(); wait(delay); long after = System.currentTimeMills(); if (after - before > delay) //超时了 此外,也可以让负责通知的线程设置一个标志。 为了始终强制使用超时,可以将封锁操作放入第二个线程,然后使用join方法来使得当前线程被封锁,直到第二个线程运行结束或经过规定的毫秒数为止。 复制代码 Thread t = new Thread() { public void run() { //封锁操作 } }; t.start(); t.join(mills); 复制代码 10,Swing大多数方法不是同步的,这就使得我们以前常用的在工作线程中通过指向主界面的指针来更新主界面元素的思路不可行,即在工作线程中不能接触用户界面,例如显示线程的进度百分比,就不能在工作线程中调用lable.setText,而应该使用EventQueue类的invokeLater和invokeAndWait方法,从而在事件调度线程中执行该调用程序。 复制代码 public void run() { try { while (!interrupted()) { EventQueue.invokeLater(new Runnable() { public void run() { int i = Math.abs(generator.nextInt()); if (i % 2 == 0) combo.insertItemAt(new Integer(i), 0); else if (combo.getItemCount() > 0) combo.removeItemAt(i % combo.getItemCount()); } }); Thread.sleep(1); } } catch (InterruptedException exception) {} } 复制代码 在事件被移到事件队列后,invokeLater立即返回。Run方法以异步方法执行。invokeAndWait方法将进行等待,直到run方法确实已经执行为止。EventQueue类负责处理具体的同步操作。需要注意的是,这里run方法的代码不是在新线程中执行的,而是在事件调度程序中执行的。 11,管道用于线程间的通信,适用于线程间低层次的通信,其他情况下可以使用队列。 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2009/09/22/1572058.html,如需转载请自行联系原作者

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

《Core Java 2》读书笔记(二)

1,防御性编程。必要时应当考虑采取保护性拷贝的手段来保护内部的私有数据,先来看下面这个例子: 复制代码 pubic final class Period { private final Date start; private final Date end; public Period(Date start, Date end) { if (start.compareTo(end) > 0) throw new IllegalArgumentException(start + "after " + end); this.start = start; this.end = end; } public Date getStart() { return start; } public Date getEnd() { return end; } } 复制代码 这个类存在两个不安全的地方,首先来看第一个攻击代码 Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); end.setYear(78);//改变p的内部数据! 这是因为外部和内部引用了同样的数据,为了解决这个问题,应当修改Period的构造函数: 复制代码 public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (start.compareTo(end) > 0) throw new IllegalArgumentException(start + "after " + end); } 复制代码 这样内部的私有数据就与外部对象指向不同,则不会被外部改变 再来看第二个攻击代码: Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); p.getEnd().setYear(78);//改变p的内部数据! 这很显然是由于公有方法暴露了内部私有数据,我们可以只返回内部私有数据的只读版本(即其一份拷贝) 复制代码 public Date getStart() { return (Date)start.clone(); } public Date getEnd() { return (Date)end.clone(); } 复制代码 2,读到上面这个例子,我想起来了下面这样的代码片段 复制代码 public class Suit { private final String name; private static int nextOrdinal = 0; private final int ordinal = nextOrdinal++; private Suit(String name) { this.name = name; } public String toString() { return name; } public int compareTo(Object o) { return o } public static final Suit CLUBS = new Suit("Clubs"); public static final Suit DIAMONDS = new Suit("diamonds"); public static final Suit HEARTS = new Suit("hearts"); public static final Suit SPADES = new Suit("spades"); private static final Suit[] PRIVATE_VALUES = {CLUBS,DIAMONDS,HEARTS,SPADES}; public static final List VALUES = Collections.unmodifiedList(Arrays.asList(PRIVATE_VALUES)); } 复制代码 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2009/09/28/1575645.html,如需转载请自行联系原作者

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

树莓派3 Windows 10 IoT Core

下载地址:https://developer.microsoft.com/zh-cn/windows/iot/Downloads 先下载安装 Windows 10 IoT 核心版仪表板: 安装完成后运行,准备好SD卡 选择好版本SD卡,设置好密码 提示SD卡会被格式化 然后是漫长的下载过程 下载完成 开始写入SD卡 SD卡插入树莓派,通电开机 选择语言 安装完成… 下面捣鼓下看看怎么把带了个3.5的LCD屏幕弄亮… 貌似人家豪都是用7寸的… 本文转自 sun8134 博客园博客,原文链接:http://www.cnblogs.com/sun8134/p/6112207.html ,如需转载请自行联系原作者

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

Spark源码阅读笔记一——part of core

内部accumulator通过心跳报告给drivertask运行时可以累加accumulator,但是不能读取value,value只能在driver获取spark内部用一个weakhashmap保存accumulator,便于gc的清理 CacheManagerspark的类用于负责传递RDD的分区内容给BlockManager,并保证一个节点不会载入一个rdd的两份拷贝,这个通过一个hashset实现,已载入的rdd会将id保存到set中获取和计算rdd时,先判断是否已经计算,如果没有再从blockmanager获取block然后计算结果。除非是本地模式,不然rdd的计算结果都会缓存如果rdd不需要在内存中缓存,则直接将计算结果通过iterator直接传给blockmanager在rdd需要缓存时,我们必须小心不能在内存中一次性展开全部的partition,否则如果jvm没有足够的空间给这个单个的partition可能会引发OOM异常。取而代之的是,我们展开这些value,小心的、可能的放弃并丢掉这个partition到磁盘如果合适。如果空间足够就全部缓存到内存中,否则如果使用磁盘就放到磁盘,不然直接就返回value DependencyNarrowDependency:一个子partition依赖于多个父partitionShuffleDependency:shuffle stage的输出依赖,在shuffle中,rdd是短暂的因为我们在executor端不需要它 ExecutorAllocationClient与cluster manager请求或杀掉executor的客户端根据我们的调度需要更新集群,依赖于三个信息1 executor的数量,我们需要的全部的executor数,cluster manager不能杀掉任何运行中的executor来达到这个数量,这是我们想要分配的executor数量2 所有要运行的stage中有本地偏好的task数量,包括运行等待和完成的task3 task到运行host的map ExecutorAllocationManager(EAM)一个代理,根据工作负载动态的分配和移除executorEAM维护一个移动的目标executor数量,定期的同步到cluster manager。target的数量从配置的一个初始值开始,并根据等待和运行task数变化在当前的target数量多于需要控制的当前的负载时,会减少target数量。target总是会一次性减到可以运行所以当前运行和等待task的数量当需要响应积压的等待需要调度的task时,会增加target的数量。如果一个队列在N秒内没有排空,则新的executor被加入。如果这个队列仍然在另外的M秒内存在,则更多的executor会被加入。增加的数量在每轮以上一轮的指数级增加,直到达到上限。上限是基于一个配置的属性和当前运行和等待任务的数量。指数增长有双重理由。1 executor应该在开始缓慢的增加,以防万一额外需要的executor数量很小。否则我们增加了多于我们需要的executor数量则我们需要在后面移除他们。2 executor的数量需要快速增加,以防万一executor的数量最大值非常高,否则在繁重的工作负载下性能提升需要很长时间。executor移除的策略很简单,如果一个executor已经空闲了K秒,意味着它没有被调度用于执行任何task,因而移除它。这里没有重试的逻辑,因为我们假定cluster manager最终会异步的执行所有它收到的请求。相关的spark属性如下 成员变量initializing,是否需要一直等待初始化的executor集合被分配,当这个变量为true的时候,我们不会取消未执行的executor请求。这个在下面两种情况会被设置成false1 一个stage被提交2 一个executor的空闲时间超时用于增加减少executor的调度任务是一个定时任务,每100毫秒执行一次调度方法上,首先基于添加时间和我们当前的需要调整我们请求的executor,然后如果一个已存在的executor已经过期了,则杀掉。 updateAndSyncNumExecutorsTarget:更新target数量并同步结果到cluster manager。检查我们已存在的分配和之前的请求超过我们现在的需要。如果满足,truncate target数量并让cluster manager知道以便于它可以取消不需要的等待的请求。如果不满足,并且添加的时间超时,看看我们是否能请求新的executor,并刷新添加时间。 当一个executor(程它为executor X)因为到达了下限而没有被删除,则它不会再被标记位空闲。当有新的executor加入,我们不再在最低下限,则我们必须再次标记executor X为空闲,以使我们不会忘记它是一个被移除的候选。当scheduler的队列是空的时候,就会将addtime设为未设置所有cache的block会被报告给driver,但不包括广播的block当executor执行任务了(busy),就会清除它的idle timeprivate val stageIdToExecutorPlacementHints = new mutable.HashMap[Int, (Int, Map[String, Int])]stageid到tuple的map,tuple是节点和将会在这个节点上运行的task的数量taskstart和blockmanageradded这些事件是在不同的线程执行的,因而顺序不一定,taskstart事件中将对应的executor置为busytaskend,如果executor不再运行任何调度的任务,则标记为idle如果task失败,则会将scheduler置为积压任务的状态,将这个task从这个stage对应的task列表中移除

资源下载

更多资源
Mario

Mario

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

Nacos

Nacos

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册