首页 文章 精选 留言 我的

精选列表

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

圆通快递快速免费对接快递鸟单号查询api接口

快递查询API接口是使用的物流单号即可实现查询物流信息。主要应用在电商商城、ERP系统商、WMS系统商、快递柜、银行等企业。多家快递物流公司接口统一接入,建议对接接口提供商,一次性可以接入多家快递,在后期的技术维护也会省下很多工作。 目前快递查询API接口有两种实现方式,一种是主动查询,一种是订阅接口推送数据。以快递鸟接口为例(接口对接需要接口秘钥,这里用的是测试的,不能够正式使用,可以到快递鸟官网申请www.kdniao.com/,是免费申请秘钥的)最后附有一个的demo,更多demo可登陆快递鸟网站查询。 一.主动查询(即时查询API)1)接口规则a、查询接口支持按照运单号查询(单个查询,并发不超过10个/S)。b、指定的物流运单号选择相应的快递公司编码,格式不对或则编码错误都会返失败的信息。如圆通快递物流单号应选择圆通快递公司编码(YTO)c、返回的物流跟踪信息按照发生的时间升序排列。d、接口指令1002。e、请求地址:快递鸟注册2)系统级和应用级输入参数系统级输入参数 3)返回结果参数 4)JSON请求示例 { “OrderCode”: “”, “ShipperCode”: “SF”, “LogisticCode”: “118650888018” } // "YTO"为圆通快递公司编码,其他编码可在快递鸟官网下载 5)JSON返回示例 //没有物流轨迹的 { “EBusinessID”: “1109259”, "Traces":[], “OrderCode”: “”, “ShipperCode”: “SF”, “LogisticCode”: “118461988807”, “Success”: true, “Reason”: null } //有物流轨迹的 { “EBusinessID”: “1109259”, "OrderCode":"", “ShipperCode”: “SF”, “LogisticCode”: “118461988807”, “Success”: true, "CallBack":"", “State”: 3, “Reason”: null, "Traces":[ { "AcceptTime": "2014/06/25 08:05:37", "AcceptStation": "正在派件..(派件人:邓裕富,电话:18718866310)[深圳 市]", "Remark": null }, { "AcceptTime": "2014/06/25 04:01:28", "AcceptStation": "快件在 深圳集散中心 ,准备送往下一站 深圳 [深圳市]", "Remark": null }, { "AcceptTime": "2014/06/2501:41:06", "AcceptStation": "快件在 深圳集散中心 [深圳市]", "Remark": null }, { "AcceptTime": "2014/06/24 20:18:58", "AcceptStation": "已收件[深圳市]", "Remark": null }, { "AcceptTime": "2014/06/24 20:55:28", "AcceptStation": "快件在 深圳 ,准备送往下一站 深圳集散中心 [深圳市]", "Remark": null }, { "AcceptTime": "2014/06/25 10:23:03", "AcceptStation": "派件已签收[深圳市]", "Remark": null }, { "AcceptTime": "2014/06/25 10:23:03", "AcceptStation": "签收人是:已签收[深圳市]", "Remark": null } ] 二.订阅接口推送数据(物流跟踪API)订阅查询接口是定制化服务,用户可将订单信息订阅给快递公司,快递公司更新轨迹后,将实时转换成标准接口形式,推送给用户,起到实时推送的作用,提高效率。同时用户订阅的数据还能选择是否通知快递员上门,实现在线下单功能。另外,快递鸟还有在途监控、电子面单等其他的接口方案,可以根据公司需求来选择。1)接口规则a、订单接收的信息(分给了的网点,业务员的信息),会通过推送接口推给客户(订阅并发不超过30次/S)客户需要按要求实现接口。b、仅支持Json格式。c、请求指令1008。d、测试接口地址:e、联调通过后请更换为正式地址:f、分发及订阅接口需要客户方实现回调接口,回调RequestType(1008)2)系统级和应用级参数 RequestData(必填参数,请求内容,JSON格式,须和DataType一致)) 用户自定义回调信息 WareHouseID 邮费支付方式: 1-现付,2-到付,3-月结,4-第三方支付 ExpType String O 快递类型:1-标准快件 Cost Double O 寄件费(运费) OtherCost Double O 其他费用 Receiver Company String O 收件人公司 Name String O 收件人 Tel String O 电话 Mobile String O 手机 PostCode String O 收件人邮编 ProvinceName String O 收件省(如广东省,不要缺少“省”) CityName String O 收件市(如深圳市,不要缺少“市”) ExpAreaName String O 收件区(如福田区,不要缺少“区”或“县”) Address String O 收件人详细地址 Sender Company String O 发件人公司 Name String O 发件人 Tel String O 发件人电话 Mobile String O 发件人手机 PostCode String O 发件人邮编 ProvinceName String O 发件省(如广东省,不要缺少“省”) CityName String O 发件市(如深圳市,不要缺少“市”) ExpAreaName String O 发件区(如福田区,不要缺少“区”或“县”) Address String O 发件详细地址 StartDate String O 上门取货时间段: "yyyy-MM-dd HH:mm:ss"格式化,本文中所有时间格式相同 EndDate String O Weight Double O 物品总重量kg Quantity Int O 件数/包裹数 Volume Double O 物品总体积m3 Remark String O 备注 IsNotice Int O 是否分发到快递公司:1-不分发;0-分发.默认为0 IsSendMessage Int O 是否订阅短信 0-不需要;1-需要 AddService Name String 0 增值服务名称 Value String 0 增值服务值 CustomerID String 0 客户标识(选填) Commodity GoodsName String O 商品名称 GoodsCode String O 商品编码 Goodsquantity Int O 件数 GoodsPrice Double O 商品价格 GoodsWeight Double O 商品重量kg GoodsDesc String O 商品描述 GoodsVol Double O 商品体积m3 EBusinessID String R 商户ID RequestType String R 请求指令类型:1008 DataSign String R 数据内容签名 DataType String R 请求、返回数据类型:2-json; 物流跟踪APIdemoimport java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.UnsupportedEncodingException;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.util.HashMap;import java.util.Map;import java.security.MessageDigest;/*快递鸟订阅推送2.0接口ID和Key请到官网申请:快递单号查询接口 //DEMO public static void main(String[] args) { KdniaoSubscribeAPI api = new KdniaoSubscribeAPI(); try { String result = api.orderTracesSubByJson(); System.out.print(result); } catch (Exception e) { e.printStackTrace(); } } //电商ID private String EBusinessID="请到快递鸟官网申请http://www.kdniao.com/ServiceApply.aspx"; //电商加密私钥,快递鸟提供,注意保管,不要泄漏 private String AppKey="请到快递鸟官网申请http://www.kdniao.com/ServiceApply.aspx"; //测试请求url private String ReqURL = "http://testapi.kdniao.cc:8081/api/dist"; //正式请求url //private String ReqURL = "http://api.kdniao.cc/api/dist"; /** * Json方式 物流信息订阅 * @throws Exception */ public String orderTracesSubByJson() throws Exception{ String requestData="{'OrderCode': 'SF201608081055208281'," + "'ShipperCode':'SF'," + "'LogisticCode':'3100707578976'," + "'PayType':1," + "'ExpType':1," + "'CustomerName':'',"+ "'CustomerPwd':''," + "'MonthCode':''," + "'IsNotice':0," + "'Cost':1.0," + "'OtherCost':1.0," + "'Sender':" + "{" + "'Company':'LV','Name':'Taylor','Mobile':'15018442396','ProvinceName':'上海','CityName':'上海','ExpAreaName':'青浦区','Address':'明珠路73号'}," + "'Receiver':" + "{" + "'Company':'GCCUI','Name':'Yann','Mobile':'15018442396','ProvinceName':'北京','CityName':'北京','ExpAreaName':'朝阳区','Address':'三里屯街道雅秀大厦'}," + "'Commodity':" + "[{" + "'GoodsName':'鞋子','Goodsquantity':1,'GoodsWeight':1.0}]," + "'Weight':1.0," + "'Quantity':1," + "'Volume':0.0," + "'Remark':'小心轻放'}"; Map<String, String> params = new HashMap<String, String>(); params.put("RequestData", urlEncoder(requestData, "UTF-8")); params.put("EBusinessID", EBusinessID); params.put("RequestType", "1008"); String dataSign=encrypt(requestData, AppKey, "UTF-8"); params.put("DataSign", urlEncoder(dataSign, "UTF-8")); params.put("DataType", "2"); String result=sendPost(ReqURL, params); //根据公司业务处理返回的信息...... return result; } /** * MD5加密 * @param str 内容 * @param charset 编码方式 * @throws Exception */ @SuppressWarnings("unused") private String MD5(String str, String charset) throws Exception { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes(charset)); byte[] result = md.digest(); StringBuffer sb = new StringBuffer(32); for (int i = 0; i < result.length; i++) { int val = result[i] & 0xff; if (val <= 0xf) { sb.append("0"); } sb.append(Integer.toHexString(val)); } return sb.toString().toLowerCase(); } /** * base64编码 * @param str 内容 * @param charset 编码方式 * @throws UnsupportedEncodingException */ private String base64(String str, String charset) throws UnsupportedEncodingException{ String encoded = base64Encode(str.getBytes(charset)); return encoded; } @SuppressWarnings("unused") private String urlEncoder(String str, String charset) throws UnsupportedEncodingException{ String result = URLEncoder.encode(str, charset); return result; } /** * 电商Sign签名生成 * @param content 内容 * @param keyValue Appkey * @param charset 编码方式 * @throws UnsupportedEncodingException ,Exception * @return DataSign签名 */ @SuppressWarnings("unused") private String encrypt (String content, String keyValue, String charset) throws UnsupportedEncodingException, Exception { if (keyValue != null) { return base64(MD5(content + keyValue, charset), charset); } return base64(MD5(content, charset), charset); } /** * 向指定 URL 发送POST方法的请求 * @param url 发送请求的 URL * @param params 请求的参数集合 * @return 远程资源的响应结果 */ @SuppressWarnings("unused") private String sendPost(String url, Map<String, String> params) { OutputStreamWriter out = null; BufferedReader in = null; StringBuilder result = new StringBuilder(); try { URL realUrl = new URL(url); HttpURLConnection conn =(HttpURLConnection) realUrl.openConnection(); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // POST方法 conn.setRequestMethod("POST"); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.connect(); // 获取URLConnection对象对应的输出流 out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); // 发送请求参数 if (params != null) { StringBuilder param = new StringBuilder(); for (Map.Entry<String, String> entry : params.entrySet()) { if(param.length()>0){ param.append("&"); } param.append(entry.getKey()); param.append("="); param.append(entry.getValue()); System.out.println(entry.getKey()+":"+entry.getValue()); } System.out.println("param:"+param.toString()); out.write(param.toString()); } // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; while ((line = in.readLine()) != null) { result.append(line); } } catch (Exception e) { e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally{ try{ if(out!=null){ out.close(); } if(in!=null){ in.close(); } } catch(IOException ex){ ex.printStackTrace(); } } return result.toString(); } private static char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; public static String base64Encode(byte[] data) { StringBuffer sb = new StringBuffer(); int len = data.length; int i = 0; int b1, b2, b3; while (i < len) { b1 = data[i++] & 0xff; if (i == len) { sb.append(base64EncodeChars[b1 >>> 2]); sb.append(base64EncodeChars[(b1 & 0x3) << 4]); sb.append("=="); break; } b2 = data[i++] & 0xff; if (i == len) { sb.append(base64EncodeChars[b1 >>> 2]); sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); sb.append(base64EncodeChars[(b2 & 0x0f) << 2]); sb.append("="); break; } b3 = data[i++] & 0xff; sb.append(base64EncodeChars[b1 >>> 2]); sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]); sb.append(base64EncodeChars[b3 & 0x3f]); } return sb.toString(); }

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

快速完成智能数据构建,Dataphin公共云版本全面解读

公测两个月,Dataphin公共云版本已经受到了阿里云上众多轻量级用户的关注。事实上,Dataphin作为一款大数据智能构建与管理的产品,其核心功能是面向各行各业大数据建设、管理及应用诉求,一站式提供从数据接入到数据消费全链路的智能数据构建与管理的大数据能力,包括产品、技术和方法论,助力企业打造标准统一、融会贯通、资产化、服务化、闭环自优化的智能数据体系,以驱动业务创新。 日前,基于公测期间用户关注的诸多问题,Dataphin团队在阿里云上启动了首场Dataphin公共云产品直播。针对性地解读了这一版本在性能和使用上的亮点。 1、Dataphin可以解决什么问题? 近年来大数据领域最热门的词非“数据中台”莫属,很多数据服务商都转型为“数据中台”的搭建者。然而与“数据中台”的构建密切相关的产品Dataphin现已正式上线阿里云公共云环境。

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

在Linux系统中快速搭建NFS服务的新途径

也许各位朋友看到这个标题会觉得很奇怪,会问:在Linux中搭建NFS网络存储服务有多难?小菜一碟。也许对给位老手来说这是一件再简单不过的事,但是,这里给到大家的是一个全新的,能一键部署NFS服务的方案,感兴趣的朋友不妨了解一下。 这里的方案就是通过URLOS一键部署NFS,话不多说,直接开始: 打开URLOS系统后台,在应用市场中搜索“nfs”,点击安装:填写服务名称 其实也没有什么需要设置的,点击提交即可。写到到这里,我们已经将nfs服务部署完,是的,就是这么快! 下面是演示如何挂载nfs共享存储,首先在别的机器上安装nfs客户端工具 root@ubuntu:/# apt-get install -y nfs-common安装完成后在根目录下新建一个目录nfsdir root@ubuntu:/# mkdir nfsdir在用以下命令挂载nfs root@ubuntu:/# mount 192.168.43.121:/ /nfsdir/192.168.43.121:/即我们刚才部署的nfs服务器,以上的意思就是将nfs服务器的根目录挂载到该机器的nfsdir目录。 我们在该机器创建一个文件a.txt,然后在urlos主控面板可以查看到该文件,说明共享存储服务生效了 root@ubuntu:/# cd nfsdir/root@ubuntu:/nfsdir# lsa.txt

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

不断被取代的传统职业:快速发展的智能交互

前记 我们身边有很多鲜为人知的职业,有些你可能知道,有些你可能不知道,更有一些,你或许听过,却从不明白它到底是做什么的。 速录师,就是这样的一个职业。很多人觉得这个职业简单,只要会打字就行,其实不然。要做一名合格的速录师,不仅需要具备文化素质、心理素质、速度素质,更需要经过考核,获得《速录师职业资格证书》才能上任。心理和能力的考核+300字/分的速度+97%以上的准确率,再加上考虑口述言语间的逻辑关系,这样加起来的速录,你还会觉得简单么? 现在,类似速录师这样你还尚未了解的职业已经在被逐步取代。以速录领域最艰深的律法行业为例,浙江高院早已在司法语音大数据解决方案的帮助下取代了传统的书记员。庭审现场,记者亲测系统同步记录延迟不超过500毫秒,并能不时进行自动纠错,准确率达97%以上。那么,究竟是什么产品才具有这样强悍的实力? 应用场景 阿里云智能语音交互是基于语音识别、语音合成、自然语言理解等技术,赋予产品“能听、会说、懂你”式的智能人机交互体验。目前,阿里云智能语音交互已在庭审速记、线路检测、智能客服、语音质检、直播字幕等场景落地。 庭审速记:法庭庭审全程实时记录,已覆盖300+法院。例:浙江省全省法院。线路检测:全量通话转文本,发现可能存在的电话诈骗。例:智检云SaaS产品。智能客服:传统客服向智能客服转型。例:蚂蚁金服95188热线、智能客服机器人。语音质检:语音转文本后对服务过程进行质检。例:阿里集团客服、合众人寿。直播字幕:实时直播字幕与监控。例:云栖大会实时字幕;奥点云的落地合作。 语言模型自学习工具 语言模型自学习是阿里云智能语音交互在全球首创的智能语音自学习平台,是能够帮助用户零基础训练业务的专属语音模型。 在业务领域内通常会有一些特有的词,默认识别效果较差时候可以考虑使用泛热词/类热词,根据不同的业务场景具体选择。通过将这些词添加到词表,就可以达到改善这部分词的识别结果。 如果在领域已经积累了比较丰富的历史数据,那么就可以使用这些历史数据对语言模型做定制的优化。通过使用语音自学习工具,可以通过可操作的界面上传训练语料文本,并选择对应领域的语言基础模型,通过对训练语料做模型训练,可以有效提高该场景的语音识别率,尤其是专有名词和文本中的高频词汇,有较好的优化效果。 智能互动大屏 智能语音交互的一大应用是包装成在各类公众空间可实现人机交互的智能大屏。其最大的特色是在强噪声环境下的语音识别,同时具备免唤醒、长句子流式理解的能力。2018年3月,全球第一台地铁语音售票机正式落地上海南站和汉中路地铁站,在地铁真实嘈杂环境下,语音识别准确率超过96%,在解放人手的情况下完成了10秒完成取票的操作,而正常情况下人工取票一般需要30秒。目前,智能互动大屏的其主要适用场景有: 大交通:地铁售票、问询,机场、景区、火车站问询; 新零售:点餐、试衣镜、试装镜,商超导览导购; 政企大厅:政务、运营商、银行、保险大厅问询; 其他:医院分诊挂号和科室导航,图书馆找书。 写在结尾的话 阿里云智能语音交互独有的语音模型训练自学习平台,加上其丰富的接口类型,及在电话、App、政法会议领域的经验沉淀,给开发者在智能人机交互开发上提供了莫大的助力。 现在,我们组建了一个开发者交流群,欲要了解更多人工智能方面的知识,和更多同道开发者交流讨论,欢迎加入我们。 一:钉钉搜索数字进入交流群:23116044二:钉钉扫描二维码进交流群:

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

使用反向代理,实现快速配置、重启 Docker 守护进程

出品丨Docker公司(ID:docker-cn)编译丨小东每周一、三、五,与您不见不散! 发布 Docker 守护进程通常涉及到创建所需的证书,重新配置 Docker 守护进程并重新启动它。但是,您通常没有更改守护进程配置或重启守护进程所需要的权限。接下来,我将演示如何使用容器化反向代理来实现它。 免责声明 在将 Docker 守护进程公开给 TCP 端口上的网络时,都需要我们配置证书身份验证。 如果不这样做,那就等于为所有人提供了 root 权限。 先决条件 请按照官方文档创建保护 Docker 守护进程所需的证书。与官方文档相反,不要将 Docker 守护进程配置为使用新创建的证书。我将在下一节“用法”中介绍为什么要这么做。 用 法 反向代理是基于“nginx:stable-alpine”,并且使用 TLS 来监听“2376/tcp”。所有请求都转发到本地 Docker 守护进程的“/var/run/docker.sock”中,它必须映射到容器中,如下所示: docker run -d \ --env CA_CRT=$(cat ca.pem) \ --env SERVER_KEY=$(cat server_key.pem) \ --env SERVER_CRT=$(cat server_cert.pem) \ --volume /var/run/docker.sock:/var/run/docker.sock --net=host nicholasdille/docker-auth-proxy 您也可以在默认网络中启动容器并公开端口: docker run -d \ --env CA_CRT=$(cat ca.pem) \ --env SERVER_KEY=$(cat server_key.pem) \ --env SERVER_CRT=$(cat server_cert.pem) \ --volume /var/run/docker.sock:/var/run/docker.sock -p 2376:2376 nicholasdille/docker-auth-proxy 可以根据需要启动和停止 Docker 守护进程的发布,这并不会影响到正在运行的容器。 下 载 浏览 https://hub.docker.com/r/nicholasdille/docker-auth-proxy/ 即可下载该反向代理镜像。

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

老司机避坑指南:如何快速搞定微服务架构?

如今,微服务架构已经成为了现代应用开发的首选。虽然它能够解决大部分的程序问题,但是它并非一颗百试不爽的“银弹”。 在采用这种架构之前,我们应当事先了解可能出现的各种问题及其共性,预先为这些问题准备好可重用的解决方案。 那么,在开始深入讨论微服务的不同设计模式之前,让我们先了解一下微服务架构的一些构建原则: ● 可扩展性 ● 可用性 ● 弹性 ● 独立、自主性 ● 去中心化治理 ● 故障隔离 ● 自动调配 ● 通过 DevOps 实现持续交付 在遵循上述各条原则的同时,我们难免会碰到一些挑战。下面我们来具体讨论可能出现的各种问题、及其解决方案。 分解模式 按照业务功能分解 问题:微服务是有关松散耦合的服务,它采用的是单一职责原则。虽然我们在逻辑原理上都知道要将单个应用分成多个小块,但是在实际操作中,我们又该如何将某个应用程序成功分解成若干个小的服务呢? 解决方案:有一种策略是按照业务功能进行分解。此处的业务功能是指能够产生价值的某种业务的最小单位。那么一组给定业务的功能划分则取决于企业本身的类型。 例如,一家保险公司的功能通常会包括:销售、营销、承保、理赔处理、结算、合规等方面。每一个业务功能都可以被看作是一种面向业务、而非技术的服务。 按照子域分解 问题:按照业务功能对应用程序进行分解只是一个良好的开端,之后您可能会碰那些不易分解的所谓“神类”(God Classes)。这些类往往会涉及到多种服务。 例如,订单类就会被订单管理、订单接受、订单交付等服务所使用到,那么我们又该如何分解呢? 解决方案:对于“神类”的问题,DDD(Domain Driven Design,领域驱动设计)能够派上用场。 它使用子域(Subdomain)和边界上下文(Bounded Context)的概念来着手解决。 DDD 会将企业的整个域模型进行分解,并创建出多个子域。每个子域将拥有一个模型,而该模型的范围则被称为边界上下文。那么每个微服务就会围绕着边界上下文被开发出来。 注意:识别子域并不是一件容易的事,我们需要通过分析业务与组织架构,识别不同的专业领域,来对企业加强了解。 刀砍模式(Strangler Pattern) 问题:前面我们讨论的设计模式一般适用于针对那些“白手起家”的 Greenfield 应用进行分解。 但是我们真实接触到的、约占 80% 的是 Brownfield 应用,即:一些大型的、单体应用(Monolithic Application)。 由于它们已经被投入使用、且正在运行,如果我们简单按照上述方式,同时对它们进行小块服务的分解,将会是一项艰巨的任务。 解决方案:此时,刀砍模式(Strangler Pattern)就能派上用场了。我们可以把扼杀模式想象为用刀砍去缠在树上的藤蔓。 该方案适用于那些反复进行调用的 Web 应用程序。对于每一个 URI(统一资源标识符)的调用来说,单个服务可以被分解为不同的域和单独的子服务。其设计思想是一次仅处理一个域。 这样,我们就可以在同一个 URI 空间内并行地创建两套独立的应用程序。最终,在新的应用重构完成后,我们就能“刀砍”或替换掉原来的应用程序,直到最后我们可以完全关闭掉原来的单体应用。 集成模式 API 网关模式 问题:当一个应用程序被分解成多个小的微服务时,我们需要关注如下方面。 具体如下: ● 如何通过调用多个微服务,来抽象出 Producer(生产者)的信息。 ● 在不同的渠道上(如电脑桌面、移动设备和平板电脑),应用程序需要不同的数据来响应相同的后端服务,比如:UI(用户界面)就可能会有所不同。 ● 不同的 Consumer(消费者)可能需要来自可重用式微服务的不同响应格式。谁将去做数据转换或现场操作? ● 如何处理不同类型的协议?特别是一些可能不被 Producer 微服务所支持的协议。 解决方案:API 网关将有助于解决在微服务实施过程中所涉及到的上述关注点。 具体如下: ● API 网关是任何微服务调用的统一入口。 ● 它像代理服务一样,能够将一个微服务请求路由到其相关的微服务处,并抽象出 Producer 的细节。 ● 它既能将一个请求扇出(fan out,输出)到多个服务上,也能汇总多个结果,并发回给 Consumer。 ● 鉴于通用 API 无法解决 Consumer 的所有请求,该方案能够为每一种特定类型的客户端创建细粒度的 API。 ● 它也可以将某种协议请求(如:AMQP)转换为另一种协议(如:HTTP),反之亦然,从而方便了 Producer 和 Consumer 的处理。 ● 它也可以将认证与授权存储库从微服务中卸载出去。 聚合器模式 问题:虽然我们已经在 API 网关模式中讨论了如何解决聚合数据的问题,不过我们仍将做进一步的讨论。 当我们将业务功能分解成多个较小的逻辑代码块时,有必要思考每个服务的返回数据是如何进行协作的。 显然,该责任不会留给 Consumer,那么我们就需要理解 Producer 应用的内部实现。 解决方案:聚合器模式将有助于解决该问题。它涉及到如何聚合来自不同服务的数据,然后向 Consumer 发送最终响应。 具体说来,我们有如下两种实现方法: ● 复合微服务(Composite Microservice) 将会去调用全部所需的微服务,整合各种数据,并在回传之前转换数据。 ● API 网关(API Gateway) 也能对多个微服务的请求进行 Partition(分区),并在发送给 Consumer 之前聚合数据。 我们建议:如果您用到了任何业务逻辑的话,请选用复合微服务;否则请采用 API 网关方案。 客户端 UI 合成模式 问题:当各种服务按照业务功能和子域被分解开发时,它们需要根据用户体验的预期效果,从一些不同的微服务中提取数据。 在过去的单体应用中,我们只要从 UI 到后端服务的唯一调用中获取所有的数据,并刷新和提交到 UI 页面上便可。如今,情况则不同了。 解决方案:对于微服务来说,UI 必须被设计成单屏、单页面的多段、多区域的结构。 每一段都会去调用单独的后端微服务,以提取数据。像 Angular JS 和 React JS 之类的框架都能够实现为特定的服务合成 UI 组件。 通过被称为单页应用(Single Page Applications,SPA)的方式,它们能够使得应用程序仅刷新屏幕的特定区域,而不是整个页面。 数据库模式 按服务分配数据库 问题:您可能会碰到如何定义数据库架构的微服务问题。 下面是具体的关注点: ● 服务必须是松散耦合的,以便能够被二次开发、部署和独立扩容。 ● 各个业务交易需要在横跨多个服务时,仍保持不变。 ● 某些业务交易需要从多个服务中查询到数据。 ● 数据库有时需要根据规模需求被复制与分片。 ● 不同的服务具有不同的数据存储需求。 解决方案:为了解决上述需求,我们需要通过设计为每个微服务配备一个独享的数据库模式。 即:该数据库仅能被其对应微服务的 API 单独访问,而不能被其他服务直接访问到。 例如,对于关系型数据库,我们可以使用:按服务分配私有表集(private-tables-per-service)、按服务分配表结构(schema-per-service)、或按服务分配数据库服务器(database-server-per-service)。 每个微服务应该拥有一个单独的数据库 ID,以便它们在独享访问的同时,禁止再访问其他的服务表集。 按服务共享数据库 问题:上面讨论的按服务分配数据库是一种理想的微服务模式,它一般被前面提到的 Greenfield 应用和 DDD 式的开发。但是,如果我们面对的是需要采用微服务的单体应用就没那么容易了。 解决方案:按服务共享数据库的模式虽然有些违背微服务的理念,但是它对于将前面提到的 Brownfield 应用(非新建应用)分解成较小的逻辑块是比较适用的。 在该模式下,一个数据库可以匹配不止一个的微服务,当然也至多 2~3 个,否则会影响到扩容、自治性和独立性。 命令查询职责隔离(CQRS) 问题:对于按服务分配数据库的模式而言,我们如何在微服务的架构中,实现对多个服务进行联合查询数据的需求呢? 解决方案:CQRS 建议将应用程序拆分成两个部分:命令和查询。命令部分主要处理创建、更新和删除之类的请求;查询部分则利用物化视图(Materialized Views)来处理各种查询。 它通常配合事件溯源模式(Event Sourcing Pattern)一起创建针对任何数据的变更事件。而物化视图则通过订阅事件流,来保持更新。 Saga 模式 问题:当每个服务都有自己的数据库,而且业务交易横跨多个服务时,我们该如何确保整体业务数据的一致性呢? 例如:对于某个带有客户信用额度标识的电商应用而言,它需要确保新的订单不会超出客户的信用额度。 但是,由于订单和客户分属不同的数据库,应用程序无法简单地实现本地交易的 ACID(原子性、一致性、隔离性、持久性)特性。 解决方案:Saga 代表了一个高层次的业务流程,它是由一个服务中的多个子请求,并伴随着逐个更新的数据所组成。在某个请求失败时,它的补偿请求会被执行。 实现方式有如下两种: ● 编排(Choreography): 没有中央协调器,每个服务都会产生并侦听其他服务的事件,以决定是否应采取行动。 ● 协调(Orchestrator): 由一个中央协调器(对象)负责集中处理某个事件(Saga)的决策,和业务逻辑的排序。 观测模式 日志聚合 问题:我们来考虑这样一个用例:某个应用程序包括了那些在多台机器上运行的多个服务实例,各种请求横跨在这些多个服务实例之中。同时,每个服务实例都会生成一种标准格式的日志文件。 那么我们如何针对某个特定的请求,通过各种日志来理解该应用程序的行为呢? 解决方案:显然,我们需要一个集中化的日志服务,将各个服务实例的日志予以聚合,以便用户对日志进行搜索和分析。他们可以针对日志中可能出现的某些消息,配置相应的警告。 例如:PCF(Pivotal Cloud Foundry)平台拥有一个日志聚合器,它从每种元素(如:路由器、控制器等)中收集与应用相关的日志。而 AWS Cloud Watch 也具有相似的功能。 性能指标 问题:当各种服务组合随着微服务架构变得越来越复杂时,监控交易的完整性,并能够在出现问题时及时发出警告,就显得尤为重要了。那么我们该如何收集与应用相关的性能指标呢? 解决方案:为了收集不同操作的统计信息,并提供相应的报告和警告。 我们一般会用两种模式来聚集各项指标: ● 推式: 将各项指标推给专门的指标服务,如:NewRelic 和 AppDynamics。 ● 拉式: 从指标服务处拉取各项指标,如:Prometheus。 分布式跟踪 问题:在微服务架构中,横跨多个服务的请求是比较常见的。某个服务需要通过横跨多个服务去执行一到多项操作,才能处理一些特定的请求。 那么,我们该如何通过跟踪某个端到端的请求,以获知出现的问题呢? 解决方案:我们需要一种具有特性的服务。 具体特性服务如下: ● 为每个外部请求分配一个唯一的 ID。 ● 将该外部请求 ID 传给所有的服务。 ● 在所有的日志消息中都包含该外部请求 ID。 ● 在集中式服务中,记录处理外部请求的相关信息,包括:开始时间、结束时间、和执行时间。 Spring Cloud Slueth + Zipkin Server,是一种常见的实现方式。 健康检查 问题:我们在实施微服务架构的过程中,可能会碰到某个服务虽已启动,但是无法处理交易的情况。 那么,我们该如何通过负载均衡的模式,来确保请求不会“落入”失败的实例中呢? 解决方案:每个服务都需要有一个端点,通过诸如 /health 的参数,对应用进行健康检查。 该 API 需要能够检查主机的状态,其他服务与基础设施的连接性,以及任何特定的逻辑关系。 Spring Boot Actuator 不但能够实现端点的健康检查,还能够被定制实施。 横切关注点模式(Cross-Cutting Concern Patterns) 外部配置 问题:通常情况下,一个服务需要去调用其他的服务和数据库。在诸如开发、QA(Quality Assurance,质量保证)、UAT(User Acceptance Test,用户验收测试)、和生产环境中,端点的 URL、或某些配置的属性会有所不同。 因此,有时候我们需要对这些服务的各种属性进行重构、和重新部署。那么我们如何避免在配置变更中修改代码呢? 解决方案:外部化(externalize)所有的配置,包括各个端点的 URL 和信任凭据,以保证应用程序在启动时、或运行中能够加载它们。 Spring Cloud 配置服务器提供了向 GitHub 进行属性外部化的选项,并将其作为环境属性予以加载。 此法保证了应用程序能够在启动时就被访问到,或是在不重启服务器的情况下实现刷新。 服务发现模式 问题:当微服务初具规模时,我们需要考虑如下两个关于调用服务方面的问题。 具体问题如下: ● 由于采用了容器技术,IP 地址往往被动态地分配给不同的服务实例。因此,每次当 IP 地址发生变化时,Consumer 服务可能会受到影响,需要我们手动更改。 ● Consumer 需要记住每个服务的 URL,这就倒退成了紧耦合的状态。 那么,Consumer 或路由器该如何获知所有可用的服务实例与位置呢? 解决方案:我们需要创建一个服务注册表,来保存每个 Producer 服务的元数据(Meta Data)。 一个服务实例在启动时,应当被注册到表中;而在关闭时,需从表中被注销。 Consumer 或路由器通过查询该注册表,就能够找到服务的位置。Producer 服务也需要对该注册表进行健康检查,以确保能够消费到那些可用的、且正在运行的服务实例。 我们一般有两种服务发现的类型:客户端和服务器端。使用客户端发现的例子是 Netflix Eureka;而使用服务器端发现的例子是 AWS ALB。 断路器模式 问题:有时候,某个服务在调用其他服务,以获取数据的时候,会出现下游服务(Downstream Service)“掉线”的情况。 它一般会带来两种结果: ● 该请求持续发往该掉线服务,直至网络资源耗尽和性能降低。 ● 用户产生不可预料的、较差的使用体验。 那么我们该如何避免服务的连锁故障,并妥善处置呢? 解决方案:Consumer 应该通过一个代理来调用某项远程服务,就像电路中的断路器一样。 当出现持续失败的数量超过设定阈值时,断路器就会“跳闸”一段时间,从而导致所有调用远程服务的尝试被立即切断。 在超过设定时间之后,断路器只允许有限数量的测试请求通过。而如果这些请求成功了,那么断路器将恢复正常运行;否则判定为故障依旧,并重新开始新的定时周期。 Netflix Hystrix 就很好地使用了该断路器模式。它可以在断路器“跳闸”的时候,帮助您定义一种回退机制,以提供更好的用户体验。 蓝绿部署模式 问题:在微服务架构中,一个应用程序可以有多个微服务。如果我们为了部署一个增强版,而停止所有的服务,那么停机时间一旦过长,就会对业务造成影响。 况且,这对于回退来说也将会是一场噩梦。那么我们该如何避免、或减少部署过程中服务的停机时间呢? 解决方案:我们可以采用蓝绿部署的策略,以减少或消除停机时间。在蓝、绿两个相同的生产环境中,我们假设绿色环境有着当前真实的实例,而蓝色环境具有应用程序的最新版本。 在任何时候,只有一个环境能够处理所有真实的流量,并对外提供服务。如今,所有的云服务平台都能提供基于蓝绿部署的选项。 当然,我们还可以采用许多其他的微服务架构模式,如:Sidecar 模式、链式微服务(Chained Microservice)、分支微服务(Branch Microservice)、事件溯源模式(Event Sourcing Pattern)、和持续交付方式等。 原文发布时间为:2018-11-14 本文作者:陈峻编译 本文来自云栖社区合作伙伴“技术琐话”,了解相关信息可以关注“技术琐话”。

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

使用PHP结合Ffmpeg快速搭建流媒体服务实践

一、背景 笔者想将自己收藏的一些电影放到网站上可以用来随时播放,不过遇到了一个问题,便是如果直接将MP4文件放放到网站目录当中,手机端必须下载整个视频才可以播放,而如果跨外网传输,这实在是不太现实。 为了解决这个问题,便想着搭建一套流媒体服务,这样手机就可以边看边下载,查询了一些资料了了解到需要先将视频分成一小片来传输,比如将MP4转码为M3U8格式,查询了相关转码方法,比较主流的方式是使用ffmpeg这个开源工具 二、操作概要 1. 安装Ffmpeg 2. 服务搭建 3. 功能测试 三、搭建ffmpeg 视频转码的工具可能有很多,但开源且使用人数最多的还是莫过于ffmpeg这个工具,具体功能笔者不在这里详细讲解;安装此工具的方式有很多,比如apt安装、源码安装、docker安装等等,不过docker是跨平台的,因此笔者这里将以docker方式安装为例 3.1 镜像下载 首先笔者需要下载对应的docker镜像,参考命令如下 docker pull jrottenberg/ffmpeg 命令执行过程中将会从远处下载镜像,这个时间由当前的网络带宽所决定,当下载完成之后,可以看到如下参考信息 Using default tag: latest latest: Pulling from jrottenberg/ffmpeg b234f539f7a1: Pull complete 55172d420b43: Pull complete 5ba5bbeb6b91: Pull complete 43ae2841ad7a: Pull complete f6c9c6de4190: Pull complete 2a0ef76bfa54: Pull complete 40ddf796a4bb: Pull complete 32ba137d2764: Pull complete Digest: sha256:bcf65375f593518de7e450fd6b775d16a047d3ded00957c2e794e2fe8f7e1590 Status: Downloaded newer image for jrottenberg/ffmpeg:latest 3.2 容器运行 当容器下载完毕之后,可以用一些命令进行验证是否能够正常运行,如下参考命令 docker run jrottenberg/ffmpeg 命令执行完毕之后,会返回如下结果 Hyper fast Audio and Video encoder usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}... Getting help: ..... 省略 Audio options: -aframes number set the number of audio frames to output -aq quality set audio quality (codec-specific) -ar rate set audio sampling rate (in Hz) -ac channels set number of audio channels -an disable audio -acodec codec force audio codec ('copy' to copy stream) -vol volume change audio volume (256=normal) -af filter_graph set audio filters Subtitle options: -s size set frame size (WxH or abbreviation) -sn disable subtitle -scodec codec force subtitle codec ('copy' to copy stream) -stag fourcc/tag force subtitle tag/fourcc -fix_sub_duration fix subtitles duration -canvas_size size set canvas size (WxH or abbreviation) -spre preset set the subtitle options to the indicated preset 3.3 查看支持协议 FFmpeg所支持的输入输出协议非常多,比如可以选择file协议作为来源,使用hls协议作为输出结果,具体所支持的协议可以通过如下命令查看 docker run jrottenberg/ffmpeg -protocols 执行命令之后,参考结果如下 ffmpeg version 3.4.2 Copyright (c) 2000-2018 the FFmpeg developers built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.9) 20160609 configuration: --disable-debug --disable-doc --disable-ffplay --enable-shared --enable-avresample --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-gpl --enable-libass --enable-libfreetype --enable-libvidstab --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libtheora --enable-libvorbis ..... 省略 Supported file protocols: Input: async cache concat crypto data ..... 省略 Output: crypto file ..... 省略 tls udp 3.4 转换测试 现在笔者使用FFmpeg对视频进行转码测试,命令非常简单,首先需要通过-v将视频所在的目录挂载到容器中,然后使用-i选项找到容器中对应的视频文件; 接着就可以对编码进行一些选项,比如-hls_time 10便是将文件没10秒输出一个TS文件,-hls_list_size 0 则是在m3u8文件中记录所以ts文件(默认是记录最后五个TS文件),参数最后则填写文件输出路径,具体参考命令如下: docker run -v /Users/song/video:/root/download jrottenberg/ffmpeg:latest -i /root/download/1.mp4 -hls_time 10 -hls_list_size 0 -f hls /root/download/index.m3u8 命令执行过程中会展示转换进度,参考如下返回所示 Metadata: major_brand : mp42 minor_version : 0 compatible_brands: mp42mp41 encoder : Lavf57.83.100 Stream #0:0(eng): Video: h264 (libx264), yuv420p(progressive), 1920x1080, q=-1--1, 30 fps, 90k tbn, 30 tbc (default) Metadata: creation_time : 2018-08-21T15:09:24.000000Z handler_name : Alias Data Handler encoder : Lavc57.107.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1 Stream #0:1(eng): Audio: aac, 48000 Hz, stereo, fltp, 128 kb/s (default) Metadata: creation_time : 2018-08-21T15:09:24.000000Z handler_name : Alias Data Handler encoder : Lavc57.107.100 aac frame= 82 fps= 12 q=29.0 size=N/A time=00:00:02.62 bitrate=N/A speed=0.381x 此时便可以在刚才的挂载点查看TS文件,如下图所示 现在笔者将刚才的TS文件都删除,在下面将使用自动化完成。 四、服务搭建 在上一步中笔者已经成功通过终端使用FFmpeg将视频进行转码,下面笔者将结合PHP代码将这些操作完全自动化实现,这样便可以达到通过手机访问网站,服务端自动完成转码播放的需求,这个过程包括创建虚拟主机、编写展示视频列表、视频自动解码三个部分 4.1 创建虚拟主机 首先笔者需要借助nginx搭建一个web服务,这时便需要修改配置文件,但并不记得nginx配置文件存放位置,此时可以借助如下命令 sudo nginx -t 得到结果如下,在结果中可以便可以看到nginx的配置文件存放位置 nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful 使用vim编辑器直接编辑nginx配置文件 vim /usr/local/etc/nginx/nginx.conf 然后在配置文件中加入如下参考配置信息 server { listen 8089; server_name localhost; root /Users/song/mycode/work/test/video; location / { index index.html index.htm index.php; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } 4.2 获取视频列表 nginx配置完成之后,便需要编写PHP代码,通过PHP可以获取到目录的视频列表,然后将其输出到网页当中,参考代码如下所示 <?php $list = scandir('/Users/song/video/'); foreach ($list as $key => $val) { if (!in_array(pathinfo($val, PATHINFO_EXTENSION), ['mp4', 'rmvb', 'wmv'])) { continue; } ?> <a class="btn btn-default btn-video btn-lg" href="./encode.php?name=<?= $val ?>" role="button"> <h2><?= $val ?></h2></a> <?php } } ?> 在代码中,首先通过scandir读取文件夹下所有文件,然后进行foreach循环,通过后缀名来判断是否为视频文件,如果是视频文件,则输出一个链接地址方便用户选择。 4.3 进行视频转码 上面的代码在列出视频列表之后,当用户点击链接后就需要使用FFmpeg进行转码,参考代码如下 <?php //接收必要参数 $name = $_GET['name'] ?? '1.mp4'; $forced = $_GET['forced'] ?? 0; $fileName = getFileName($name); $outPath = '/Users/song/video'; $inPath = '/root/download'; $dir = __DIR__; //判断之前是否已经转码,如果不强制转码便先返回 if (is_dir("$outPath/$fileName") && empty($forced)) { header("location:./static/{$fileName}/index.m3u8"); die; } //将目标映射过来 system("ln -s {$outPath} {$dir}/static"); //先创建文件夹 system("mkdir -p {$outPath}/{$fileName}"); //进行转码 $ffmpeg = "docker run -v $outPath:/root/download jrottenberg/ffmpeg:latest"; $cmd = "nohup $ffmpeg -i {$inPath}/{$name} -hls_time 10 -hls_list_size 0 -f hls -r 25 {$inPath}/{$fileName}/index.m3u8 >> ./code.log &"; system($cmd); //延时执行跳转 returnUrl($fileName); function getFileName($filename) { $houzhui = substr(strrchr($filename, '.'), 1); $result = basename($filename, "." . $houzhui); return $result; } function returnUrl($fileName) { echo "<a class='btn btn-video btn-lg' href='./static/{$fileName}/index.m3u8'><h1>正在处理中...点击进行跳转</h1></a>"; die; } 在上面代码当中,考虑文件是否已经被转码,如果已经转码过了直接返回播放地址,否则创建一个存放TS文件的文件夹,然后进行转码,转码的时候使用nohup命令可以让FFmpeg异步执行,然后PHP返回播放地址。 五、检验与测试 通过前面的步骤,笔者已经完整的搭建了一套流媒体服务器,下面将检验这些服务是否能否正常运行,包括视频列表展示、视频转码是否正常、已经转码的视频能否播放 5.1 视频列表 首先通过浏览器打开URL地址如下 http://localhost:8089/ 加载完成之后可以看到如下的视频列表 读者如果将上方的代码运行界面有稍有差异,因为笔者为了节省文章篇幅,并没有将样式代码放到文章当中,如需界面好看可以自行编写样式代码。 5.2 视频转码 在视频列表点击一个链接之后,后台PHP程序将会执行转码任务,然后返回一个链接地址,如下图所示 此时便代表FFmpeg已经在后台运行,可以通过如下命令进行查看FFmpeg这个容器的运行状态,参考命令如下 docker ps 返回的参考结果如下所示 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ac3e7233eb9f jrottenberg/ffmpeg:latest "ffmpeg -i /root/dow…" 1 hours ago Up 1 hours keen_feynman 从上面的返回结果当中可以看出当前正有一个任务处于运行状态,此时打开视频输出目录,会看到有多个ts格式的视频文件,这些文件是刚在通过PHP自动执行所产生的,如下图所示 当看到如上图的转码视频文件时,便可以通过浏览器进行访问 5.3 视频播放 这里需要记住,HLS协议是苹果公司所开发的,因此除了苹果的浏览器外,其他浏览器默认都是不支持m3u8的解析的,如果需要使用其他浏览器播放,需要安装插件;苹果的默认就支持则不需要 笔者重新通过Safari浏览器打开页面,然后再次选择1.mp4视频,则直接跳转到了播放页面,如下图所示 看到这里,搭建流媒体就基本已经完成了,如果需要将更多视频播放,只需要将视频文件存放到指定的视频目录,网页中便会自动读取出来,页面可能太简化,读者可以根据自己的需要将html页面美化一下。 六、新书推荐 如果对笔者的实战文章较为感兴趣,可以关注笔者新书《PHP Web安全开发实战》,现已在各大平台上架销售,封面如下图所示 作者:汤青松 微信:songboy8888 日期:2018-10-28

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

快速上手物联网解决方案(4)—— 数据转储

『物联网平台』默认将设备上传的数据存放在公有云中,实际业务场景下,时常有数据转储到私有数据库的需求,这时我们就需要用到『数据转发』功能。 数据转发前,我们得先了解设备上传到云端的数据到底长什么样。具体来说就是设备数据上报的 Topic 是什么? 在『物联网平台』中打开 设备管理 —— 查看 —— Topic类列表,即可查看该设备数据上下行的默认 Topic: 有了 Topic,我们对数据如何提取就有了底,接着我们跳转到『规则引擎』部分,选择创建规则 —— JSON 格式 —— 处理数据 —— 编辑 —— 输入以下查询字段: items.Accelerometer.value.X, items.Accelerometer.value.Y, items.Accelerometer.value.Z, deviceName() as device

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

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

Nacos

Nacos

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

Rocky Linux

Rocky Linux

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

用户登录
用户注册