首页 文章 精选 留言 我的

精选列表

搜索[云数据库 Redis®],共10034篇文章
优秀的个人博客,低调大师

Docker 搭建私有仓库Registry&Harbor

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36367789/article/details/81623854 为什么要弄私有仓库,大多是为了速度,我们再私有仓库中的push和pull的速度是特别快的。 利用registry快速搭建 /registry/”>https://hub.docker.com//registry/ Run a local registry: Quick Version $ docker run -d -p 5000:5000 --restart always --name registry registry:2 Now, use it from within Docker: $ docker pull ubuntu $ docker tag ubuntu localhost:5000/ubuntu $ docker push localhost:5000/ubuntu 这是官方的一个小demo。下面是我自己的实践。 # 拉取registry2.0版本 [root@FantJ ~]# docker pull registry:2 Trying to pull repository docker.io/library/registry ... 2: Pulling from docker.io/library/registry 81033e7c1d6a: Pull complete b235084c2315: Pull complete c692f3a6894b: Pull complete ba2177f3a70e: Pull complete a8d793620947: Pull complete Digest: sha256:672d519d7fd7bbc7a448d17956ebeefe225d5eb27509d8dc5ce67ecb4a0bce54 Status: Downloaded newer image for docker.io/registry:2 # 后台启动运行 [root@FantJ ~]# docker run -d -p 5000:5000 --restart always --name registry registry:2 ce5b8bfa6d7f535906730ea3a058b00e7cfdaaa20ea0db3c49d700a4e2c8a645 [root@FantJ ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/openjdk 8-jre bef23b4b9cac 2 weeks ago 443 MB docker.io/fantj/nginx latest ae513a47849c 4 weeks ago 109 MB docker.io/nginx latest ae513a47849c 4 weeks ago 109 MB docker.io/registry 2 d1fd7d86a825 4 months ago 33.3 MB # tag 镜像 [root@FantJ ~]# docker tag docker.io/nginx 127.0.0.1:5000/nginx # 上传到私有仓库 [root@FantJ ~]# docker push 127.0.0.1:5000/nginx The push refers to a repository [127.0.0.1:5000/nginx] 7ab428981537: Pushed 82b81d779f83: Pushed d626a8ad97a1: Pushed latest: digest: sha256:e4f0474a75c510f40b37b6b7dc2516241ffa8bde5a442bde3d372c9519c84d90 size: 948 [root@FantJ ~]# 缺点:没有可视化管理工具,私有仓库服务宕机造成麻烦,没有用户管理机制、没有操作的记录功能。 优点:搭建操作简单 利用harbor搭建 下载地址:https://storage.googleapis.com/harbor-releases/release-1.5.0/harbor-offline-installer-v1.5.1.tgz wget https://storage.googleapis.com/harbor-releases/release-1.5.0/harbor-offline-installer-v1.5.1.tgz tar zxvf harbor-offline-installer-v1.5.1.tgz cd harbor 修改配置harbor.cfg hostname = fantj.top:8888 http还是https啥的自己看着改 保存退出,直接运行install.sh cd .. ./install.sh 注意一点:harbor默认会占用80端口,所以请确保你的80端口不被占用,那怎么修改呢? 修改配置docker-compose.yml(需要改端口再进行) 将80:80的第一个80改为自定义的端口号 我在这里改成8888端口。 然后运行install.sh ...... [Step 4]: starting Harbor ... Creating network "harbor_harbor" with the default driver Creating harbor-log Creating redis Creating registry Creating harbor-db Creating harbor-adminserver Creating harbor-ui Creating nginx Creating harbor-jobservice ----Harbor has been installed and started successfully.---- Now you should be able to visit the admin portal at http://fantj.top:8888 . For more details, please visit https://github.com/vmware/harbor . 好的,成功了,我们来访问一下。 默认账号密码: admin Harbor12345 如果想修改,去harbor.cfg修改。 [root@FantJ harbor]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ea66b87c5d26 vmware/harbor-jobservice:v1.5.1 "/harbor/start.sh" 7 minutes ago Up 7 minutes harbor-jobservice 5fecbc47ea68 vmware/nginx-photon:v1.5.1 "nginx -g 'daemon ..." 7 minutes ago Up 7 minutes (healthy) 0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:8888->80/tcp nginx 9ccfa0d137de vmware/harbor-ui:v1.5.1 "/harbor/start.sh" 7 minutes ago Up 7 minutes (healthy) harbor-ui b1f6387545d6 vmware/harbor-db:v1.5.1 "/usr/local/bin/do..." 7 minutes ago Up 7 minutes (healthy) 3306/tcp harbor-db 6bcd46635374 vmware/registry-photon:v2.6.2-v1.5.1 "/entrypoint.sh se..." 7 minutes ago Up 7 minutes (healthy) 5000/tcp registry c40db866f7d2 vmware/harbor-adminserver:v1.5.1 "/harbor/start.sh" 7 minutes ago Up 7 minutes (healthy) harbor-adminserver 8d0ee20abfbf vmware/redis-photon:v1.5.1 "docker-entrypoint..." 7 minutes ago Up 7 minutes 6379/tcp redis 17c002dd8b98 vmware/harbor-log:v1.5.1 "/bin/sh -c /usr/l..." 7 minutes ago Up 7 minutes (healthy) 127.0.0.1:1514->10514/tcp harbor-log [root@FantJ harbor]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE vmware/redis-photon v1.5.1 19245c7a4f51 3 days ago 207 MB vmware/clair-photon v2.0.1-v1.5.1 e7f0ab982469 3 days ago 303 MB vmware/notary-server-photon v0.5.1-v1.5.1 611385e920c3 3 days ago 211 MB vmware/notary-signer-photon v0.5.1-v1.5.1 f9e01495db0e 3 days ago 209 MB vmware/registry-photon v2.6.2-v1.5.1 2efae6b250b1 3 days ago 198 MB vmware/nginx-photon v1.5.1 90d35cd72a68 3 days ago 135 MB vmware/harbor-log v1.5.1 67000769dfac 3 days ago 200 MB vmware/harbor-jobservice v1.5.1 3f7a7987ca5b 3 days ago 194 MB vmware/harbor-ui v1.5.1 8dbe945233a8 3 days ago 212 MB vmware/harbor-adminserver v1.5.1 a11b8eb3f9d8 3 days ago 183 MB vmware/harbor-db v1.5.1 afa780d73279 3 days ago 526 MB vmware/mariadb-photon v1.5.1 59ed57632415 3 days ago 526 MB vmware/postgresql-photon v1.5.1 41b693c0ce50 3 days ago 221 MB docker.io/openjdk 8-jre bef23b4b9cac 2 weeks ago 443 MB vmware/harbor-migrator v1.5.0 466c57ab0dc3 4 weeks ago 1.16 GB 127.0.0.1:5000/nginx latest ae513a47849c 4 weeks ago 109 MB docker.io/fantj/nginx latest ae513a47849c 4 weeks ago 109 MB docker.io/nginx latest ae513a47849c 4 weeks ago 109 MB vmware/photon 1.0 4b481ecbef2a 5 weeks ago 130 MB docker.io/registry 2 d1fd7d86a825 4 months ago 33.3 MB 可以看到我们的进程和镜像都多了很多的以vmware开头的(harbor是vmware公司的开源工具). 好了,开始push测试 [root@FantJ harbor]# docker tag docker.io/nginx fantj.top:8888/internet-plus/nginx [root@FantJ harbor]# docker push fantj.top:8888/internet-plus/nginx The push refers to a repository [fantj.top:8888/internet-plus/nginx] Get https://fantj.top:8888/v1/_ping: dial tcp: lookup fantj.top: no such host 它提示需要用https请求才安全,解决方式有两种: 第一种:docker启动的时候添加对域名+端口的信任 –insecure-registry=xxxx.xx.xx.xx:8888 第二种:添加ssl证书,改天更新 Harbor重启 #docker-compose stop # ./install.sh 遇到过的问题 如果你的服务上挂了https,也就是SA证书,它和docker的harbor会有冲突,因为你访问的harbor端口会被

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

C# 内存分配&&垃圾回收解析

在学习C#的过程中,大家一定会听说过一些CLR、JIT、LR、什么堆栈分配、内存释放的东西,谈到大家对这些元素的理解,多数都是这些是操作系统里面的东西,值类型、引用类型会和堆栈相关,但是在问到这些提到的名称具体是做什么的,或者扮演什么样的角色的时候,大家好像也能讲出点什么,但是也讲得模模糊糊,虽然这些都是一些理论知识,而且在开发的过程中可能也用不到,但还是能尽量多了解一下比较好,今天,笔者就谈一谈自己对这些元素的理解 有说的不准确或者不正确的地方欢迎留言指正 在日常生活中,如果要和其他语种的人交流,而且自己还不懂得情况下我们会怎么办?首先会想到找翻译软件,首先把自己说的话输入到翻译软件中,软件会根据输入文字的语法转到另一种歪果仁说的语言,其中主要步骤会经过检测-----校验-----输出。 其实在计算机的世界中,代码编译成0101这种形式的机器码也是大概如此,首先我们会在编译器中(例如:visual studio 2017)根据逻辑的需求编写C#代码,这个可以理解为我们说的母语,然后经过计算机的翻译编译成机器能听懂的语言(机器码),而下图中显示的 【metadata】【IL】【CLR】【JIT】就是在上面举例中提到翻译,翻译过程中【检测】----【校验】----【输出】需要这些元素的参与 缩写的全称: CTS是通用类型系统(Common Type System) CLR是公共语言运行时(Common language runtime) CLS是公共语言定义(Common Language Specification) 参考链接:https://blog.csdn.net/huang_xw/article/details/8578162 参考链接:https://docs.microsoft.com/zh-cn/dotnet/standard/common-type-system 代码编译后会形成DLL或者EXE文件,在这些文件中含有【metadata】与【IL】两种元素,下面我们逐一说明这两个元素的用途 metadata 通俗的讲:metadata就是一个档案库,一份清单,一个说明里面含有什么东西的列表。他里面详细的说明这个DLL或者EXE文件中都有什么类、函数、属性、字段、版本号等等,而且经常用到的特性(Attribute)的信息也在里面,不熟悉【特性】的小伙伴请看Unity C#基础之 特性,一个灵活的小工具。(也就是举例中需要翻译的是什么语言,多少个字,含有什么标点符号,在什么位置等等这些信息) IL(中间语言) IL又称:中间语言,他在翻译过程中是起到牵线搭桥的作用,类似于我能听懂(编译器),歪果仁也能听懂(计算机)的语言。如果想查看IL可以使用ILSpy反编译工具查看 上面提到的【metadata】【IL】仅仅是翻译前的准备工作,下面才是开始正式的【检测】----【校验】----【输出】 首先说下CLR 说道CLR他就厉害了,正是因为有了CLR这种运行环境,才能让不同语言编译的IL得以在不同的操作系统中运行,例如32位、64位的操作系统,而且不同的操作系统里面额CLR也是不一样的。 然后是JIT 基于上面提到的CLR环境,JIT根据不同的CLR将相同的IL依据清单(metadata)和dll或exe,开始正式的【检测】----【校验】----【输出】生成0101这种的机器码,JIT编译的时候会检测是否编译过机器码。如果编译过拿过来复用 上面说到的整体流程可以看一下托管执行过程 接下来说一下.NET 中的内存管理和垃圾回收 因为下面所提到的都是总结性结论,参考地址MSDN官方文档 .NET 中的内存管理和垃圾回收 什么是“托管代码”? 自动内存管理 线程栈:栈-stack 先进后出的数据结构 随着线程而分配的 默认执行方法分配1MB内存 对象堆:内存,进程中独立画出来的一块儿内存,有一些对象长期使用不释放的,例如static,方便对象重用(多个对象指向一个内存地址) 我们结合代码来说一下堆栈的分配 public struct ValuePoint// : System.ValueType 结构不能有父类,因为隐式继承了ValueType(通过反编译工具可查看) { public int x; public ValuePoint(int x) { this.x = x; } } public void Test() { //内存分配:线程栈 {//值类型分配在线程栈,变量和值都是在线程栈 ValuePoint valuePoint;//先声明变量,没有初始化 但是我可以正常赋值 跟类不同 valuePoint.x = 123; ValuePoint point = new ValuePoint(); Console.WriteLine(valuePoint.x); } } 声明的valuePoint和他对应的x都是在栈上面的 public class ReferencePoint { public int x; public ReferencePoint(int x) { this.x = x; } } public void Test() { ReferencePoint referencePoint = new ReferencePoint(123); } 引用类型分布在堆上面 变量是在栈上的(保存的地址),值是在堆上面 new的时候去堆开辟内存,分配一个地址 调用构造函数(因为在构造函数里可以使用this),才执行构造函数把引用传给变量 /// <summary> /// class 引用类型 /// </summary> public class ReferenceTypeClass { private int _valueTypeField;//堆:因为对象都在堆里,对象里面的属性也在堆里 public ReferenceTypeClass() { _valueTypeField = 0; } public void Method() { int valueTypeLocalVariable = 0;//栈:全新的局部变量,线程栈来调用方法,然后分配内存 } } public void Test() { ReferenceTypeClass referenceTypeClassInstance = new ReferenceTypeClass(); referenceTypeClassInstance.Method(); } _valueTypeField是在堆上面,因为对象都在堆里,对象里面的属性也在堆里 valueTypeLocalVariable是在栈上面,因为全新的局部变量,线程栈来调用方法,然后分配内存 /// <summary> /// 值类型 /// </summary> public struct ValueTypeStruct { private object _referenceTypeField;// 这个对象的变量在栈上,值在堆上 public ValueTypeStruct(int x) { _referenceTypeField = new object(); } public void Method() { object referenceTypeLocalVariable = new object();//这个对象的变量在栈上,值在堆上 } } public void Test() { ValueTypeStruct valueTypeStructInstance = new ValueTypeStruct(); valueTypeStructInstance.Method(); } _referenceTypeField这个对象的变量在栈上(保存地址),值在堆上 referenceTypeLocalVariable这个对象的变量在栈上(保存地址),值在堆上 综上所述: 方法的局部变量:根据变量自身决定,跟所在的环境没关系 对象是引用类型,其属性/字段,都是在堆里面 对象是值类型,其属性/字段,值类型就在栈里 引用类型就在堆里 引用类型任何时候都在堆里;值类型都在栈里, 除非值类型所在对象是在堆里(ReferencePoint这个例子就是) 装箱和拆箱(C# 编程指南) { int i = 0; object oValue = i; i = (int)oValue; } 装箱拆箱(仅仅是说内存的拷贝动作):内存copy 也会浪费性能 通常都是因为object 装箱拆箱只能发生在父子类里面, 否则无法转换 string字符串内存分配 string student = "菜鸟海澜";//开辟一块儿内存 放入“菜鸟海澜“ 返还一个引用(student变量) string student2 = student;//把student的引用copy一份儿给student2 Console.WriteLine(student);//打印结果 菜鸟海澜 Console.WriteLine(student2);//打印结果 菜鸟海澜 student2 = "菜鸟"; Console.WriteLine(student);//打印结果 :菜鸟海澜 Console.WriteLine(student2);//打印结果:菜鸟 改了student2的值 但是不是修改内存;因为string字符串的内存是不可变的 赋值其实是new string(APP),重新开辟内存,返回引用 不可变是因为享元,可能有多个变量指向同一个字符串,字符串变化了,多个变量都会受到影响。(例如多个类中的不同字符串变量都声明 "菜鸟海澜",本质上都是指向一个地址) 还因为堆里面的内存是连续分配的,如果变长度,会导致大量数据的移动 string student = "菜鸟海澜"; string student2 = "菜鸟";//共享 student2 = "菜鸟海澜"; Console.WriteLine(object.ReferenceEquals(student, student2));//打印结果为 True 就是同一个 享元模式 CLR内存分配字符串的时候,会查找相同值,有就重用了 使用享元的主要原因: 因为在堆中每个对象的内存都是紧密连接的,使用享元且不可改变,这样可以提高内存的使用率。 避免导致大量数据的移动,降低内存的重新分配、摆放(有不同的线程栈,但共用一个堆)。 垃圾回收 参考自 垃圾回收 与 清理非托管资源 网上一位开发者的文章:https://kb.cnblogs.com/page/106720/ 首先简述一下线程栈和托管堆的概念 值类型出现在线程栈:每次调用都有线程栈,,用完自己就结束,变量-值类型 都会释放的(不用我们维护) 引用类型出现在堆里:全局就一个堆,空间有限,所以才需要垃圾回收 操作系统里面,内存是链式分配的,可能有碎片的 CLR的堆:连续分配(数组),空间有限,节约空间 大对象策略:如果该对象占用内存大于85000字节,属于大对象,单独管理,用的是链表(碎片),避免频繁的内存移动造成性能消耗 下面要说的垃圾回收主要是以堆中的操作为主要内容 GC(Garbage Collector 的缩写) 1问:什么是垃圾? 垃圾是完全访问不到的东西了。例如临时变量,或者已经赋值为null的引用类型的变量 2问:什么时候会发生GC? gc发生在new的时候 new一个对象时,会开辟内存,看看空间够不够,不够的话就要GC了 gc程序退出的时候也会gc 手动GC。例如定时程序,很久执行一次,而且使用的时长很短,这时候就可以手动GC了 3问:怎么回收? new的时候发现内存不够,然后就去遍历所有堆的对象,标记有引用的对象,然后启动一个线程来清理内存 清除没有标记的对象,挪动其他剩余对象,然后整齐摆放,所以这个时候全部线程停止(开多线程时这个时候是停止的),不允许操作内存 内存不够的是指一级对象的内存,有个临界值,也不是全部的堆的大小 但是类中含有 析构函数【~类名称()】 ,内存的释放就需要单独的处理,把这些对象放入一个队列单独处理,具体哪一时刻调用析构函数不确定 注意:静态的对象是不会被回收的,且持有的引用也是不会被回收的 关于垃圾回收第几代的问题官方文档是这么说明的 在下面的例子中,声明一个静态变量staticStudent ,调用Test方法后主动调用GC,最终 变量【student】【@class】会被回收,但他们对应在堆中的内容不会被回收,因为有staticStudent 持有,变量 【i】会在弹栈之后直接被回收,变量【gCTest】以及它对应在堆中的内容都会被回收 private static Student staticStudent = new Student()//静态的不可能被回收 静态持有的引用也不会被回收 { Id = 123, Name = "菜鸟海澜" }; public void Test() { Student student = staticStudent; Class @class = new Class() { classId = 1, classdata = "数据" }; student.tempdata = @class; int i = 0;//都会被GC GCTest gCTest = new GCTest();//都会被GC } 在下面的示例中,很多开发者会把一个非静态变量设置成null,其实编译器会无视这句话,不是改成null这个对象没有了,其实内存还占用着,把对象赋值成null 意义不大,垃圾回收主要的原因是因为访问不到。但是静态可以把变量设置成null,促进垃圾回收,这样可以让变量不再被引用 Student student = new Student() { Id = 1, Name = "su9257", tempdata = new Class() { classId = 1, classdata = "数据1" } }; student = null; GC.Collect(); 非托管资源的释放 关于释放非托管资源必须要谈到的两个东西:【析构函数】和【Disposable】 析构函数 析构函数 主要是用来释放非托管资源(函数中调用具体释放资源的API或方法),等着GC的时候去把非托管资源释放掉 系统自动执行 GC回收的时候,CLR一定调用的,但是可能有延迟,具体是哪个时刻不确定 Dispose Dispose() 也是释放非托管资源的,主动释放(或手动调用),方法本身是没有意义的,我们需要在方法里面实现对资源的释放 GC不会调用,而是用对象时,使用者主动调用这个方法,去释放非托管资源 不过Dispose有一个自动调用的方法,就是使用【using】关键字,在using语句块运行完时自动调用Dispose方法(前提有的情况下)。且在Dispose方法中调用GC.SuppressFinalize(this);就是告诉CLR这个类我要释放的东西已经释放完了,你就不用调用析构函数了 using (Student student = new Student()) { Console.WriteLine("菜鸟海澜"); } public class People : IDisposable { public string Remark { get; set; } public virtual void Dispose() { Console.WriteLine($"执行{this.GetType().Name}Dispose"); } } public class Student : People, IDisposable { public int Id { get; set; } public string Name { get; set; } public Class tempdata { get; set; } public override void Dispose()//提供主动释放方式 { base.Dispose();//把我引用的其他东西给清理掉 if (this.tempdata != null) { this.tempdata.Dispose(); } //通知垃圾回收机制不再调用终结器(析构器) GC.SuppressFinalize(this); } 本质上是调用try finally try { } finally { //调用的dispose() }

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

依赖注入 in 前端 &amp;&amp; Typescript 实现依赖注入

背景 最近因为工作需要,研究了vscode的代码,看文档时发现其中提到了Dependency Injection,并且在类的构造函数中看到了这样的写法。 constructor( id: string, @IMessageService messageService: IMessageService, @IStorageService storageService: IStorageService, @ITelemetryService telemetryService: ITelemetryService, @IContextMenuService contextMenuService: IContextMenuService, @IPa

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

Elasticsearch Index API &amp; Aggregations API &amp; Query DSL

这篇小菜给大家演示和讲解一些Elasticsearch的API,如在工作中用到时,方便查阅。 一、Index API 创建索引库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 curl-XPUT 'http://127.0.0.1:9200/test_index/' -d'{ "settings" :{ "index" :{ "number_of_shards" :3, "number_of_replicas" :1 } }, "mappings" :{ "type_test_01" :{ "properties" :{ "field1" :{ "type" : "string" }, "field2" :{ "type" : "string" } } }, "type_test_02" :{ "properties" :{ "field1" :{ "type" : "string" }, "field2" :{ "type" : "string" } } } } }' 验证索引库是否存在 1 curl–XHEAD-i 'http://127.0.0.1:9200/test_index?pretty' 注: 这里加上的?pretty参数,是为了让输出的格式更好看。 查看索引库的mapping信息 1 curl–XGET-i 'http://127.0.0.1:9200/test_index/_mapping?pretty' 验证当前库type为article是否存在 1 curl-XHEAD-i 'http://127.0.0.1:9200/test_index/article' 查看test_index索引库type为type_test_01的mapping信息 1 curl–XGET-i 'http://127.0.0.1:9200/test_index/_mapping/type_test_01/?pretty' 测试索引分词器 1 2 3 4 5 curl-XGET 'http://127.0.0.1:9200/_analyze?pretty' -d' { "analyzer" : "standard" , "text" : "thisisatest" }' 输出索引库的状态信息 1 curl 'http://127.0.0.1:9200/test_index/_stats?pretty' 输出索引库的分片相关信息 1 curl-XGET 'http://127.0.0.1:9200/test_index/_segments?pretty' 删除索引库 1 curl-XDELETEhttp: //127 .0.0.1:9200 /logstash-nginxacclog-2016 .09.20/ 二、Count API 简易语法 curl -XGET 'http://elasticsearch_server:port/索引库名称/_type(当前索引类型,没有可以不写)/_count 用例: 1、统计 logstash-nginxacclog-2016.10.09 索引库有多少条记录 1 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_count' 2、统计 logstash-nginxacclog-2016.10.09 索引库status为200的有多少条记录 1 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_count?q=status:200' DSL 写法 1 2 3 4 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_count' -d' { "query" : { "term" :{ "status" : "200" }} }' 三、Aggregations API (数据分析和统计) 注: 聚合相关的API只能对数值、日期 类型的字段做计算。 1、求平均数 业务场景: 统计访问日志中的平均响应时长 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "avg_num" :{ "avg" :{ "field" : "responsetime" }} }, "size" :0 #这里的size:0表示不输出匹配到数据,只输出聚合结果。 }' { "took" :598, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :32523067, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "avg_num" :{ "value" :0.0472613558675975 } } } #得到平均响应时长为0.0472613558675975秒 2、求最大值 业务场景:获取访问日志中最长的响应时间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "max_num" :{ "max" :{ "field" : "responsetime" }} }, "size" :0 }' { "took" :29813, "timed_out" : false , "_shards" :{ "total" :431, "successful" :431, "failed" :0 }, "hits" :{ "total" :476952009, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "max_num" :{ "value" :65.576 } } } #得到最大响应时长为65.576秒 3、求最小值 业务场景: 获取访问日志中最快的响应时间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "min_num" :{ "min" :{ "field" : "responsetime" }} }, "size" :0 }' { "took" :2145, "timed_out" : false , "_shards" :{ "total" :431, "successful" :431, "failed" :0 }, "hits" :{ "total" :477156773, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "min_num" :{ "value" :0.0 } } } #看来最快的响应时间竟然是0,笔者通过查询日志发现,原来这些响应时间为0的请求是被nginx拒绝掉的。 4、数值求和 业务场景: 统计一天的访问日志中为响应请求总共输出了多少流量。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "sim_num" :{ "sum" :{ "field" : "size" }} }, "size" :0 }' { "took" :1226, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :32523067, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "sim_num" :{ "value" :6.9285945505E10 } } } #这个数有点大,后面的E10表示6.9285945505X10^10,笔者算了下,大概70GB流量。 5、获取常用的数据统计指标 其中包括( 最大值、最小值、平均值、求和、个数 ) 业务场景: 求访问日志中的 responsetime ( 最大值、最小值、平均值、求和、个数 ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "like_stats" :{ "stats" :{ "field" : "responsetime" }} }, "size" :0 }' { "took" :2868, "timed_out" : false , "_shards" :{ "total" :431, "successful" :431, "failed" :0 }, "hits" :{ "total" :477797577, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "like_stats" :{ "count" :469345191, "min" :0.0, "max" :65.576, "avg" :0.06088492952649428, "sum" :2.8576048877634E7 } } } 这个是上面统计方式的增强版,新增了几个统计数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "like_stats" :{ "extended_stats" :{ "field" : "responsetime" }} }, "size" :0 }' { "took" :2830, "timed_out" : false , "_shards" :{ "total" :431, "successful" :431, "failed" :0 }, "hits" :{ "total" :478145456, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "like_stats" :{ "count" :469687072, "min" :0.0, "max" :65.576, "avg" :0.06087745173159307, "sum" :2.859335205463328E7, "sum_of_squares" :1.3162790273264633E7, "variance" :0.02431853151732958, "std_deviation" :0.1559440012226491, "std_deviation_bounds" :{ "upper" :0.3727654541768913, "lower" :-0.2510105507137051 } } } } #其中新增的三个返回结果分别是: #sum_of_squares平方和 #variance方差 #std_deviation标准差 6、统计数据在某个区间所占的百分比 业务场景: 求出访问日志中响应时间的各个区间,所占的百分比 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "outlier" :{ "percentiles" :{ "field" : "responsetime" }} }, "size" :0 }' { "took" :60737, "timed_out" : false , "_shards" :{ "total" :431, "successful" :431, "failed" :0 }, "hits" :{ "total" :478287997, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "outlier" :{ "values" :{ "1.0" :0.0, "5.0" :0.0, "25.0" :0.02, "50.0" :0.038999979789136247, "75.0" :0.06247223731250421, "95.0" :0.16479760590682113, "99.0" :0.520510492464275 } } } } #values对应的列为所占的百分比,右边则是对应的数据值。表示: #响应时间小于或等于0的请求占1% #响应时间小于或等于0的请求占5% #响应时间小于或等于0.02的请求占25% #响应时间小于或等于0.038999979789136247的请求占50% #响应时间小于或等于0.06247223731250421的请求占75% #响应时间小于或等于0.16479760590682113的请求占95% #响应时间小于或等于0.520510492464275的请求占99% #还可以通过percents参数,自定义一些百分比区间,如10%,30%,60%,90%等。 #注:经笔者测试,这个方法只能对数值类型的字段进行统计,无法操作字符串类型的字段。 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "outlier" :{ "percentiles" :{ "field" : "status" , "percents" :[5,10,20,50,99.9] } } }, "size" :0 }' 7、求指定字段数值在各个区间所占的百分比 业务场景:求响应时间 0, 0.01, 0.1, 0.2 在整个日志文件中,分别所占的百分比。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "outlier" :{ "percentile_ranks" :{ "field" : "responsetime" , "values" :[0,0.01,0.1,0.2] } } }, "size" :0 }' { "took" :6950, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :32523067, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "outlier" :{ "values" :{ "0.0" :8.79897648675993, "0.01" :17.90331319256336, "0.1" :91.18297638776373, "0.2" :98.22564774611764 } } } } #响应时间小于或等于0的请求占8.7% #响应时间小于或等于0.01的请求占17.9% #响应时间小于或等于0.1的请求占91.1% #响应时间小于或等于0.2的请求占98.2% 8、求该数值范围内有多少文档匹配 业务场景: 求访问日志中的响应时间为,0 ~ 0.02、0.02 ~ 0.1 、大于 0.1 这三个数值区间内,各有多少文档匹配。 "ranges":[{"to": 0.02}, {"from":0.02,"to":0.1},{"from":0.1}] {"to": 0.02} 求响应时间 0 ~ 0.02 区间内的匹配文档数 {"from":0.02,"to":0.1} 求响应时间 0.02 ~ 0.1 区间内匹配的文档数 {"from":0.1} 求响应时间大于 0.1 匹配的文档数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "range_info" :{ "range" :{ "field" : "responsetime" , "ranges" :[{ "to" :0.02},{ "from" :0.02, "to" :0.1},{ "from" :0.1}] } } }, "size" :0 }' { "took" :474, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :32523067, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "range_info" :{ "buckets" :[{ "key" : "*-0.02" , "to" :0.02, "to_as_string" : "0.02" , "doc_count" :9093600 },{ "key" : "0.02-0.1" , "from" :0.02, "from_as_string" : "0.02" , "to" :0.1, "to_as_string" : "0.1" , "doc_count" :20547128 },{ "key" : "0.1-*" , "from" :0.1, "from_as_string" : "0.1" , "doc_count" :2879418 }] } } } "aggregations" :{ "range_info" :{ "buckets" :[{ "key" : "*-0.02" , "to" :0.02, "to_as_string" : "0.02" , "doc_count" :9093600 } #响应时间在0~0.02的文档数是9093600 ,{ "key" : "0.02-0.1" , "from" :0.02, "from_as_string" : "0.02" , "to" :0.1, "to_as_string" : "0.1" , "doc_count" :20547128 } #响应时间在0.02~0.1的文档数是20547128 ,{ "key" : "0.1-*" , "from" :0.1, "from_as_string" : "0.1" , "doc_count" :2879418 } #响应时间在大于0.1的文档数是2879418 ] } } 9、求时间范围内有多少文档匹配 业务场景:求访问日志中,在 2016-10-09T01:00:00 之前的文档有多少。 和在 2016-10-09T02:00:00 之后的文档有多少。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "match_all" :{}}, "aggs" :{ "range_info" :{ "date_range" :{ "field" : "@timestamp" , "ranges" :[{ "to" : "2016-10-09T01:00:00" },{ "from" : "2016-10-09T02:00:00" }] } } }, "size" :0 }' { "took" :432, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :32523067, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "range_info" :{ "buckets" :[{ "key" : "*-2016-10-09T01:00:00.000Z" , "to" :1.4759748E12, "to_as_string" : "2016-10-09T01:00:00.000Z" , "doc_count" :613460 }, #在2016-10-09T01:00:00之前的文档数有613460 { "key" : "2016-10-09T02:00:00.000Z-*" , "from" :1.4759784E12, "from_as_string" : "2016-10-09T02:00:00.000Z" , "doc_count" :31264881 } #在2016-10-09T02:00:00之后的文档数有31264881 ] } } } 10、聚合结果不依赖于查询结果集 "global":{} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "term" :{ "status" : "200" }}, "aggs" :{ "all_articles" :{ "global" :{}, "aggs" :{ "sum_like" :{ "sum" :{ "field" : "responsetime" }} } } }, "size" :0 }' { "took" :1519, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :26686196, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "all_articles" :{ "doc_count" :32523067, "sum_like" :{ "value" :1536946.1929722272 } } } } #可以看到查询结果集hitstotal部分才匹配到26686196条记录。而聚合的文档数则是32523067多于查询结果匹配到的文档。 #聚合结果为1536946.1929722272 #我们再看看没有引用"global":{}参数的方式 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "query" : { "term" :{ "status" : "200" }}, "aggs" :{ "sum_like" :{ "sum" :{ "field" : "responsetime" }} }, "size" :0 }' { "took" :1326, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :26686196, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "sum_like" :{ "value" :1526710.3929916811 } } } #聚合结果小于上诉的结果。表示这次的聚合的值,是依赖于检索匹配到的文档。 11、分组聚合 用于统计指定字段在自定义的固定增长区间下,每个增长后的值,所匹配的文档数量。 1 2 3 4 5 6 7 8 9 10 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "aggs" :{ "like_histogram" :{ "histogram" :{ "field" : "status" , "interval" :200, "min_doc_count" :1} } }, "size" :0 }' #对status字段操作,增长区间为200,为了避免有的区间匹配为0所导致空数据,所以这里指定最小文档数为1"histogram":{"field":"status","interval":200,"min_doc_count":1} 12、分组聚合-基于时间做分组 "date_histogram":{"field": "@timestamp", "interval": "1d","format": "yyyy-MM-dd",} "field": "@timestamp" 指定记录时间的字段 "interval": "1d" 分组区间为每天. 1M 每月、1H 每小时、1m 每分钟 "format": "yyyy-MM-dd" 指定时间的输出格式 统计每天产生的日志数量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-*/_search?pretty' -d'{ "aggs" :{ "date_histogram_info" :{ "date_histogram" :{ "field" : "@timestamp" , "interval" : "1d" , "format" : "yyyy-MM-dd" , "min_doc_count" :1} } } }' "aggregations" :{ "date_histogram_info" :{ "buckets" :[{ "key_as_string" : "2016-09-27" , "key" :1474934400000, "doc_count" :6895375 },{ "key_as_string" : "2016-09-28" , "key" :1475020800000, "doc_count" :1255775 },{ "key_as_string" : "2016-09-29" , "key" :1475107200000, "doc_count" :38512862 },{ "key_as_string" : "2016-09-30" , "key" :1475193600000, "doc_count" :35314225 },{ "key_as_string" : "2016-10-01" , "key" :1475280000000, "doc_count" :45358162 },{ "key_as_string" : "2016-10-02" , "key" :1475366400000, "doc_count" :42058056 },{ "key_as_string" : "2016-10-03" , "key" :1475452800000, "doc_count" :39945587 },{ "key_as_string" : "2016-10-04" , "key" :1475539200000, "doc_count" :39509128 },{ "key_as_string" : "2016-10-05" , "key" :1475625600000, "doc_count" :40506342 },{ "key_as_string" : "2016-10-06" , "key" :1475712000000, "doc_count" :43303499 },{ "key_as_string" : "2016-10-07" , "key" :1475798400000, "doc_count" :44234780 },{ "key_as_string" : "2016-10-08" , "key" :1475884800000, "doc_count" :32880600 },{ "key_as_string" : "2016-10-09" , "key" :1475971200000, "doc_count" :32523067 },{ "key_as_string" : "2016-10-10" , "key" :1476057600000, "doc_count" :31454044 },{ "key_as_string" : "2016-10-11" , "key" :1476144000000, "doc_count" :2018401 }] } } } #基于小时做分组 #统计当天每小时产生的日志数量 curl-XGET 'http://127.0.0.1:9200/logstash-nginxacclog-2016.10.09/_search?pretty' -d'{ "aggs" :{ "date_histogram_info" :{ "date_histogram" :{ "field" : "@timestamp" , "interval" : "1H" , "format" : "yyyy-MM-dd-H" , "min_doc_count" :1} } }, "size" :0 }' { "took" :530, "timed_out" : false , "_shards" :{ "total" :5, "successful" :5, "failed" :0 }, "hits" :{ "total" :32523067, "max_score" :0.0, "hits" :[] }, "aggregations" :{ "date_histogram_info" :{ "buckets" :[{ "key_as_string" : "2016-10-09-0" , "key" :1475971200000, "doc_count" :613460 },{ "key_as_string" : "2016-10-09-1" , "key" :1475974800000, "doc_count" :644726 },{ "key_as_string" : "2016-10-09-2" , "key" :1475978400000, "doc_count" :687196 },{ "key_as_string" : "2016-10-09-3" , "key" :1475982000000, "doc_count" :730831 },{ "key_as_string" : "2016-10-09-4" , "key" :1475985600000, "doc_count" :1460320 },{ "key_as_string" : "2016-10-09-5" , "key" :1475989200000, "doc_count" :1469098 },{ "key_as_string" : "2016-10-09-6" , "key" :1475992800000, "doc_count" :1004399 },{ "key_as_string" : "2016-10-09-7" , "key" :1475996400000, "doc_count" :962843 },{ "key_as_string" : "2016-10-09-8" , "key" :1476000000000, "doc_count" :1232560 },{ "key_as_string" : "2016-10-09-9" , "key" :1476003600000, "doc_count" :1809741 },{ "key_as_string" : "2016-10-09-10" , "key" :1476007200000, "doc_count" :2802804 },{ "key_as_string" : "2016-10-09-11" , "key" :1476010800000, "doc_count" :3941192 },{ "key_as_string" : "2016-10-09-12" , "key" :1476014400000, "doc_count" :4631032 },{ "key_as_string" : "2016-10-09-13" , "key" :1476018000000, "doc_count" :3651968 },{ "key_as_string" : "2016-10-09-14" , "key" :1476021600000, "doc_count" :2079933 },{ "key_as_string" : "2016-10-09-15" , "key" :1476025200000, "doc_count" :973578 },{ "key_as_string" : "2016-10-09-16" , "key" :1476028800000, "doc_count" :517435 },{ "key_as_string" : "2016-10-09-17" , "key" :1476032400000, "doc_count" :388382 },{ "key_as_string" : "2016-10-09-18" , "key" :1476036000000, "doc_count" :361296 },{ "key_as_string" : "2016-10-09-19" , "key" :1476039600000, "doc_count" :345926 },{ "key_as_string" : "2016-10-09-20" , "key" :1476043200000, "doc_count" :342214 },{ "key_as_string" :

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

Android -- 重置Bitmap大小&amp;&amp;Bitmap转角度

重置Bitmap大小 Bitmap bitMap = BitmapFactory.decodeFile(path); int width = bitMap.getWidth(); int height = bitMap.getHeight(); // 设置想要的大小 int newWidth = 500; int newHeight = 400; // 计算缩放比例 float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; // 取得想要缩放的matrix参数 Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); // 得到新的图片 bitMap = Bitmap.createBitmap(bitMap, 0, 0, width, height, matrix, true); Bitmap转角度 Bitmap bm = BitmapFactory.decodeByteArray(imgdata, 0,imgdata.length); Matrix matrix = new Matrix(); matrix.preRotate(270); bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),bm.getHeight(), matrix, true); imgdata为camera开发的时候的图片数据。 这里其实找到了bitmap就OK了。 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3744875.html,如需转载请自行联系原作者

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

Callable、Future&amp;阻塞队列&amp;阻塞栈

Callable、Future 简单应用 在Java5之前,线程是没有返回值的,常常为了“有”返回值,破费周折,而且代码很不好写。或者干脆绕过这道坎,走别的路了。现在Java终于有可返回值的任务(也可以叫做线程)了。 可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。 Code public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { //创建一个线程池 ExecutorService pool = Executors.newFixedThreadPool(2); //创建两个有返回值的任务 Callable c1 = new MyCallable("A"); Callable c2 = new MyCallable("B"); //执行任务并获取Future对象 Future f1 = pool.submit(c1); Future f2 = pool.submit(c2); //从Future对象上获取任务的返回值,并输出到控制台 System.out.println(">>>"+f1.get().toString()); System.out.println(">>>"+f2.get().toString()); //关闭线程池 pool.shutdown(); } } class MyCallable implements Callable{ private String oid; MyCallable(String oid) { this.oid = oid; } @Override public Object call() throws Exception { return oid+"任务返回的内容"; } } >>>A任务返回的内容 >>>B任务返回的内容 阻塞队列 简单应用 阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止。 有了这样的功能,就为多线程的排队等候的模型实现开辟了便捷通道,非常有用。 Code public class Test { public static void main(String[] args) throws InterruptedException { BlockingQueue bqueue = new ArrayBlockingQueue(20); for (int i = 0; i < 30; i++) { //将指定元素添加到此队列中,如果没有可用空间,将一直等待(如果有必要)。 bqueue.put(i); System.out.println("向阻塞队列中添加了元素:" + i); } System.out.println("程序到此运行结束,即将退出----"); } } 向阻塞队列中添加了元素:0 向阻塞队列中添加了元素:1 向阻塞队列中添加了元素:2 向阻塞队列中添加了元素:3 向阻塞队列中添加了元素:4 向阻塞队列中添加了元素:5 向阻塞队列中添加了元素:6 向阻塞队列中添加了元素:7 向阻塞队列中添加了元素:8 向阻塞队列中添加了元素:9 向阻塞队列中添加了元素:10 向阻塞队列中添加了元素:11 向阻塞队列中添加了元素:12 向阻塞队列中添加了元素:13 向阻塞队列中添加了元素:14 向阻塞队列中添加了元素:15 向阻塞队列中添加了元素:16 向阻塞队列中添加了元素:17 向阻塞队列中添加了元素:18 向阻塞队列中添加了元素:19 可以看出,输出到元素19时候,就一直处于等待状态,因为队列满了,程序阻塞了。 阻塞栈 简单应用 对于阻塞栈,与阻塞队列相似。不同点在于栈是“后入先出”的结构,每次操作的是栈顶,而队列是“先进先出”的结构,每次操作的是队列头。Java为阻塞栈定义了接口:java.util.concurrent.BlockingDeque。 Code public class Test { public static void main(String[] args) throws InterruptedException { BlockingDeque bDeque = new LinkedBlockingDeque(20); for (int i = 0; i < 30; i++) { //将指定元素添加到此阻塞栈中,如果没有可用空间,将一直等待(如果有必要)。 bDeque.putFirst(i); System.out.println("向阻塞栈中添加了元素:" + i); } System.out.println("程序到此运行结束,即将退出----"); } } 向阻塞栈中添加了元素:0 向阻塞栈中添加了元素:1 向阻塞栈中添加了元素:2 向阻塞栈中添加了元素:3 向阻塞栈中添加了元素:4 向阻塞栈中添加了元素:5 向阻塞栈中添加了元素:6 向阻塞栈中添加了元素:7 向阻塞栈中添加了元素:8 向阻塞栈中添加了元素:9 向阻塞栈中添加了元素:10 向阻塞栈中添加了元素:11 向阻塞栈中添加了元素:12 向阻塞栈中添加了元素:13 向阻塞栈中添加了元素:14 向阻塞栈中添加了元素:15 向阻塞栈中添加了元素:16 向阻塞栈中添加了元素:17 向阻塞栈中添加了元素:18 向阻塞栈中添加了元素:19 从上面结果可以看到,程序并没结束,二是阻塞住了,原因是栈已经满了,后面追加元素的操作都被阻塞了。 我是天王盖地虎的分割线 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/4104014.html,如需转载请自行联系原作者

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

Docker &amp; Consul &amp; Fabio &amp; ASP.NET Core 2.0 微服务跨平台实践

相关博文: Ubuntu 简单安装 Docker Mac OS、Ubuntu 安装及使用 Consul Consul 服务注册与服务发现 Fabio 安装和简单使用 阅读目录: Docker 运行 Consul 环境 Docker 运行 Fabio 环境 使用 Consul 注册 ASP.NET Core 2.0 服务 使用 Docker 发布部署 ASP.NET Core 2.0 服务 本篇博文的目的:在 Mac OS 中使用 VS Code 开发 ASP.NET Core 2.0 应用程序,然后在 Ubuntu 服务器配置 Docker 环境,并使用 Docker 运行 Consul 和 Fabio 环境,最后使用 Docker 运行 ASP.NET Core 2.0 应用程序。 你要的项目源码:https://github.com/yuezhongxin/HelloDocker.Sample 上面配置看起来还蛮简单,但实际去操作的时候,还是遇到了蛮多的问题,并且花了很多的时间去解决,比如 Docker 运行 Consul 和 Fabio,下面详细说下过程。 1. Docker 运行 Consul 环境 关于Consul的概念: Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,比如 Airbnb 的 SmartStack 等相比,Consul 的方案更“一站式”,内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其他工具(比如 ZooKeeper 等)。使用起来也较 为简单。Consul 用 Golang 实现,因此具有天然可移植性(支持 Linux、windows 和 Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。 Consul Docker 镜像地址:https://hub.docker.com/_/consul/ 配置 Consul 的微服务集群环境,需要先配置下 Server 服务端(需要独立服务器环境),配置命令(没有使用 Docker): $ consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -ui-dir=./dist -config-dir /etc/consul.d -bind=10.9.10.110 一开始,我想在 Mac OS 环境中使用 Docker 配置 Consul Client 客户端,但遇到了一些问题,配置命令: $ docker run -d --net=host --name=consul-client consul agent -bind=10.9.10.190 -client=0.0.0.0 -node=mac-xishuai -retry-join=10.9.10.236 先解析下命令的意思: --net=host:host网络模式,容器的网络接口和主机一样,也就是共享一个 IP 地址,如果没有此命令,默认是bridge网络模式,也就是我们常用的桥接模式,Docker 会分配给容器一个独立的 IP 地址(端口也是独立的),并且容器和主机之间可以相互访问。 -bind=:Consul Client 绑定的 IP 地址,一般是内网的私有 IP 地址,需要内网服务器之前可以相互访问到,注意并不是127.0.0.1。 -retry-join=:加入 Consul 集群中,地址是 Consul Server 的 IP 地址,也可以是-join=,加上retry会不断进行重试。 一台服务器一般会配置一个 Consul Client,所以我们可以直接让 Consul 容器和主机的 IP 地址一样(我使用的),但使用了 Docker 之后,一台服务器就可以配置多个 Consul Client,我们就可以使用bridge网络模式,一台服务器可以完成配置整个 Consul 集群环境。 这里需要再重点说下-client=,一开始我没有理解,先看下官方说明: If you want to expose the Consul interfaces to other containers via a different network, such as the bridge network, use the-clientoption for Consul. With this configuration, Consul's client interfaces will be bound to the bridge IP and available to other containers on that network, but not on the host network. Note that we still keep the cluster address out on the host network for performance. Consul will also accept the-client=0.0.0.0option to bind to all interfaces. 啥意思呢?Consul 服务注册的时候,一般是通过HTTP API接口进行注册,比如:http://10.9.10.190:8500/v1/agent/service/register,就是往 Consul 集群中注册服务,需要注意的是,10.9.10.190一般是 Consul Client 的 IP 地址(也可以是 Consul Server),-client配置的就是此地址,简单来说,就是用来服务注册并能访问到的地址,换句话说,服务注册可以跨服务器(服务和 Consul Client 并不需要在同一台服务器上),0.0.0.0表示任何本机的相关 IP 地址都可以访问,推荐此配置。 这里需要再说明下,Docker 部署 ASP.NET Core 2.0、Consul 和 Fabio 有两种方式: 使用一个 Docker 容器:很简单,在一个容器中完成服务部署,并且配置 Consul 和 Fabio 环境,这样容器就会很臃肿,并且每次发布的时候都得重新配置 Consul 和 Fabio 环境,如果服务很多的话,想想就觉得恐怖。 分别独立 Docker 容器:服务部署、配置 Consul 和 Fabio 环境,都是独立容器实现,互不影响,也可以跨服务实现,简单灵活。 显而易见,推荐第二种方式。 回到正题,上面配置命令,在 Mac OS 报如下错误: $ docker logs consul-client ==> Starting Consul agent... ==> Error starting agent: Failed to start Consul client: Failed to start lan serf: Failed to create memberlist: Could not set up network transport: failed to obtain an address: Failed to start TCP listener on "10.9.10.190" port 8301: listen tcp 10.9.10.190:8301: bind: cannot assign requested address 这个问题花了很多时间也没有解决,奇怪的是不使用 Docker,直接运行 Consul Client 配置命令,却是可以的,后来没办法,我就在 Mac OS 中使用 Ubuntu 虚拟机了(版本 14.04),使用的Vagrant管理工具。 再重新运行配置命令: $ docker run -d --net=host --name=consul-client consul agent -bind=10.9.10.89 -client=0.0.0.0 -node=vagrant-ubuntu-xishuai -retry-join=10.9.2.236 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9c4988cf475f consul "docker-entrypoint..." 2 seconds ago Up 2 seconds consul-client $ docker logs consul-client ==> Starting Consul agent... ==> Consul agent running! Version: 'v1.0.0' Node ID: '34e63f0a-d361-f152-3803-b9fda0642e4d' Node name: 'vagrant-ubuntu-xishuai' Datacenter: 'dc1' (Segment: '') Server: false (Bootstrap: false) Client Addr: [0.0.0.0] (HTTP: 8500, HTTPS: -1, DNS: 8600) Cluster Addr: 10.9.10.89 (LAN: 8301, WAN: 8302) Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false ==> Log data will now stream in as it occurs: 2017/11/14 06:40:52 [INFO] serf: EventMemberJoin: vagrant-ubuntu-xishuai 10.9.10.89 2017/11/14 06:40:52 [INFO] agent: Started DNS server 0.0.0.0:8600 (udp) 2017/11/14 06:40:52 [INFO] agent: Started DNS server 0.0.0.0:8600 (tcp) 2017/11/14 06:40:52 [INFO] agent: Started HTTP server on [::]:8500 (tcp) 2017/11/14 06:40:52 [INFO] agent: Retry join LAN is supported for: aws azure gce softlayer 2017/11/14 06:40:52 [INFO] agent: Joining LAN cluster... 2017/11/14 06:40:52 [INFO] agent: (LAN) joining: [10.9.2.236] 2017/11/14 06:40:52 [WARN] manager: No servers available 2017/11/14 06:40:52 [ERR] agent: failed to sync remote state: No known Consul servers 2017/11/14 06:40:52 [INFO] serf: EventMemberJoin: agent_1 10.9.2.236 2017/11/14 06:40:52 [INFO] agent: (LAN) joined: 1 Err: <nil> 2017/11/14 06:40:52 [INFO] agent: Join LAN completed. Synced with 1 initial agents 2017/11/14 06:40:52 [INFO] consul: adding server agent_1 (Addr: tcp/10.9.2.236:8300) (DC: dc1) 打开 Consul UI 界面,就可以看到我们配置的 Consul Client 了: 2. Docker 运行 Fabio 环境 Fabio是一个快速、现代、zero-conf 负载均衡 HTTP(S) 路由器,用于部署 Consul 管理的微服务。 Fabio Docker 镜像地址:https://hub.docker.com/r/magiconair/fabio/ 配置命令: $ docker run -d --net=host --name=fabio -e 'registry_consul_addr=10.9.10.89:8500' magiconair/fabio 执行日志: $ docker logs fabio 2017/11/14 09:43:49 [INFO] Setting log level to INFO 2017/11/14 09:43:49 [INFO] Runtime config { "Proxy": { "Strategy": "rnd", "Matcher": "prefix", "NoRouteStatus": 404, "MaxConn": 10000, "ShutdownWait": 0, "DialTimeout": 30000000000, "ResponseHeaderTimeout": 0, "KeepAliveTimeout": 0, "FlushInterval": 1000000000, "LocalIP": "10.0.2.15", "ClientIPHeader": "", "TLSHeader": "", "TLSHeaderValue": "", "GZIPContentTypes": null, "RequestID": "" }, "Registry": { "Backend": "consul", "Static": { "Routes": "" }, "File": { "Path": "" }, "Consul": { "Addr": "10.9.10.89:8500", "Scheme": "http", "Token": "", "KVPath": "/fabio/config", "TagPrefix": "urlprefix-", "Register": true, "ServiceAddr": ":9998", "ServiceName": "fabio", "ServiceTags": null, "ServiceStatus": [ "passing" ], "CheckInterval": 1000000000, "CheckTimeout": 3000000000, "CheckScheme": "http", "CheckTLSSkipVerify": false }, "Timeout": 10000000000, "Retry": 500000000 }, "Listen": [ { "Addr": ":9999", "Proto": "http", "ReadTimeout": 0, "WriteTimeout": 0, "CertSource": { "Name": "", "Type": "", "CertPath": "", "KeyPath": "", "ClientCAPath": "", "CAUpgradeCN": "", "Refresh": 0, "Header": null }, "StrictMatch": false, "TLSMinVersion": 0, "TLSMaxVersion": 0, "TLSCiphers": null } ], "Log": { "AccessFormat": "common", "AccessTarget": "", "RoutesFormat": "delta", "Level": "INFO" }, "Metrics": { "Target": "", "Prefix": "{{clean .Hostname}}.{{clean .Exec}}", "Names": "{{clean .Service}}.{{clean .Host}}.{{clean .Path}}.{{clean .TargetURL.Host}}", "Interval": 30000000000, "Timeout": 10000000000, "Retry": 500000000, "GraphiteAddr": "", "StatsDAddr": "", "Circonus": { "APIKey": "", "APIApp": "fabio", "APIURL": "", "CheckID": "", "BrokerID": "" } }, "UI": { "Listen": { "Addr": ":9998", "Proto": "http", "ReadTimeout": 0, "WriteTimeout": 0, "CertSource": { "Name": "", "Type": "", "CertPath": "", "KeyPath": "", "ClientCAPath": "", "CAUpgradeCN": "", "Refresh": 0, "Header": null }, "StrictMatch": false, "TLSMinVersion": 0, "TLSMaxVersion": 0, "TLSCiphers": null }, "Color": "light-green", "Title": "", "Access": "rw" }, "Runtime": { "GOGC": 800, "GOMAXPROCS": 1 }, "ProfileMode": "", "ProfilePath": "/tmp" } 需要注意的两个属性值: Proxy.LocalIP:10.0.2.15:绑定本机的 IP 地址,服务器的 IP 地址是10.9.10.89,所以配置的10.0.2.15是错误的,这个 IP 地址内网是访问不了的。 Registry.Consul.Addr:10.9.10.89:8500:绑定 Consul 地址,我们上面已经完成的 Consul Client 地址就是10.9.10.89:8500,所以是正确的。 这个配置命令研究了好久,也没有解决绑定本机 IP 地址的问题,后来又找到了另外一种方式。 首先,在/etc/fabio/目录下创建一个fabio.properties文件(示例配置),然后vim fabio.properties增加下面配置: registry.consul.register.addr = 10.9.10.89:9998 registry.consul.addr = 10.9.10.89:8500 registry.consul.register.addr绑定 Fabio 地址(本机 IP 地址),registry.consul.addr绑定 Consul 地址。 然后切换到/etc/fabio/目录,执行配置命令: $ docker run -d -p 9999:9999 -p 9998:9998 --net=host --name=fabio -v $PWD/fabio.properties:/etc/fabio/fabio.properties magiconair/fabio $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 301fe4a5b40b magiconair/fabio "/fabio -cfg /etc/..." About a minute ago Up About a minute fabio 9c4988cf475f consul "docker-entrypoint..." 4 hours ago Up 4 hours consul-client 查看执行日志: $ docker logs fabio 2017/11/14 10:10:58 [INFO] Version 1.5.3 starting 2017/11/14 10:10:58 [INFO] Go runtime is go1.9.2 2017/11/14 10:10:58 [INFO] Metrics disabled 2017/11/14 10:10:58 [INFO] Setting GOGC=800 2017/11/14 10:10:58 [INFO] Setting GOMAXPROCS=1 2017/11/14 10:10:58 [INFO] consul: Connecting to "10.9.10.89:8500" in datacenter "dc1" 2017/11/14 10:10:58 [INFO] Admin server access mode "rw" 2017/11/14 10:10:58 [INFO] Admin server listening on ":9998" 2017/11/14 10:10:58 [INFO] Waiting for first routing table 2017/11/14 10:10:58 [INFO] consul: Using dynamic routes 2017/11/14 10:10:58 [INFO] consul: Using tag prefix "urlprefix-" 2017/11/14 10:10:58 [INFO] consul: Watching KV path "/fabio/config" 2017/11/14 10:10:58 [INFO] consul: Manual config changed to #3723938 2017/11/14 10:10:58 [INFO] HTTP proxy listening on :9999 2017/11/14 10:10:58 [INFO] Access logging disabled 2017/11/14 10:10:58 [INFO] Using routing strategy "rnd" 2017/11/14 10:10:58 [INFO] Using route matching "prefix" 2017/11/14 10:10:58 [INFO] consul: Health changed to #3727339 2017/11/14 10:10:59 [INFO] consul: Registered fabio with id "fabio-vagrant-ubuntu-trusty-9998" 2017/11/14 10:10:59 [INFO] consul: Registered fabio with address "10.9.10.89" 2017/11/14 10:10:59 [INFO] consul: Registered fabio with tags "" 2017/11/14 10:10:59 [INFO] consul: Registered fabio with health check to "http://[10.9.10.89]:9998/health" 2017/11/14 10:11:00 [INFO] Config updates 可以通过 Consul UI,进行查看 Fabio 是否正常: 也可以直接浏览http://10.9.10.89:9998/routes?filter=,查看已经注册的服务: 其实,如果不清楚配置命令的话,我们也可以查看 Consul 源码,有可能会帮助我们熟悉命令,比如(https://github.com/fabiolb/fabio/blob/master/registry/consul/register.go): 3. 使用 Consul 注册 ASP.NET Core 2.0 服务 在 Mac OS 中使用 VS Code 开发 ASP.NET Core 2.0 应用程序,就像写 Markdown 一样方便。 Consul 注册 ASP.NET Core 2.0 服务,使用的是 Consul 组件,地址:https://github.com/PlayFab/consuldotnet 安装程序包(VS Code 需要使用NuGet Pakcage Manager命令安装): > install-package Conusl 然后添加一个RegisterWithConsul扩展服务: using System; using System.Collections.Generic; using System.Linq; using Consul; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.DependencyInjection; public static class ApplicationBuilderExtensions { public static IApplicationBuilder RegisterWithConsul(this IApplicationBuilder app, IApplicationLifetime lifetime) { //var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{Program.IP}:8500"));//如果服务和 Consul 在同一台服务器上,使用此代码 var consulClient = new ConsulClient(x => x.Address = new Uri($"http://10.9.10.89:8500"));//请求注册的 Consul 地址 var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔 HTTP = $"http://{Program.IP}:{Program.Port}/health",//健康检查地址 Timeout = TimeSpan.FromSeconds(5) }; // Register service with consul var registration = new AgentServiceRegistration() { Checks = new[] { httpCheck }, ID = Guid.NewGuid().ToString(), Name = Program.ServiceName, Address = Program.IP, Port = Program.Port, Tags = new[] { $"urlprefix-/{Program.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别 }; consulClient.Agent.ServiceRegister(registration).Wait();//服务启动时注册,内部实现其实就是使用 Consul API 进行注册(HttpClient发起) lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册 }); return app; } } Start.cs配置代码: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime lifetime) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); app.RegisterWithConsul(lifetime);//here } Program.cs配置代码: public class Program { public static string IP = ""; public const int Port = 54917; public const string ServiceName = "hello-docker"; public const string Version = "v1"; public static void Main(string[] args) { //Program.IP = LocalIPAddress;//使用 Docker 的时候,获取的是 IP 地址不正确,需要进行完善 Program.IP = "10.9.10.190";//Docker 容器中的 IP 地址,如果使用 host 网络模式,也是主机的 IP 地址 BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseUrls($"http://*:{Program.Port}") .UseStartup<Startup>() .Build(); public static string LocalIPAddress { get { UnicastIPAddressInformation mostSuitableIp = null; var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); foreach (var network in networkInterfaces) { if (network.OperationalStatus != OperationalStatus.Up) continue; var properties = network.GetIPProperties(); if (properties.GatewayAddresses.Count == 0) continue; foreach (var address in properties.UnicastAddresses) { if (address.Address.AddressFamily != AddressFamily.InterNetwork) continue; if (IPAddress.IsLoopback(address.Address)) continue; return address.Address.ToString(); } } return mostSuitableIp != null ? mostSuitableIp.Address.ToString() : ""; } } } 健康检查配置代码: [Route("[controller]")] public class HealthController : Controller { private static readonly HttpClient _httpClient; static HealthController() { _httpClient = new HttpClient(); } [HttpGet] public IActionResult Get() => Ok("ok"); //或者使用fabio进行健康检查 //[Route("")] //[HttpGet] //public async Task<HttpResponseMessage> GetWithFabio() => await _httpClient.GetAsync("http://127.0.0.1:9998/health"); } 4. 使用 Docker 发布部署 ASP.NET Core 2.0 服务 我们需要在 ASP.NET Core 2.0 应用程序目录下,添加一个Dockerfile文件,用来构建自定义镜像(命令参考:使用 Dockerfile 定制镜像),示例: FROM microsoft/aspnetcore-build AS build-env WORKDIR /app # copy csproj and restore as distinct layers COPY *.csproj ./ RUN dotnet restore # copy everything else and build COPY . ./ RUN dotnet publish -c Release -o out # build runtime image FROM microsoft/aspnetcore WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "HelloDocker.Web.dll"] 简单来说,就是先使用microsoft/aspnetcore-build镜像,还原程序包并发布,然后再使用microsoft/aspnetcore镜像,运行 ASP.NET Core 2.0 应用程序。 构建镜像命令: $ docker build -t hello-docker:v1 . Sending build context to Docker daemon 41.98kB Step 1/10 : FROM microsoft/aspnetcore-build AS build-env ---> d6273f7c44d4 Step 2/10 : WORKDIR /app ---> e37f90cd9aaf Removing intermediate container a4e4db93ea06 Step 3/10 : COPY *.csproj ./ ---> 56278755f94c Step 4/10 : RUN dotnet restore ---> Running in 3b7e8c5d01f4 Restoring packages for /app/HelloDocker.Web.csproj... Restore completed in 411.99 ms for /app/HelloDocker.Web.csproj. Installing System.Security.Principal.Windows 4.4.0-preview1-25305-02. Installing Microsoft.NETCore.Platforms 2.0.0-preview1-25305-02. Installing System.Security.AccessControl 4.4.0-preview1-25305-02. Installing Microsoft.Win32.Registry 4.3.0. Installing System.Security.Permissions 4.4.0-preview1-25305-02. Installing System.Diagnostics.Process 4.3.0. Installing Newtonsoft.Json 10.0.2. Installing System.Net.Http.WinHttpHandler 4.0.0. Installing CoreCompat.System.Drawing.v2 5.2.0-preview1-r131. Installing System.Data.Common 4.3.0. Installing System.Security.Cryptography.Pkcs 4.3.0. Installing System.Xml.XPath.XmlDocument 4.3.0. Installing Pomelo.EntityFrameworkCore.MySql 2.0.0. Installing MySqlConnector 0.26.4. Installing Pomelo.JsonObject 1.1.1. Installing Consul 0.7.2.3. Installing EPPlus.Core 1.5.2. Generating MSBuild file /app/obj/HelloDocker.Web.csproj.nuget.g.props. Generating MSBuild file /app/obj/HelloDocker.Web.csproj.nuget.g.targets. Restore completed in 5.71 sec for /app/HelloDocker.Web.csproj. ---> cdf6ca65acf6 Removing intermediate container 3b7e8c5d01f4 Step 5/10 : COPY . ./ ---> fffa81d15ddc Step 6/10 : RUN dotnet publish -c Release -o out ---> Running in 291c8eea750f Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. HelloDocker.Web -> /app/bin/Release/netcoreapp2.0/HelloDocker.Web.dll HelloDocker.Web -> /app/out/ ---> 078311772175 Removing intermediate container 291c8eea750f Step 7/10 : FROM microsoft/aspnetcore ---> b97d3cf55223 Step 8/10 : WORKDIR /app ---> b0637e3d706b Removing intermediate container 7095565fbbca Step 9/10 : COPY --from=build-env /app/out . ---> c3cb8a708c4b Step 10/10 : ENTRYPOINT dotnet HelloDocker.Web.dll ---> Running in d4111dc055f8 ---> 29121f0eb2b0 Removing intermediate container d4111dc055f8 Successfully built 29121f0eb2b0 Successfully tagged hello-docker:v1 上面构建镜像的过程,非常详细,我们可以得到很多的信息,这边就不叙述了,构建完镜像之后,我们可以查看下是否成功: $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-docker v1 29121f0eb2b0 Less than a second ago 284MB <none> <none> 078311772175 Less than a second ago 1.9GB microsoft/aspnetcore-build latest d6273f7c44d4 4 days ago 1.85GB microsoft/aspnetcore latest b97d3cf55223 4 days ago 280MB consul latest dff07cab6abd 9 days ago 51.8MB magiconair/fabio latest b0d96559369f 10 days ago 11.8MB hello-docker下面没命名的镜像,是临时生成的,作用是使用microsoft/aspnetcore-build镜像,还原程序包的时候,不需要重新安装了。 另外,我们可以在 ASP.NET Core 2.0 应用程序目录下,添加.dockerignore文件,来减少我们构建的镜像文件大小,示例: bin/* obj/* 需要说明下,Consul 和 Fabio 我都是部署在虚拟机的 Docker 容器中,ASP.NET Core 2.0 应用程序,我打算运行在 Mac OS 系统中,也就是说服务和 Consul 是跨服务器的。 运行命令: $ docker run -d -p 54917:54917 --name hello-docker-web hello-docker:v1 查看下是否运行成功: $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 396d42f37185 hello-docker:v1 "dotnet Hello-Dock..." Less than a second ago Up 2 seconds 0.0.0.0:54917->54917/tcp hello-docker-web $ docker logs hello-docker-web Hosting environment: Production Content root path: /app Now listening on: http://[::]:54917 Application started. Press Ctrl+C to shut down. 可以看到,运行是成功的。 我们可以请求验证下: $ curl http://10.9.10.190:54917/api/values ["value1","value2"] 或者使用 Fabio 的网关请求(Fabio 可以用作负载均衡): $ curl http://10.9.10.89:9999/hello-docker/api/values ["value1","value2"] 我们可以查看 Consul UI 中的服务是否运行正常: 或者查看 Fabio UI 中的服务是否存在(通过健康检查后会出现): 本文转自田园里的蟋蟀博客园博客,原文链接:http://www.cnblogs.com/xishuai/p/ubuntu-docker-consul-fabio-aspnet-core.html,如需转载请自行联系原作者

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

VueJS &amp;&amp; ReactJS 如何?听听别人怎么说。

使用所有新的库和框架,很难跟上所有这些库和框架,也就是说,这就需要您决定哪些是值得花时间的。 让我们看看人们说什么: “和Vue.JS一起工作是很愉快的,我发现学习曲线很浅,然而,这纯粹是基于我的经验,如前所述,我过去曾和一些人一起工作过。 默认的模板结构工作原理和Angular非常类似,所以有这个背景的开发人员可能会React上手更快。如果React像Vue.js那么容易学习的话,我真的不会不学习React,它的影响很大。 Reme Le Hane “比起React我更喜欢vue.js。在JavaScript领域vue.js是镇上新来的小子。所以我想说学习的简单性可能是第一。简洁是设计的基础。 Vue是简单的,它具有很多从Angular1和react来的概念。你可以使用它来建立任何系统 - 只是把它包含到HTML文件中。 React更大,更复杂一点(例如在设置方面)。 所以如果你想只想学一个框架,并且没有一个已经建立的系统那就选择Vue。vue.js很平易近人,提供如何把各种事情做好的更多的结构。如果你还不确定,两者都试试。也可以点击这里来阅读,ReactJS vs Vue.js vs AngularJS: https://www.agriya.com/blog/2017/03/08/angularjs-vs-vue-js/ Kathreen Riya “回答你的问题,我认为Vue.js是了解React系统的一个好方法。然而,你看完指南之前你可能会爱上Vue.js。让我告诉你,整件内容都值得一读。找个星期六开始试试吧! 在你读我的回答,我非常鼓励你看看Vue的框架比较。它非常体贴,涉及许多重要的考虑因素。 您想用哪一个平台开发?选择你自己的毒药吧。 React是几乎所有平台的理想选择。无论是Web还是原生开发,React都已经覆盖并在两个方向都成熟了。在UI开发方面,在任何上下文中都是一个灵活的开发人员。它甚至进入了虚拟现实。 Vue 2太走向原生。Evan和他的团队正在与阿里巴巴合作创造Weex,这将允许本地渲染就像React Natvie。Vue 2现在主要集中在Web开发,但也承诺支持其他平台。根据Evan的最新的Vue的博客,2017对Weex是重要的一年。 你想多久才开始开发呢?为什么不今天就开始,而要等几个星期? React有陡峭的学习曲线。它的文件和术语在某些概念是不同寻常,而凌乱,在Vue中指南,属性名称,安装过程,等一切感觉很熟悉,与更广泛的HTML,CSS和ES6标准一致。感谢这两个框架,他们的社区欣欣向荣。你可以找到大量的资源来启动。 我面临的最大障碍是理解构建工具链:Webpack,JSX,我的文本编辑器插件等等。 然而,Vue不需要Webpack,或任何其他事情。你可以马上通过ES5快速的写应用包括使用你最喜爱的软件包管理器或CDN的框架。这意味着你可以用CodePen和其他代码共享的环境。 React最近推出了create-React-app。你可以将这个和Vue的命令行工具进行对比。 在专业领域… Vue一直有大牌公司像gitlab,Laravel,PageKit等采用。 Vue仍然感觉像在我的开发周期上新的孩子。然而,许多开发商在我公司(IHS Markit)已经开始采用Vue,在考虑Angular和React太重。 React很受欢迎,而且已经持续很久了。可能更多的企业使用了React。如果你现在找一份新工作,那就记住这一点。 在过去的几个月里(下降2016),我看过很多文章说:“为什么我们选择vue.js超过React和Angular…”。vue.js获得牵引力,快捷,越来越多的人意识到它是多么容易使用。 再来看看Vue迷… 包括状态管理和路由!你已经知道了关于Flux/Redux,这就是Vue所提供的: Vuex是Vue的Flux/Redux/Elm-inspired的实现,专门针对使用Vue的响应系统。其系统的mutations, getters,actions非常协调,与您的组件集成很容易。不过,如果你更喜欢用Redux,Vue用Revue也是很酷的。无论哪种方式,知道如何使用状态管理系统是一种很有价值的模式。 如果你需要URL路径和参数Vue-Router是该死的简单而强大。只要检查一下文档就ok了。 其他值得注意的事情… Vue的文档是一个梦。我不能告诉足够多的人它的指南和API参考有多大。Evan You(作者和项目负责人)有一种将现代开发提供给门外汉的方式。即使是经验丰富的开发人员,这也是令人耳目一新的。 写单文件vue组件感觉很自然 - 我从来没有回头,因为。这不需要Webpack,但没有恐惧,Vue提供了一个非常方便的命令行工具来帮助你产生很小的安装骨干项目。如果你喜欢Browserify,也不用担心。炼狱,你可以写你自己的CLI模板,如果你想要的话!提供的模板非常灵活。 Vue 2支持服务器端渲染,帮你做SEO,让你的网站可以呈现给禁用javascript的人。 最后,不断有什么给我印象深刻的东西,再次回来的Vue.js是其突出的社区,Evan和他的贡献很专业,它的易用性,其显而易见的对齐与Web部件标准。我被这个项目的成功所震惊,创造出几乎任何我能梦想得到的前端都是多么令人愉快的事情。 Andy Merskin 我也来这儿。 我花了大约一年的时间来处理这个问题。我最近换了Vue在过去的几个月里,我没有回头。关于Vue的一些事情让我沉迷过度了,即: JSX - 我讨厌JSX。它总是花费我几秒钟的时间,如果不是几分钟就万幸了。我每次打开项目要接受这个事实,我一直在寻找一个JavaScript组件包括风格、传统的JavaScript方法和UI元素都支持的一个模块化的野兽。它很快就老化了。 重命名传统HTML属性 - 传统HTML类和风格的元素属性。哦,React也能做到,你所要做的就是确保你所有的类的属性称为类名和样式属性没有字符串值了。想象一下,试图创建一个基于购买的现有主题的网站。把它换成React就像用刀子刺眼球一样。而对Vue,现有的HTML只是普通的工作。你想“reactify”吗?继续,但这不是React中所要求的。 打包需要 - 所以React就只是UI层吗?他们是正确的;你甚至也可以不需要WebPack或任何其他的打包机。但是如果没有它们,你可以尝试建造任何实质性的东西,你都会很难过的。你开始拉动左右,使功能和所有那些假定WebPack包。如果你只是写“hello world”,然后只使用React可以。别的,你就得开始阅读所有的打包内容。 josullivan “我用Angular1一年多一点,然后切换到React。我已经看了Vue几次却从来没有建立任何东西,那就是说我什么也没听到,但伟大的事情,从外观上来看,它是很容易。 我准备采取行动,原因有3: 这是目前最流行的:这很重要,最受欢迎的是它拥有最多的在线资源,更好的工作机会,更有可能获得长期的成功(除非他们使用谷歌的Angular1)。 它是通用的:有库允许您使用React来编写移动甚至桌面应用程序(尽管我还没有亲自尝试构建桌面应用程序)。Vue也将推出自己的混合移动框架,但即使当它来到的时候,我严重怀疑它会赶上React,有多少人考虑重头开始考虑到RN有及其社区的规模。 这很复杂,很难学:我不同意大多数人的观点,说这个不是学习React的好理由,而且实际上是我喜欢React的原因之一。学习React会让你成为更好的JavaScript开发人员。React很难,因为: 它使用了很多中间高级JS概念。像一个深入了解的对象,“this”关键词和一些功能的编程概念是必要的工作,React的效率(最后一个是更相关的如果你使用Redux)。它也将更可能迫使你学习ES6如果你还不知道。 你需要的工具只有1件套,所以你必须依靠终极版的其他库。开始时这可能很痛苦,但它教你如何混合、匹配和连接不同的库。也让你能够定制你的工具,你认为合适或甚至将React放进Angular/Vue应用如果你只想用它在你的应用程序的某些部分的优势。 它通常用到构建工具像WebPack(虽然它实际上并不需要他们)。Vue是建立更加容易没有编译工具,但是相当多的任何真实世界的应用都将是最终使用编译工具,无论如何,这是唯一的一个优势,如果你还在学习,只是想跳过麻烦去更快建设。即使是这样的话,你仍然可以通过使用项目生成器,比如创建React应用程序来跳过所有配置并直接构建。 前端开发的问题是js生态系统可能非常不稳定,框架在不断变化。因此,我认为,不是寻找最简单、最强大、最流行的框架,而是作为一个开发人员长期学习有用的东西(尽管React也有最流行的东西),这可能更有用。即使React最终变得过时,我也不会对学习它感到后悔,因为当我开始学习JavaScript的时候,我知道的比我想知道的还要多。 Ahmed Wagdi “这些天我很少做网页,大多工作在后端数据处理、网络I/O和分布式通信。 一年多一点以前,我想要的是一个实时的Web UI想象一些我对服务器端的数据,我想用SignalR。我回到了一些流行的框架,有一个非常简单的思维方式:“我可以阅读‘入门’,然后在15分钟内开始一些基本的工作吗?”。 我最终选择了Vue,主要是因为它使用简单的对象模型和我真的只是过去的东西我可以从SignalR直接进入并显示。我所尝试的几乎所有其他的东西围绕着数据都有某种类型的打包器/代理,这意味着你必须运行一些映射才可以使模型正常工作。我几乎决定用Mithril,但是当我发现这只是我的需要与Vue重合更多。其实我真的想用React,但Vue只是更平易近人,我不需要花费额外的时间学习React。 然而,真正的考验是几个月后,我去修改和添加更多的功能到我的简单调试UI中。我几乎可以立即拿起它,甚至做了相当大的改动。 与我的经历相比,Ember。我们有一个大的应用程序基于Ember编写,每一次我试图做的是我认为应该是一个简单的改变(不接触的几个月后),我花了比我想象的要长5倍,我花了大部分的时间与它作战之前实现我忘了5个的地方,你必须修改参考额外的依赖或其它一些同样平凡但真气人的细节。 你可以学习Vue在分钟的基础知识,并在几个小时内很内行。这是不是很多的框架,可以说,这是一个被严重低估的好处。 gregmac 这篇文章最初发表在bootstrapbay博客 - https://bootstrapbay.com/blog/vuejs-vs-reactjs/ 各位,你们怎么看?在这场辩论中,请随意点儿,别忘了分享你的体验,这样其他人就能了解到你的想法。 汇智网(www.hubwiz.com,大量最新的vue/react/angular课程),小智翻译。 原文发布时间为:2018年01月05日原文作者:笔阁 本文来源:开源中国 如需转载请联系原作者

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

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部分的功能。

用户登录
用户注册