有明

有明 查看完整档案

杭州编辑河海大学  |  计算机科学与技术 编辑  |  填写所在公司/组织 youmingdot.com 编辑
编辑

支持一下杭州本土网站。

Laravel - 艺术家成长之路系列讲座

SF | 有明的技术交流群,欢迎大家加入交流分布式、服务化、设计模式、算法、Laravel、Docker、Swoole。QQ 群:666093315,进群还有讲座优惠福利

个人动态

有明 赞了文章 · 2020-09-04

阿里云体验实验室 教你如何《快速搭建Docker环境》

体验平台简介

面向开发者和中小企业打造的一站式、全云端的开发平台,打开浏览器就可以开发、调试、上线,所测即所得,并结合无服务器的模式,重新定义云原生时代的研发工作方法论。旨在降低开发者上手成本和中小企业的启动成本、运营成本、以及突发流量带来的运维风险。

教程介绍

本教程介绍如何快速搭建Docker环境,并使用Docker部署一个Nginx服务。

场景体验

场景内容选自 阿里云体验实验室
阿里云体验实验室 提供一台配置了CentOS 7.7的ECS实例(云服务器)。通过本教程的操作,您可以基于ECS实例搭建Hadoop伪分布式环境。

阿里云 场景免费资源
https://developer.aliyun.com/adc/scenario/9fd79b8711984e309f20d82bc65a26fa

背景知识

容器技术
容器是一个允许我们在资源隔离的过程中,运行应用程序和其依赖项的 、轻量的 、操作系统级别的虚拟化技术, 运行应用程序所需的所有必要组件都打包为单个镜像,这个镜像是可以重复使用的。当镜像运行时,它是运行在独立的环境中,并不会和其他的应用共享主机操作系统的内存、CPU或磁盘。这保证了容器内的进程不会影响到容器外的任何进程。

Docker
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器或Windows机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。

Docker底层用的Linux的cgroup和namespace这两项技术来实现应用隔离,一个完整的Docker有以下几个部分组成:

Docker Client客户端
Docker Daemon守护进程
Docker Image镜像
Docker Container容器

步骤一:安装Docker CE

Docker有两个分支版本:Docker CE和Docker EE,即社区版和企业版。

本教程基于CentOS 7安装Docker CE。
1.安装Docker的依赖库。

yum install -y yum-utils device-mapper-persistent-data lvm2

2.添加Docker CE的软件源信息。

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

3.安装Docker CE。

yum makecache fast
yum -y install docker-ce

4.启动Docker服务。

systemctl start docker

步骤二:配置阿里云镜像仓库(镜像加速)

Docker的默认官方远程仓库是hub.docker.com,由于网络原因,下载一个Docker官方镜像可能会需要很长的时间,甚至下载失败。为此,阿里云容器镜像服务ACR提供了官方的镜像站点,从而加速官方镜像的下载。下面介绍如何使用阿里云镜像仓库。
1.使用体验平台提供的阿里云子账号登录容器镜像服务控制台。
在这里插入图片描述
2.单击镜像中心 > 镜像加速器,可以看到阿里云为您提供了一个专属的镜像加速地址。
在这里插入图片描述
3.配置Docker的自定义镜像仓库地址。请将下面命令中的镜像仓库地址https://kqh8**.mirror.aliyuncs.com替换为阿里云为您提供的专属镜像加速地址。

tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://kqh8****.mirror.aliyuncs.com"]
}
EOF

4.重新加载服务配置文件。

systemctl daemon-reload

5.重启Docker服务。

systemctl restart docker

步骤三:使用Docker安装Nginx服务

1.查看Docker镜像仓库中Nginx的可用版本。

docker search nginx

命令输出如下所示:
在这里插入图片描述
2.拉取最新版的Nginx镜像。

docker pull nginx:latest

命令输出如下所示:
在这里插入图片描述
3.查看本地镜像。

docker images

命令输出如下所示:
在这里插入图片描述

4.运行容器。

docker run --name nginx-test -p 8080:80 -d nginx

命令参数说明:

--name nginx-test:容器名称。
-p 8080:80: 端口进行映射,将本地8080端口映射到容器内部的80端口。
-d nginx: 设置容器在后台一直运行。

命令输出如下所示:
在这里插入图片描述
5.在浏览器地址栏输入http://&lt;ECS公网IP地址>:8080访问Nginx服务。
在这里插入图片描述

以上就是【快速搭建Docker环境】 的所有教程了

更多体验场景请至开发者实验室:https://developer.aliyun.com/adc/labs/

查看原文

赞 2 收藏 2 评论 0

有明 关注了用户 · 2020-09-04

阿里云体验实验室 @bainana

阿里云开发者实验室提供免费云资源和丰富的场景化实践,旨在帮助开发者在学习应用技术,了解阿里云产品的特性。

关注 3

有明 回答了问题 · 2020-07-20

解决try catch 什么时候用

阿里巴巴 Java 开发手册里有段话:(仅供参考)

【强制】异常不要用来做流程控制,条件控制。
说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。

用异常做流程控制,是件很爽的事情,因为它看清来更清晰、简单。但是它也有坏处,异常的创建意味着栈信息的收集等一系列有关的操作,这对于正常的业务来说除了拖累性能没有其他作用。

那到底该不该用异常处理业务逻辑呢?个人觉得,这是可取的。正如刚才说的,异常的优势就是清晰、简单,让我们的程序更好看,更容易明白。至于性能之类的,我想应该交给框架、语言去优化。

另外,自己不处理的异常,丢出去很优雅,也很符合原则。为什么你会觉得不好呢……

关注 6 回答 4

有明 回答了问题 · 2018-12-31

解决消息队列和消息中间件的区别是什么?

如果真的进行细分,可以认为消息队列是消息中间件的一部分,消息中间件是消息队列的超集。

严格来说,消息队列指的就是能够提供消息排队消费功能的软件程序。

而消息中间件,可以理解为在消息队列的基础增加了一些延迟发送、分布式事务等功能的软件程序。

关注 4 回答 3

有明 评论了文章 · 2018-12-06

mysql自增id超大问题查询

引言

小A正在balabala写代码呢,DBA小B突然发来了一条消息,“快看看你的用户特定信息表T,里面的主键,也就是自增id,都到16亿了,这才多久,在这样下去过不了多久主键就要超出范围了,插入就会失败,balabala......”

我记得没有这么多,最多1k多万,count了下,果然是1100万。原来运维是通过auto_increment那个值看的,就是说,表中有大量的删除插入操作,但是我大部分情况都是更新的,怎么会这样?
图片描述

问题排查

这张表是一个简单的接口服务在使用,每天大数据会统计一大批信息,然后推送给小A,小A将信息更新到数据库中,如果是新数据就插入,旧数据就更新之前的数据,对外接口就只有查询了。

很快,小A就排查了一遍自己的代码,没有删除的地方,也没有主动插入、更新id的地方,怎么会这样呢?难道是小B的原因,也不太可能,DBA那边儿管理很多表,有问题的话早爆出来了,但问题在我这里哪里也没头绪。

小A又仔细观察了这1000多万已有的数据,将插入时间、id作为主要观察字段,很快,发现了个问题,每天第一条插入的数据总是比前一天多1000多万,有时候递增的多,有时候递增的少,小A又将矛头指向了DBA小B,将问题又给小B描述了一遍。

小B问了小A,“你是是不是用了REPLACE INTO ...语句”,这是怎么回事呢,原来REPLACE INTO ...会对主键有影响。

REPLACE INTO ...对主键的影响

假设有一张表t1:

CREATE TABLE `t1` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID,自增',
  `uid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户uid',
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户昵称',
  PRIMARY KEY (`id`),
  UNIQUE KEY `u_idx_uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试replace into';

如果新建这张表,执行下面的语句,最后的数据记录如何呢?

insert into t1 values(NULL, 100, "test1"),(NULL, 101, "test2");
replace into t1 values(NULL, 100, "test3");

图片描述

原来,REPLACE INTO ...每次插入的时候如果唯一索引对应的数据已经存在,会删除原数据,然后重新插入新的数据,这也就导致id会增大,但实际预期可能是更新那条数据。

小A说:“我知道replace是这样,所有既没有用它”,但还是又排查了一遍,确实不是自己的问题,没有使用REPLACE INTO ...

小A又双叒叕仔细的排查了一遍,还是没发现问题,就让小B查下binlog日志,看看是不是有什么奇怪的地方,查了之后还是没发现问题,确实存在跳跃的情况,但并没有实质性的问题。

下图中@1的值对应的是自增主键id,用(@2, @3)作为唯一索引

图片描述

后来过了很久,小B给小A指了个方向,小A开始怀疑自己的插入更新语句INSERT ... ON DUPLICATE KEY UPDATE ...了,查了许久,果然是这里除了问题。

INSERT ... ON DUPLICATE KEY UPDATE ...对主键的影响

这个语句跟REPLACE INTO ...类似,不过他并不会变更该条记录的主键,还是上面t1这张表,我们执行下面的语句,执行完结果是什么呢?

insert into t1 values(NULL, 100, "test4") on duplicate key update name = values(name);

图片描述

没错,跟小A预想的一样,主键并没有增加,而且name字段已经更新为想要的了,但是执行结果有条提示,引起了小A的注意

No errors; 2 rows affected, taking 10.7ms

明明更新了一条数据,为什么这里的影响记录条数是2呢?小A,又看了下目前表中的auto_increment

CREATE TABLE `t1` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID,自增',
  `uid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户uid',
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户昵称',
  PRIMARY KEY (`id`),
  UNIQUE KEY `u_idx_uid` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='测试replace into';

竟然是5`,这里本应该是4的。

也就是说,上面的语句,会跟REPLACE INTO ...类似的会将自增ID加1,但实际记录没有加,这是为什么呢?

查了资料之后,小A得知,原来,mysql主键自增有个参数innodb_autoinc_lock_mode,他有三种可能只0,1,2,mysql5.1之后加入的,默认值是1,之前的版本可以看做都是0

可以使用下面的语句看当前是哪种模式

select @@innodb_autoinc_lock_mode;

小A使用的数据库默认值也是1,当做简单插入(可以确定插入行数)的时候,直接将auto_increment加1,而不会去锁表,这也就提高了性能。当插入的语句类似insert into select ...这种复杂语句的时候,提前不知道插入的行数,这个时候就要要锁表(一个名为AUTO_INC的特殊表锁)了,这样auto_increment才是准确的,等待语句结束的时候才释放锁。还有一种称为Mixed-mode inserts的插入,比如INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d'),其中一部分明确指定了自增主键值,一部分未指定,还有我们这里讨论的INSERT ... ON DUPLICATE KEY UPDATE ...也属于这种,这个时候会分析语句,然后按尽可能多的情况去分配auto_incrementid,这个要怎么理解呢,我看下面这个例子:

truncate table t1;
insert into t1 values(NULL, 100, "test1"),(NULL, 101, "test2"),(NULL, 102, "test2"),(NULL, 103, "test2"),(NULL, 104, "test2"),(NULL, 105, "test2");

-- 此时数据表下一个自增id是7

delete from t1 where id in (2,3,4);

-- 此时数据表只剩1,5,6了,自增id还是7

insert into t1 values(2, 106, "test1"),(NULL, 107, "test2"),(3, 108, "test2");

-- 这里的自增id是多少呢?

上面的例子执行完之后表的下一个自增id是10,你理解对了吗,因为最后一条执行的是一个Mixed-mode inserts语句,innoDB会分析语句,然后分配三个id,此时下一个id就是10了,但分配的三个id并不一定都使用。此处@总是迟到 多谢指出,看官方文档理解错了

模式0的话就是不管什么情况都是加上表锁,等语句执行完成的时候在释放,如果真的添加了记录,将auto_increment加1。

至于模式2,什么情况都不加AUTO_INC锁,存在安全问题,当binlog格式设置为Statement模式的时候,从库同步的时候,执行结果可能跟主库不一致,问题很大。因为可能有一个复杂插入,还在执行呢,另外一个插入就来了,恢复的时候是一条条来执行的,就不能重现这种并发问题,导致记录id可能对不上。

至此,id跳跃的问题算是分析完了,由于innodb_autoinc_lock_mode值是1,INSERT ... ON DUPLICATE KEY UPDATE ...是简单的语句,预先就可以计算出影响的行数,所以不管是否更新,这里都将auto_increment加1(多行的话大于1)。

如果将innodb_autoinc_lock_mode值改为0,再次执行INSERT ... ON DUPLICATE KEY UPDATE ...的话,你会发现auto_increment并没有增加,因为这种模式直接加了AUTO_INC锁,执行完语句的时候释放,发现没有增加行数的话,不会增加自增id的。

INSERT ... ON DUPLICATE KEY UPDATE ...影响的行数是1为什么返回2?

为什么会这样呢,按理说影响行数就是1啊,看看官方文档的说明

With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the row is inserted as a new row, 2 if an existing row is updated, and 0 if an existing row is set to its current values

官方明确说明了,插入影响1行,更新影响2行,0的话就是存在且更新前后值一样。是不是很不好理解?

其实,你要这样想就好了,这是为了区分到底是插入了还是更新了,返回1表示插入成功,2表示更新成功。

解决方案

innodb_autoinc_lock_mode设置为0肯定可以解决问题,但这样的话,插入的并发性可能会受很大影响,因此小A自己想着DBA也不会同意。经过考虑,目前准备了两种较为可能的解决方案:

修改业务逻辑

修改业务逻辑,将INSERT ... ON DUPLICATE KEY UPDATE ...语句拆开,先去查询,然后去更新,这样就可以保证主键不会不受控制的增大,但增加了复杂性,原来的一次请求可能变为两次,先查询有没有,然后去更新。

删除表的自增主键

删除自增主键,让唯一索引来做主键,这样子基本不用做什么变动,只要确定目前的自增主键没有实际的用处即可,这样的话,插入删除的时候可能会影响效率,但对于查询多的情况来说,小A比较两种之后更愿意选择后者。

结语

其实INSERT ... ON DUPLICATE KEY UPDATE ...这个影响行数是2的,小A很早就发现了,只是没有保持好奇心,不以为然罢了,没有深究其中的问题,这深究就起来会带出来一大串新知识,挺好,看来小A还是要对外界保持好奇心,保持敏感,这样才会有进步。

查看原文

有明 回答了问题 · 2018-12-02

解决PHP闭包函数的问题

因为你上面的代码用了两个 = function () {},定义了两个嵌套的闭包。俩闭包对两个括号,这不是很合理么。

关注 5 回答 5

有明 评论了文章 · 2018-12-02

对 SegmentFault 社区提问标准的一些解释

有心的用户应该发现最近 SegmentFault 问答的审核趋向严格,甚至一些已经正常展示的问题都会因质量问题提示作者修改。随着社区用户的增长,新进入用户的习惯正逐渐冲击着之前社区形成的默契,我们的问答质量出现了一定程度的下降。这对整个社区的运营提出了挑战,我们不希望发生劣币驱逐良币的状况,因此有必要在这个问题上达成新的共识。

应该说 SegmentFault 的提问一直都是有具体的标准的(https://segmentfault.com/faq#...),但是在具体理解的时候每个人都会产生偏差,为了尽量缩小这个偏差,我们约定如下几个提问的原则:

  1. 回答者优先
  2. 考虑后来者

回答者优先

当你理解了回答者优先的原则,就会自然而然地理解我们的运营规范,甚至你都不需要时刻记住这些规范,因为它们只是保证这一原则的最低要求。

什么是回答者优先?简而言之,就是你在提问的时候要优先考虑回答者能否清晰准确地知晓你要表达的意思,我们在审核的时候也是以这一条标准做为最优先的准则。提问者怎么判断呢?很简单,把自己置于回答者的位子上去审视一下你的问题,看看做为回答者的你是否可以通过这些表述知晓题意。

以这条原则为出发点,我们会对存在以下情况的问题说不:

  1. 问题表述过于简略,往往就一句话甚至一个标题的。(举例:标题是“如何实现一个淘宝一样的网站?”,内容是:“如题”)
  2. 问题中完全没有自己的观点,也就是传说中的伸手党。伸手党的存在主要有两大害处,第一,你没有说出已经尝试过哪些方法,没有尽量为回答者排除错误情况,会大大降低回答者的答题效率。第二,你的付出过少,无法达到回答者的心里预期,会大大影响回答者的答题积极性。用通俗的话说就是,你自己都不重视自己的事情,其他人又凭什么去帮你呢?
  3. 问题的排版过于混乱。从语法上讲,我们并不认为 Markdown 语法比你手上要写的任何编程语言语法更加复杂。而混乱的排版至少表明你并不重视这个问题,也不重视回答者的感受。很多人没有把代码用 Markdown 包裹起来,我们也视为排版混乱。
  4. 没有代码或者用图片代替了代码。这是一个最近比较突出的问题,代码胜千言,准确简短的描述配上必要的代码,比你说一大堆废话要好得多,我们已经看到了无数可爱的回答者在问题下方的评论中呼唤代码。与不贴代码相比,用代码截图来代替代码走入了另一个误区,让我们还是站在回答者的角度,当你面对上百行没头没尾的代码时,怎么去调试它们呢?你想让回答者浪费自己宝贵的时间,照着你们的图片一个字一个字的敲进去么?所以,当你要这么做的时候,想一想本章的标题“回答者优先”。在这里,还有一个比较特殊的情况,就是错误信息算不算代码,可不可以用截图代替?在这里,给出明确的答复:算。大部分的错误信息,包括浏览器的出错,c, java等预编译语言的运行时错误,都是一个简单的文本,你可以直接用鼠标选中复制,用 Markdown 的代码块语法包裹后附加到问题里。这样可以大大方便回答者定位错误。

考虑后来者

考虑后来者可以说是我们创建这个社区的一大目的,我们之所以让大家的问题可以公开讨论,就是为了降低在开发领域的信息不对称,让后来者少走弯路。为了做到这一点,我们提倡大家:

  1. 标题应该直接地表达问题的中心思想,如果你是因为运行时抛出某些错误而提问,你可以直接写“为什么JAVA运行时抛出xxxx异常?”。而不要写什么“一个关于JAVA的问题?”,请问做为一个后来者,我能从你的标题里获得什么重要的信息呢?如果这则问题被搜索引擎索引了,后来者遇到同类问题是怎么搜索的呢?大家想想你们搜问题,是不是喜欢把错误信息直接丢到搜索框里,那么怎样才算一个有用的问题就不言而喻了。
  2. 不要用图片代替代码,不要用图片代替代码,不要用图片代替代码!图片里的内容不能被任何搜索引擎检索到,你的问题会变成信息海洋里的垃圾沉没水底,这不是我们做为社区所提倡的。
  3. 用好标签。标签的作用在于更好地组织内容,这也是为了方便后来者。所以首先不要滥用,你的标签一定要跟问题相关。其次,标签不是用来描述问题的,不要自己创造一些描述性的语言做为标签。通常选择标签就选择这个问题所涉及到的技术就可以了,而且尽量至少使用一个大的语言标签,比如“php, java, c, javascript” 等等。

一些措施

俗话说“用霹雳手段,显菩萨心肠”,我们的菩萨心肠在上面已经告诉大家了。为了保证这些目的能够达到,我们将采取一系列措施。除了在审核时我们会严格按照标准来执行之外,我们还鼓励大家共同维护社区的秩序。大家可以通过评论来提醒一些违规的内容,或者使用举报和建议关闭功能。

我们针对把代码截图到图片里的行为,专门开发了自动扫描机器人,它会最大程度地去监控这一行为,一旦发现这一情况会提醒你修改问题。如果在一小时内没有修改的话,这个问题会被提交人工审核后处理。注意:机器人可能存在误判行为,如果你确定你的内容没有存在这种情况,请放心交给我们人工审核即可,我们会及时处理。

写在最后

当我们在6年前创立 SegmentFault 的时候,愿景是做一个高质量的中文技术问答社区。当然现在 SegmentFault 上承载的不止有问答的内容,但它依然是整个社区重要的组成部分。经常有人向我们抱怨国内技术社区的讨论氛围,思想浮躁,问题质量差,伸手党盛行等等。当我们体量比较小的时候,我们总是以提高素质还需要时间之类的理由来安慰自己或者他人。而当我们逐渐成长为国内技术问答领域一支重要力量之后,我们已经无法逃避肩上的责任,因此我们希望带领整个社区一起进步,共同打造一个属于我们自己的技术家园。

更多阅读

查看原文

有明 回答了问题 · 2018-09-26

解决求助:docker启动nginx mime.types 和 fastcgi_params 报错

先检查一下你的挂载配置,有时候有的朋友喜欢把整个 nginx 配置目录挂载到 /etc/nginx 里。殊不知你只在这个目录里加了 nginx.conf ,但容器中 /etc/nginx 目录下面还有很多其他的文件,你直接挂载整个目录进去,其他的文件便会随着目录的挂载而消失,自然读取配置会出现问题。

解决这个问题的方法有两种:

  1. 把目录挂载改为文件挂载,只挂载 nginx.conf ,也就是 -v ~/nginx/nginx.conf:/etc/nginx/nginx.conf
  2. 是把容器中 /etc/nginx 目录中的其他内容也拷贝到要挂载的目录里,随着目录一起挂载进去

关注 4 回答 3

认证与成就

  • SegmentFault 讲师
  • 获得 1360 次点赞
  • 获得 39 枚徽章 获得 1 枚金徽章, 获得 15 枚银徽章, 获得 23 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2015-09-04
个人主页被 22.3k 人浏览