AutoScaling 与函数计算结合,赋予更丰富的弹性能力

目前,弹性伸缩服务已经接入了负载均衡(SLB)、云数据库RDS 等云产品,但是暂未接入 云数据库Redis,有时候我们可能会需要弹性伸缩服务在扩缩容的时候自动将扩缩容涉及到的 ECS 实例私网 IP 添加到 Redis 白名单或者从 Redis 白名单中移除。本文将给出上述场景的最佳实践,向您介绍如何通过 AutoSclaing -> LifecycleHook -> MNS -> FC 的方式实现伸缩组发生扩容时自动将扩容出来的 ECS 实例私网 IP 添加到 Redis 白名单中,您可以在此基础上,根据您的业务需求进行扩展。

函数计算(FC)简介

阿里云函数计算是事件驱动的全托管计算服务。通过函数计算,您无需管理服务器等基础设施,只需编写代码并上传。函数计算会为您准备好计算资源,以弹性、可靠的方式运行您的代码,并提供日志查询、性能监控、报警等功能。借助于函数计算,您可以快速构建任何类型的应用和服务,无需管理和运维。而且,您只需要为代码实际运行所消耗的资源付费,代码未运行则不产生费用。更多关于函数计算的相关信息,您可以通过 函数计算官方文档 进行了解。

消息服务(MNS)简介

阿里云消息服务(Message Service,简称 MNS)是一种高效、可靠、安全、便捷、可弹性扩展的分布式消息服务。MNS能够帮助应用开发者在他们应用的分布式组件上自由的传递数据、通知消息,构建松耦合系统。更多关于消息服务的相关信息,您可以通过 消息服务官方文档 进行了解。

最佳实践

前提条件

在进行以下操作前,您需要先开通 函数计算服务FC 、 消息服务MNS 、弹性伸缩服务AutoScaling,接下来配置我们需要用的 FC、MNS、AutoScaling 相关信息

配置 MNS

登录 MNS控制台,创建 MNS 主题(作为函数计算的触发器),如下图所示:

image

同样的,创建 MNS 队列,MNS 队列作为函数计算执行结果接收器,队列名称会在代码中进行配置。

配置 FC

登录FC控制台,新建服务,如下图所示:

image

服务创建好以后,新增函数,如下图所示:

image

点击新增函数,弹出新建函数对话框,如下图所示:

image

选择函数语言,并选择空白模板,跳转到触发器配置界面,如下图所示:

image

配置好触发器类型、触发器名称以及对应的 MNS 主题(MNS 主题与 FC 所属的地域最好相同),点击下一步,跳转到基础管理配置界面,如下图所示:

image
image

所在服务默认会选择当前服务,不用改变,填写函数名称,选择运行环境,通过代码包上传的方式上传提前测试好的 java jar包(即触发函数计算时需要执行的运行的程序,本文最后会给出示例jar包),按照说明填写好函数入口,点击下一步,跳转到模版授权管理界面,如下图所示:

image
image

首先授予函数运行所需要的权限,授权时候应遵循权限最小化原则,防止权限过大,如上图步骤1、2所示,再授予 MNS 触发 FC 所需的权限,如上图步骤3、4所示,最后点击下一步,跳转到信息核对界面,如下图所示:

image

核对信息无误,点击创建,函数创建完成。

关于函数计算的配置过程,您可以通过 FC Hello World示例 进行了解。

创建云数据库 Redis

登录 Redis控制台,选择和 MNS 、FC 相同的地域,创建 Redis 实例。实例创建完以后,查看实例的白名单设置,如下图所示:
image

配置 AutoScaling

登录 弹性伸缩控制台,创建好伸缩组以及伸缩配置以后,创建生命周期挂钩(LifecycleHook),如下图所示:

image

上图中,在左侧导航栏选择生命周期挂钩,点击创建生命周期挂钩按钮,填写名称,选择生命周期挂钩对应的伸缩活动类型,配置生命周期挂钩对应的 MNS 通知为 MNS 主题,并且选择的主题为 FC 触发器对应的主题,最后点击创建按钮,生命周期挂钩函数创建完成,如下图所示:

image

在伸缩组发生扩容伸缩活动时,实例创建完成并运行起来以后,生命周期挂钩会被触发,并发送伸缩活动相关信息到生命周期挂钩配置的 MNS 主题上,挂起当前的伸缩活动,直到生命周期挂钩超时或者被提前结束。生命周期挂钩活动结束以后,伸缩活动继续执行,扩容出来的 ECS 实例会被挂载到负载均衡实例上(如果伸缩组配置了负载均衡实例的话)。关于生命周期挂钩功能的详细说明,您可以通过云栖博客 AutoScaling 生命周期挂钩功能 进行详细了解。

触发扩容伸缩活动

首先,我们通过触发扩容伸缩活动的方式,创建 10 台 ECS 实例,对应的伸缩活动如下图所示:

image

然后我们登录 MNS控制台,查看队列接收到的 FC 执行结果消息,如下图所示:

image

上述消息中 success 为 true,表示函数计算执行成功(即 ECS 实例私网 IP 添加到 Redis 白名单成功),消息体中还包括了当前生命周期挂钩活动对应的 LifecycleHookId LifecycleActionToken 参数信息,您可以根据相关参数信息调用 CompleteLifecycleAction 接口提前结束生命周期活动。

最后,我们登录 云数据库Redis控制台,查看当前的 Redis 白名单信息,如下图所示:

image

从上图可以看出,弹性伸缩扩容活动创建出来的 ECS 实例私网 IP 成功添加到 Redis 白名单中。

至此,通过 AutoScaling -> LifecycleHook -> MNS -> FC 实现 Redis 白名单自动添加的过程结束,整体过程如下:

  1. 弹性伸缩组触发扩容伸缩活动,扩容 ECS 实例,扩容活动触发生命周期挂钩
  2. 生命周期挂钩将扩容活动挂起,同时发送消息到 MNS 主题
  3. MNS 主题接收到消息以后将消息作为输入信息触发 FC,FC 被触发以后执行预置业的 JAVA 函数
  4. JAVA 函数获取 FC 触发器的输入信息,信息中包括了本次伸缩活动对应的 ECS 实例 ID信息,通过接口获取 ECS 实例私网 IP 以后添加到 Redis default 分组白名单中
  5. 最后,函数执行结果发送到代码中配置好的 MNS 队列中

上述过程仅作为一个参考的 Demo,进一步实现自动化管理,还需要我们自己编程实现,如编程的方式消费 MNS 队列中的消息,获取执行结果与 LifecycleHookId LifecycleActionToken等参数信息提前结束生命周期挂钩活动等。

FC 预置 JAVA 代码解析

FC 预置函数为 JAVA 代码,通过 Maven 管理,对应的代码及依赖如下:

Example.java

package fc;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.StreamRequestHandler;
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.model.Message;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.ecs.model.v20140526.DescribeInstancesRequest;
import com.aliyuncs.ecs.model.v20140526.DescribeInstancesResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.r_kvstore.model.v20150101.DescribeSecurityIpsRequest;
import com.aliyuncs.r_kvstore.model.v20150101.DescribeSecurityIpsResponse;
import com.aliyuncs.r_kvstore.model.v20150101.ModifySecurityIpsRequest;
import model.FCResult;
import model.HookModel;
import model.MnsMessageModel;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Example implements StreamRequestHandler {/*** 专有网络类型,此参数不用变*/private static final String  VPC_NETWORK                 = "vpc";private static final String  CHAR_SET                    = "UTF-8";/*** 接收input数组大小,4096通常够用*/private static final Integer MAX_BYTE_LENGTH             = 4096;/*** REDIS 白名单默认分组*/private static final String  DEFAULT_SECURITY_GROUP_NAME = "default";/*** REDIS 修改白名单的模式*/private static final String  MODIFY_MODE_APPEND          = "Append";/*** MNS 客户端发送消息地址*/private static final String  MNS_END_POINT               = "http://%s.mns.%s.aliyuncs.com/";/*** 待添加的REDIS实例ID,根据个人情况替换*/private static final String  REDIS_ID                    = "";/*** 接收本次函数计算执行结果的队列名称,根据个人情况替换*/private static final String  QUEUE_NAME                  = "wujin-fc-callback";/*** 阿里云账号UID,根据跟人情况替换*/private static final Long    USER_ID                     = 1111111111111111111L;/*** 伸缩组 MNS FC 所属的region,根据个人情况替换*/private static final String  REGION_ID                   = "cn-hangzhou";@Overridepublic void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) {FCResult result = new FCResult();String akId = context.getExecutionCredentials().getAccessKeyId();String akSecret = context.getExecutionCredentials().getAccessKeySecret();String securityToken = context.getExecutionCredentials().getSecurityToken();try {//获取MNS触发函数计算时输入的内容String input = readInput(inputStream);MnsMessageModel mnsMessageModel = JSON.parseObject(input,new TypeReference<MnsMessageModel>() {});if (mnsMessageModel == null) {result.setSuccess(false);result.setMessage("mnsMessageModel is null");sendMns(akId, akSecret, securityToken, result.toString());return;}HookModel contentModel = mnsMessageModel.getContent();if (contentModel == null) {result.setSuccess(false);result.setMessage("contentModel is null");sendMns(akId, akSecret, securityToken, result.toString());return;}IAcsClient client = buildClient(akId, akSecret, securityToken);//获取本次伸缩活动对应实例的私网IPList<String> privateIps = getInstancesPrivateIps(contentModel.getInstanceIds(), client);if (CollectionUtils.isEmpty(privateIps)) {result.setSuccess(false);result.setMessage("privateIps is empty");sendMns(akId, akSecret, securityToken, result.toString());return;}List<String> needAppendIps = filterPrivateIpsForAppend(privateIps, client);if (!CollectionUtils.isEmpty(needAppendIps)) {modifySecurityIps(client, needAppendIps);result.setLifecycleHookId(contentModel.getLifecycleHookId());result.setLifecycleActionToken(contentModel.getLifecycleActionToken());sendMns(akId, akSecret, securityToken, result.toString());}} catch (Exception ex) {result.setSuccess(false);result.setMessage(ex.getMessage());sendMns(akId, akSecret, securityToken, result.toString());}}/*** 构建请求 ECS Redis 接口客户端** @param akId* @param akSecret* @param securityToken* @return*/private IAcsClient buildClient(String akId, String akSecret, String securityToken) {IClientProfile clientProfile = DefaultProfile.getProfile(REGION_ID, akId, akSecret,securityToken);return new DefaultAcsClient(clientProfile);}/*** 将执行结果发送消息到MNS** @param ak* @param aks* @param securityToken* @param msg*/private void sendMns(String ak, String aks, String securityToken, String msg) {MNSClient client = null;try {CloudAccount account = new CloudAccount(ak, aks,String.format(MNS_END_POINT, USER_ID, REGION_ID), securityToken);client = account.getMNSClient();CloudQueue queue = client.getQueueRef(QUEUE_NAME);Message message = new Message();message.setMessageBody(msg);queue.putMessage(message);} finally {if (client != null) {client.close();}}}/*** 过滤出需要添加到redis的私网IP** @param privateIps 过滤以前的私网IP* @param client* @return* @throws ClientException*/private List<String> filterPrivateIpsForAppend(List<String> privateIps, IAcsClient client)throws ClientException {List<String> needAppendIps = new ArrayList<>();if (CollectionUtils.isEmpty(privateIps)) {return needAppendIps;}DescribeSecurityIpsRequest request = new DescribeSecurityIpsRequest();request.setInstanceId(REDIS_ID);DescribeSecurityIpsResponse response = client.getAcsResponse(request);List<DescribeSecurityIpsResponse.SecurityIpGroup> securityIpGroups = response.getSecurityIpGroups();if (CollectionUtils.isEmpty(securityIpGroups)) {return privateIps;}for (DescribeSecurityIpsResponse.SecurityIpGroup securityIpGroup : securityIpGroups) {if (!securityIpGroup.getSecurityIpGroupName().equals(DEFAULT_SECURITY_GROUP_NAME)) {continue;}String securityIps = securityIpGroup.getSecurityIpList();if (securityIps == null) {continue;}String[] securityIpList = securityIps.split(",");List<String> existIps = Arrays.asList(securityIpList);if (CollectionUtils.isEmpty(existIps)) {continue;}for (String ip : privateIps) {if (!existIps.contains(ip)) {needAppendIps.add(ip);}}}return privateIps;}/*** 修改REDIS实例DEFAULT分组私网IP白名单** @param client* @param needAppendIps* @throws ClientException*/private void modifySecurityIps(IAcsClient client, List<String> needAppendIps)throws ClientException {if (CollectionUtils.isEmpty(needAppendIps)) {return;}ModifySecurityIpsRequest request = new ModifySecurityIpsRequest();request.setInstanceId(REDIS_ID);String ip = StringUtils.join(needAppendIps.toArray(), ",");request.setSecurityIps(ip);request.setSecurityIpGroupName(DEFAULT_SECURITY_GROUP_NAME);request.setModifyMode(MODIFY_MODE_APPEND);client.getAcsResponse(request);}/*** 获取输入,并base64解码** @param inputStream* @return* @throws IOException*/private String readInput(InputStream inputStream) throws IOException {try {byte[] bytes = new byte[MAX_BYTE_LENGTH];int tmp;int len = 0;//循环读取所有内容while ((tmp = inputStream.read()) != -1 && len < MAX_BYTE_LENGTH) {bytes[len] = (byte) tmp;len++;}inputStream.close();byte[] act = new byte[len];System.arraycopy(bytes, 0, act, 0, len);return new String(Base64.decodeBase64(act), CHAR_SET);} finally {inputStream.close();}}/*** 获取实例列表对应的私网IP,并限制每次请求实例数量不超过100** @param instanceIds 实例列表* @param client 请求客户端* @return* @throws Exception*/public List<String> getInstancesPrivateIps(List<String> instanceIds, IAcsClient client)throws Exception {List<String> privateIps = new ArrayList<>();if (CollectionUtils.isEmpty(instanceIds)) {return privateIps;}int size = instanceIds.size();int queryNumberPerTime = 100;int batchCount = (int) Math.ceil((float) size / (float) queryNumberPerTime);//support 100 instancefor (int i = 1; i <= batchCount; i++) {int fromIndex = queryNumberPerTime * (i - 1);int toIndex = Math.min(queryNumberPerTime * i, size);List<String> subList = instanceIds.subList(fromIndex, toIndex);DescribeInstancesRequest request = new DescribeInstancesRequest();request.setInstanceIds(JSON.toJSONString(subList));DescribeInstancesResponse response = client.getAcsResponse(request);List<DescribeInstancesResponse.Instance> instances = response.getInstances();if (CollectionUtils.isEmpty(instances)) {continue;}for (DescribeInstancesResponse.Instance instance : instances) {String privateIp = getPrivateIp(instance);if (privateIp != null) {privateIps.add(privateIp);}}}return privateIps;}/*** 从 DescribeInstancesResponse.Instance 中解析出私网 IP** @param instance DescribeInstancesResponse.Instance*/private String getPrivateIp(DescribeInstancesResponse.Instance instance) {String privateIp = null;if (VPC_NETWORK.equalsIgnoreCase(instance.getInstanceNetworkType())) {DescribeInstancesResponse.Instance.VpcAttributes vpcAttributes = instance.getVpcAttributes();if (vpcAttributes != null) {List<String> privateIpAddress = vpcAttributes.getPrivateIpAddress();if (!CollectionUtils.isEmpty(privateIpAddress)) {privateIp = privateIpAddress.get(0);}}} else {List<String> innerIpAddress = instance.getInnerIpAddress();if (!CollectionUtils.isEmpty(innerIpAddress)) {privateIp = innerIpAddress.get(0);}}return privateIp;}
}

代码中涉及到的 Model 文件

FCResult.java

package model;import com.alibaba.fastjson.JSON;public class FCResult {private boolean success = true;private String  lifecycleHookId;private String  lifecycleActionToken;private String  message;public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}public String getLifecycleHookId() {return lifecycleHookId;}public void setLifecycleHookId(String lifecycleHookId) {this.lifecycleHookId = lifecycleHookId;}public String getLifecycleActionToken() {return lifecycleActionToken;}public void setLifecycleActionToken(String lifecycleActionToken) {this.lifecycleActionToken = lifecycleActionToken;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}@Overridepublic String toString() {return JSON.toJSONString(this);}
}

HookModel.java

package model;import java.util.List;public class HookModel {private String            lifecycleHookId;private String            lifecycleActionToken;private String            lifecycleHookName;private String            scalingGroupId;private String            scalingGroupName;private String            lifecycleTransition;private String            defaultResult;private String            requestId;private String            scalingActivityId;private List<String>      instanceIds;public String getLifecycleHookId() {return lifecycleHookId;}public void setLifecycleHookId(String lifecycleHookId) {this.lifecycleHookId = lifecycleHookId;}public String getLifecycleActionToken() {return lifecycleActionToken;}public void setLifecycleActionToken(String lifecycleActionToken) {this.lifecycleActionToken = lifecycleActionToken;}public String getLifecycleHookName() {return lifecycleHookName;}public void setLifecycleHookName(String lifecycleHookName) {this.lifecycleHookName = lifecycleHookName;}public String getScalingGroupId() {return scalingGroupId;}public void setScalingGroupId(String scalingGroupId) {this.scalingGroupId = scalingGroupId;}public String getScalingGroupName() {return scalingGroupName;}public void setScalingGroupName(String scalingGroupName) {this.scalingGroupName = scalingGroupName;}public String getLifecycleTransition() {return lifecycleTransition;}public void setLifecycleTransition(String lifecycleTransition) {this.lifecycleTransition = lifecycleTransition;}public String getDefaultResult() {return defaultResult;}public void setDefaultResult(String defaultResult) {this.defaultResult = defaultResult;}public String getRequestId() {return requestId;}public void setRequestId(String requestId) {this.requestId = requestId;}public String getScalingActivityId() {return scalingActivityId;}public void setScalingActivityId(String scalingActivityId) {this.scalingActivityId = scalingActivityId;}public List<String> getInstanceIds() {return instanceIds;}public void setInstanceIds(List<String> instanceIds) {this.instanceIds = instanceIds;}
}

MnsMessageModel.java

package model;public class MnsMessageModel {private String    userId;private String    regionId;private String    resourceArn;private HookModel content;public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getRegionId() {return regionId;}public void setRegionId(String regionId) {this.regionId = regionId;}public String getResourceArn() {return resourceArn;}public void setResourceArn(String resourceArn) {this.resourceArn = resourceArn;}public HookModel getContent() {return content;}public void setContent(HookModel content) {this.content = content;}
}

Maven 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.aliyun.fc.wujin</groupId><artifactId>demo</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-ecs</artifactId><version>4.10.1</version></dependency><dependency><groupId>com.aliyun.fc.runtime</groupId><artifactId>fc-java-core</artifactId><version>1.0.0</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>3.2.6</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-r-kvstore</artifactId><version>2.0.3</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.25</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.2.5.RELEASE</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.2</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>com.springsource.org.apache.commons.lang</artifactId><version>2.6.0</version></dependency><dependency><groupId>com.aliyun.mns</groupId><artifactId>aliyun-sdk-mns</artifactId><version>1.1.8.4</version></dependency></dependencies><build><plugins><plugin><artifactId>maven-assembly-plugin</artifactId><version>3.1.0</version><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><appendAssemblyId>false</appendAssemblyId> <!-- this is used for not append id to the jar name --></configuration><executions><execution><id>make-assembly</id> <!-- this is used for inheritance merges --><phase>package</phase> <!-- bind to the packaging phase --><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build></project>

上述java文件中,Example.java 文件在包名为 fc 的目录下,FCResult.java HookModel.java MnsMessageModel.java 三个文件在包名为 model 的目录下,package fc 与 package model 处于同级目录。
Example.java 文件需要根据实际情况对相关参数进行替换,QUEUE_NAME 参数定义了接收函数执行结果的 MNS 队列,我们在 配置 MNS 章节已经提前创建好了。
参数替换完成以后,可以参考 FC Java 编程说明 重新打包并上传您的 jar 包即可,上传方法如下图所示:
image

写在最后

通过 AutoScaling -> LifecycleHook -> MNS -> FC 的方式,您可以具备更加丰富的弹性能力,从而更加灵活地管理您伸缩组内的资源。

上述代码仅供参考,具体实现需要结合具体业务进行测试改造。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/388751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

参考文献_参考

参考文献Recently, I am attracted by the news that Tanzania has attained lower middle income status under the World Bank’s classification, five years ahead of projection. Being curious on how they make the judgement, I take a look of the World Bank’s offi…

数据统计 测试方法_统计测试:了解如何为数据选择最佳测试!

数据统计 测试方法This post is not meant for seasoned statisticians. This is geared towards data scientists and machine learning (ML) learners & practitioners, who like me, do not come from a statistical background.Ť他的职位是不是意味着经验丰富的统计人…

spring的几个通知(前置、后置、环绕、异常、最终)

1、没有异常的 2、有异常的 1、被代理类接口Person.java 1 package com.xiaostudy;2 3 /**4 * desc 被代理类接口5 * 6 * author xiaostudy7 *8 */9 public interface Person { 10 11 public void add(); 12 public void update(); 13 public void delete();…

每个Power BI开发人员的Power Query提示

If someone asks you to define the Power Query, what should you say? If you’ve ever worked with Power BI, there is no chance that you haven’t used Power Query, even if you weren’t aware of it. Therefore, one could easily say that Power Query is the “he…

c# PDF 转换成图片

1.新建项目 2.新增一个新文件夹“lib”&#xff08;主要是为了存放引用的dll&#xff09; 3.将“gsdll32.dll 、PDFLibNet.dll 、PDFView.dll”3个dll添加到文件夹中 4.项目添加“PDFLibNet.dll 、PDFView.dll”2个类库的引用&#xff0c;并将gsdll32.dll 拷贝到项目生产根…

oracle 死锁

为什么80%的码农都做不了架构师&#xff1f;>>> ORA-01013: user requested cancel of current operation 转载于:https://my.oschina.net/8808/blog/2994537

a/b测试_如何进行A / B测试?

a/b测试The idea of A/B testing is to present different content to different variants (user groups), gather their reactions and user behaviour and use the results to build product or marketing strategies in the future.A / B测试的想法是将不同的内容呈现给不同…

hibernate h2变mysql_struts2-hibernate-mysql开发案例 -解道Jdon

Hibernate专题struts2-hibernate-mysql开发案例与源码源码下载本案例展示使用Struts2&#xff0c;Hibernate和MySQL数据库开发一个个人音乐管理器Web应用程序。&#xff0c;可将您的音乐收藏添加到数据库中。功能有&#xff1a;显示一个添加记录的表单和所有的音乐收藏的列表。…

提取图像感兴趣区域_从图像中提取感兴趣区域

提取图像感兴趣区域Welcome to the second post in this series where we talk about extracting regions of interest (ROI) from images using OpenCV and Python.欢迎来到本系列的第二篇文章&#xff0c;我们讨论使用OpenCV和Python从图像中提取感兴趣区域(ROI)。 As a rec…

解决java compiler level does not match the version of the installed java project facet

ava compiler level does not match the version of the installed java project facet错误的解决 因工作的关系&#xff0c;Eclipse开发的Java项目拷来拷去&#xff0c;有时候会报一个很奇怪的错误。明明源码一模一样&#xff0c;为什么项目复制到另一台机器上&#xff0c;就会…

php模板如何使用,ThinkPHP如何使用模板

到目前为止&#xff0c;我们只是使用了控制器和模型&#xff0c;还没有接触视图&#xff0c;下面来给上面的应用添加视图模板。首先我们修改下 Action 的 index 操作方法&#xff0c;添加模板赋值和渲染模板操作。PHP代码classIndexActionextendsAction{publicfunctionindex(){…

什么是嵌入式系统

在我们的日常生活中&#xff0c;我们经常使用许多使用嵌入式系统技术设计的电气和电子电路和套件。计算机&#xff0c;手机&#xff0c;平板&#xff0c;笔记本电脑&#xff0c;数字电子系统以及其他电子和电子设备都是使用嵌入式系统设计的。 什么是嵌入式系统&#xff1f;将硬…

面向数据科学家的实用统计学_数据科学家必知的统计数据

面向数据科学家的实用统计学Beginners usually ignore most foundational statistical knowledge. To understand different models, and various techniques better, these concepts are essential. These work as baseline knowledge for various concepts involved in data …

suse安装php,SUSE下安装LAMP

安装Apache可以看到编译安装Apache出错&#xff0c;rpm包安装gcc (首先要安装GCC)makemake install修改apache端口cd /home/sxit/apache2vi conf/httpd.confListen 8000启动 apache/home/root/apache2/bin/apachectl start(stop restart)http://localhost:8000安装一下PHP开发…

自己动手写事件总线(EventBus)

2019独角兽企业重金招聘Python工程师标准>>> 本文由云社区发表 事件总线核心逻辑的实现。 <!--more--> EventBus的作用 Android中存在各种通信场景&#xff0c;如Activity之间的跳转&#xff0c;Activity与Fragment以及其他组件之间的交互&#xff0c;以及在某…

viz::viz3d报错_我可以在Excel中获得该Viz吗?

viz::viz3d报错Have you ever found yourself in the following situation?您是否遇到以下情况&#xff1f; Your team has been preparing and working tireless hours to create and showcase the end product — an interactive visual dashboard. It’s a culmination of…

java 添加用户 数据库,跟屌丝学DB2 第二课 建立数据库以及添加用户

在安装DB2 之后&#xff0c;就可以在 DB2 环境中创建自己的数据库。首先考虑数据库应该使用哪个实例。实例(instance) 提供一个由数据库管理配置(DBM CFG)文件控制的逻辑层&#xff0c;可以在这里将多个数据库分组在一起。DBM CFG 文件包含一组 DBM CFG 参数&#xff0c;可以使…

iphone视频教程

公开课介绍 本课程共28集 翻译至第15集 网易正在翻译16-28集 敬请关注 返回公开课首页 一键分享&#xff1a;  网易微博开心网豆瓣网新浪微博搜狐微博腾讯微博邮件 讲师介绍 名称&#xff1a;Alan Cannistraro 课程介绍 如果你对iPhone Development有兴趣&#xff0c;以下是入…

在Python中有效使用JSON的4个技巧

Python has two data types that, together, form the perfect tool for working with JSON: dictionaries and lists. Lets explore how to:Python有两种数据类型&#xff0c;它们一起构成了使用JSON的理想工具&#xff1a; 字典和列表 。 让我们探索如何&#xff1a; load a…

Vlan中Trunk接口配置

Vlan中Trunk接口配置 参考文献&#xff1a;HCNA网络技术实验指南 模拟器&#xff1a;eNSP 实验环境&#xff1a; 实验目的&#xff1a;掌握Trunk端口配置 掌握Trunk端口允许所有Vlan配置方法 掌握Trunk端口允许特定Vlan配置方法 实验拓扑&#xff1a; 实验IP地址 &#xff1a;…