精华内容
下载资源
问答
  • 来源:https://lilinchao.com/archives/1226.html一、UidGenerator是什么UidGenerator是百度开源的一款分布式高性能的唯一ID生成器...

    来源:https://lilinchao.com/archives/1226.html

    一、UidGenerator是什么

    UidGenerator是百度开源的一款分布式高性能的唯一ID生成器,是基于snowflake模型的一种ID生成器

    二、UidGenerator的优势

    1. 解决了时钟回调的问题

    2. 使用ringbuffer,无锁进行id的生产与消费,速度非常快

    3. 适用于多线程,不会有单线程瓶颈

    三、整合

    本次通过SpringBoot2.x和MyBatis对百度UidGenerator进行整合。

    3.1 UidGenerator引入

    一般使用两种方式引入UidGenerator:

    (1)从官网下载源码作为自己项目的一个Module引入到项目中

    官网地址:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md

    (2)互联网jar包引入(本文采取的是该种方式)

    因为UidGenerator自带引入了mybatis,和自己项目有冲突的可以进行排除

    <dependency>
        <groupId>com.xfvape.uid</groupId>
        <artifactId>uid-generator</artifactId>
        <version>0.0.4-RELEASE</version>
    </dependency>
    

    排除冲突依赖

    uid-generator中依赖了logback和mybatis。一般在项目搭建过程中,springboot中已经有了logback依赖,mybatis会作为单独的依赖引入。如果版本和uid-generator中的依赖不一致的话,就会导致冲突。

    排除冲突的依赖如下:

    <dependency>
        <groupId>com.xfvape.uid</groupId>
        <artifactId>uid-generator</artifactId>
        <version>0.0.4-RELEASE</version>
        <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>log4j-over-slf4j</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>ch.qos.logback</groupId>
                        <artifactId>logback-classic</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-api</artifactId>
                    </exclusion>
                     <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis-spring</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis</artifactId>
                    </exclusion>
        </exclusions>
    </dependency>
    

    3.2 创建表

    在 MySQL数据库中建一个名为 WORKER_NODE的数据表,其 sql如下:

    CREATE TABLE WORKER_NODE
    (
    ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
    HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
    PORT VARCHAR(64) NOT NULL COMMENT 'port',
    TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
    LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
    MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
    CREATED TIMESTAMP NOT NULL COMMENT 'created time',
    PRIMARY KEY(ID)
    )
     COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;
    

    建表时可能会报错,原因是该建表语句定义了两个TIMESTAMP字段,因为mysql 低版本控制比较严格

    解决办法:

    方式一:

    直接把TIMESTAMP改成DATETIME 即可

    方式二:

    建表前先设置sql_mode:

    set sql_mode="NO_ENGINE_SUBSTITUTION";
    

    3.3 将uid-generator核心对象装配为spring的bean

    uid-generator提供了两种生成器: DefaultUidGenerator、CachedUidGenerator。如对UID生成性能有要求, 请使用CachedUidGenerator。

    @Configuration
    public class WorkerNodeConfig {
    
        @Bean("disposableWorkerIdAssigner")
        public DisposableWorkerIdAssigner disposableWorkerIdAssigner(){
            DisposableWorkerIdAssigner disposableWorkerIdAssigner = new DisposableWorkerIdAssigner();
            return  disposableWorkerIdAssigner;
        }
    
        @Bean("cachedUidGenerator")
        public UidGenerator uidGenerator(DisposableWorkerIdAssigner disposableWorkerIdAssigner){
            CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
            cachedUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);
            return cachedUidGenerator;
        }
    }
    

    直接创建WorkerNodeConfig类,复制以上代码。

    3.4 重写WorkerIdAssigner接口

    public class DisposableWorkerIdAssigner implements WorkerIdAssigner {
    
        @Resource
        private WorkerNodeMapper workerNodeMapper;
        @Override
        @Transactional
        public long assignWorkerId() {
            WorkerNode workerNode = buildWorkerNode();
    
            workerNodeMapper.addWorkerNode(workerNode);
    
            return workerNode.getId();
        }
    
        private WorkerNode buildWorkerNode() {
            WorkerNode workNode = new WorkerNode();
            if (DockerUtils.isDocker()) {
                workNode.setType(WorkerNodeType.CONTAINER.value());
                workNode.setHostName(DockerUtils.getDockerHost());
                workNode.setPort(DockerUtils.getDockerPort());
                workNode.setLaunchDate(new Date());
            } else {
                workNode.setType(WorkerNodeType.ACTUAL.value());
                workNode.setHostName(NetUtils.getLocalAddress());
                workNode.setPort(System.currentTimeMillis() + "-" + RandomUtils.nextInt(100000));
                workNode.setLaunchDate(new Date());
            }
    
            return workNode;
        }
    }
    

    创建一个DisposableWorkerIdAssigner类直接复制以上代码。

    3.5 引入WorkerNodeMapper.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.uidgenerator.mapper.WorkerNodeMapper">
      <resultMap id="BaseResultMap"
                 type="com.uidgenerator.entity.WorkerNode">
        <id column="ID" jdbcType="BIGINT" property="id" />
        <result column="HOST_NAME" jdbcType="VARCHAR" property="hostName" />
        <result column="PORT" jdbcType="VARCHAR" property="port" />
        <result column="TYPE" jdbcType="INTEGER" property="type" />
        <result column="LAUNCH_DATE" jdbcType="DATE" property="launchDate" />
        <result column="MODIFIED" jdbcType="TIMESTAMP" property="modified" />
        <result column="CREATED" jdbcType="TIMESTAMP" property="created" />
      </resultMap>
    
      <insert id="addWorkerNode" useGeneratedKeys="true" keyProperty="id"
              parameterType="com.uidgenerator.entity.WorkerNode">
            INSERT INTO WORKER_NODE
            (HOST_NAME,
             PORT,
             TYPE,
             LAUNCH_DATE,
             MODIFIED,
             CREATED)
            VALUES (
                       #{hostName},
                       #{port},
                       #{type},
                       #{launchDate},
                       NOW(),
                       NOW())
        </insert>
    
      <select id="getWorkerNodeByHostPort" resultMap="BaseResultMap ">
            SELECT
                ID,
                HOST_NAME,
                PORT,
                TYPE,
                LAUNCH_DATE,
                MODIFIED,
                CREATED
            FROM
                WORKER_NODE
            WHERE
                HOST_NAME = #{host} AND PORT = #{port}
        </select>
    </mapper>
    

    可以通过mybatis生成工具直接生成文件和实体类,然后将插入和查询方法复制

    注意修改resultMap中的type和insert中的keyProperty为自身项目的实体类地址

    在application.yml文件中增加如下配置

    mybatis:
      mapper-locations: classpath:mybatis/*.xml
    

    3.6实体类

    使用插件生成的实体类

    3.7创建Mapper

    @Mapper
    public interface WorkerNodeMapper {
    
        int addWorkerNode(WorkerNode workerNodeEntity);
    
    
        WorkerNode getWorkerNodeByHostPort(@Param("host") String host, @Param("port") String port);
    
    }
    

    3.8 Service

    IWorkerNodeService接口

    public interface IWorkerNodeService {
        public long genUid();
    }
    

    WorkerNodeServiceImpl实现类

    @Service
    public class WorkerNodeServiceImpl implements IWorkerNodeService {
        @Resource
        private UidGenerator uidGenerator;
    
        @Override
        public long genUid() {
            Long uu\_id = UidGeneratorComponent.uu\_id;
            return uidGenerator.getUID();
        }
    }
    

    3.8 Controller

    @RestController
    public class WorkerNodeServiceController {
        @Resource
        private IWorkerNodeService workerNodeService;
        /**
         * 集成百度uid-generator生成id
         * @return
         */
        @GetMapping("/baidu/uid")
        public long baiduUid(){
            long uid = workerNodeService.genUid();
            return uid;
        }
    }
    

    3.9 访问接口测试

    http://127.0.0.1:8099/test/baidu/uid

    项目目录结构

    推荐好文

    强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

    分享一套基于SpringBoot和Vue的企业级中后台开源项目,代码很规范!

    能挣钱的,开源 SpringBoot 商城系统,功能超全,超漂亮

    展开全文
  • 对于App云平台系统,如何唯一标识移动设备非常重要.... iOS受到系统强大限制的独特认可. 目前,唯一可以部分满足条件的部分是IDFA,但这要求您的App本身必须嵌入广告.当许多开发人员使用Jiguang P...

    8d5e47879341ff4dc584a2ce4e7bba7c.png

    对于App云平台系统,如何唯一标识移动设备非常重要. 否则,每次用户在设备上卸载并重新安装应用程序时,后端系统只能将用户视为全新用户.

    在Android上识别设备的唯一性. 因为这个圆圈太乱了,所以设备本身的任何标识都不能直接用作设备的唯一标识. iOS受到系统强大限制的独特认可. 目前,唯一可以部分满足条件的部分是IDFA,但这要求您的App本身必须嵌入广告.

    当许多开发人员使用Jiguang Push时,他们有一个问题: Jiguang Push如何唯一地标识设备. 本文分析了Aurora Push如何尽可能唯一地标识设备.

    Jiguang Push使用RegistrationID作为设备上安装的App的标识. Aurora Push希望“尽可能”确保设备的唯一性,即使RegistrationID尽可能唯一.

    关于RegistrationID,积光的正式文件具有以下定义:

    be849099af043d2f98bf5da0ac5ba0f8.png

    启动第一个应用程序后,将与JPush SDK集成的应用程序成功注册到JPush服务器时,JPush服务器将把device-RegistrationID的唯一标识返回给客户端. JPush SDK将以广播的形式将RegistrationID发送到应用程序.

    有了此标识,App编程可以将此RegistrationID保存到其自己的应用程序服务器,然后根据RegistrationID将消息或通知推送到设备.

    如果未卸载该应用,则会直接覆盖并安装该应用,Android和iOS上的RegistrationID的值不会更改.

    如果该应用已卸载然后再次安装:

    在Android上,由于中国存在大量假冒设备,因此无法使用可被视为唯一标识符的常规IMEI,Mac地址和AndroidID值,因为这些值可能在一批设备中相同的值.

    c6342b4a12d1c604350798619598998d.png

    Aurora的基本思想是:

    生成DeviceID并将其保存到“设置”,“外部存储”. 依靠本地存储. 卸载并重新安装应用程序后,这些存储中的DeviceID仍然是同一设备. 这个理论上解决了90%的不变性问题. 在DeviceID之外添加补充规则: 根据IMEI,MAC地址,AndroidID的值全面判断它是否是旧设备.

    根据实际操作条件和收集的反馈不断调整特定的逻辑细节. 大多数逻辑都可以在服务器端进行调整.

    由于iOS系统设计限制了设备的唯一标识,因此Jiguang一直使用Device Token作为标识,并且因为Jiguang Push本身需要Device Token的值才能运行.

    在iOS 9版本之后,每次卸载后重新安装都会导致设备令牌更改,因此对于Jiguang后端,只能将其识别为新用户.

    ad4857623c8d2d59fbe3b27d40c5f6f7.png

    新版的Jiguang SDK添加了IDFA选项. 集成并初始化SDK时,可以设置IDFA值,以便Jiguang背景会首先根据IDFA值识别用户如何查设备码,并在有可能的情况下在卸载后重新安装该应用程序,还可以将其标识为旧设备.

    IDFA是广告标识符,由iOS专门设计,用于唯一标识用于广告跟踪的用户. 在iOS设备上,设备->隐私->广告页面上有一个设置项: 限制广告跟踪. 默认未选中,即关闭状态,没有限制. 用户可以选择限制广告跟踪. 除了设置外,还有一个按钮: 恢复广告标识符...如果用户单击此按钮,则IDFA值将更改.

    2115454-b0c648ae038d8d0a.png

    默认情况下,广告跟踪没有限制,并且可以采用IDFA值. 并且当用户不单击“还原广告徽标”时如何查设备码,此值将不会更改. 这样就可以达到唯一识别设备并跟踪用户的目的.

    但是,请注意,不一定要启用IDFA. 它要求您的应用程序具有广告功能,然后才能使用. 否则,Apple可能会在审核过程中发现并拒绝.

    e4951c0cde4d87cba7d8b363fe65f047.png

    有关Apple App的IDFA要求,请参阅此处的说明:

    由于在JPush SDK注册完成后获得了RegistrationID,因此在调用SDK API以获得RegistrationID的值时需要注意. 它并不总是立即可用.

    例如,在iOS上,建议在监视通知kJPFNetworkDidLoginNotification后获取代码中RegistrationID的值.

    Android拥有写设置的权限,该设置可以将数据写到设置中,等效于用作永久存储点. 外部存储通常指的是SDCard,现在越来越多的手机直接与手机一起使用,就像iPhone一样.

    如果这两点的数据都被破坏,则实际上不会通过本地DeviceID存储确认为唯一设备. 但是,服务器还可以通过IMEI / AndroidID灵活地确认设备是否相同.

    从上方复制

    本文来自电脑杂谈,转载请注明本文网址:

    http://www.pc-fly.com/a/ruanjian/article-288610-1.html

    展开全文
  • 摘要:有趣的编程谜题可以练习你解决问题的能力,快来挑战吧~~
    摘要:有趣的编程谜题可以练习你解决问题的能力,快来挑战吧~~

    本文分享自华为云社区《代码的出现:用 Python 解决你的难题》,作者: Yuchuan 。

    代码谜题的出现旨在让任何对解决问题感兴趣的人都能上手。您不需要具有深厚的计算机科学背景即可参与。相反,代码的来临是学习新技能和测试 Python 新功能的绝佳场所。

    编程中的困惑?

    处理谜题似乎是在浪费您可用的编程时间。毕竟,您似乎并没有真正生产出任何有用的东西,也没有推进您当前的项目。

    然而,花一些时间练习编程谜题有几个好处:

    • 与您的常规工作任务相比,编程难题通常更明确且包含更多内容。它们让您有机会针对比您在日常工作中通常需要处理的问题更简单的问题练习逻辑思维
    • 你经常可以用几个类似的谜题来挑战自己。这使您可以建立程序记忆,就像肌肉记忆一样,并获得构建某些类型代码的经验。
    • 拼图的设计通常着眼于解决方案。它们使您可以了解和应用经过试验和测试的算法,这些算法是任何程序员工具箱的重要组成部分。
    • 对于一些谜题解决方案,如果算法效率低下,即使是最强大的超级计算机也可能太慢。您可以分析您的解决方案的性能并获得经验,以帮助您了解什么时候简单的方法足够快,什么时候需要更优化的程序。
    • 大多数编程语言都非常适合解决编程难题。这为您提供了一个很好的机会,可以针对不同的任务比较不同的编程语言。拼图也是了解新编程语言或尝试您最喜欢的语言的一些最新功能的好方法。

    最重要的是,用编程难​​题挑战自己通常非常有趣!当你把所有的东西加起来时,为谜题留出一些时间是非常有益的。

    探索在线解决编程难题的选项

    幸运的是,您可以在许多网站上找到编程难题并尝试解决它们。这些网站存在的问题类型、您提交解决方案的方式以及网站可以提供的反馈和社区类型通常存在差异。因此,您应该花一些时间环顾四周,找到对您最有吸引力的那些。

    在本教程中,您将了解代码的来临,包括您可以在那里找到什么样的谜题以及您可以使用哪些工具和技巧来解决它们。但是,您也可以在其他地方开始解决编程难题:

    • Exercism有许多不同编程语言的学习路径。每个学习轨道都提供有关不同编程概念、编码挑战和指导者的小型教程,为您提供有关解决方案的反馈。
    • 欧拉计划已经存在很长时间了。该网站提供数百个谜题,通常以数学问题的形式表述。您可以使用任何编程语言解决问题,一旦您解决了难题,您就可以访问社区线程,在那里您可以与其他人讨论您的解决方案。
    • Code Wars提供了大量的编码挑战,他们称之为katas。您可以使用许多不同的编程语言通过内置编辑器和自动化测试解决难题。之后,您可以将您的解决方案与其他人的解决方案进行比较,并在论坛中讨论策略。
    • 如果您正在寻找工作,HackerRank具有强大的功能。他们提供许多不同技能的认证,包括解决问题和 Python 编程,以及一个工作板,可让您在工作申请中展示自己的解谜技能。

    还有许多其他网站可供您练习解谜技巧。在本教程的其余部分,您将重点关注 Advent of Code 必须提供的内容。

    为 Code 的出现做准备:25 个圣诞节的新鲜谜题

    现在是代码出现的时候了!它由Eric Wastl于 2015 年创立。从那时起,每年 12 月都会发布包含 25 个新编程谜题的新出现日历。这些年来,拼图变得越来越流行。自 2020 年以来,已有超过 170,000人至少解决了其中一个难题。

    注意:传统上,降临节日历是用于在等待圣诞节期间计算降临节天数的日历。多年来,降临节日历变得更加商业化并且失去了一些与基督教的联系。

    大多数降临节日历从 12 月 1 日开始,到 12 月 24 日(平安夜)或 12 月 25 日(圣诞节)结束。如今,各种降临节日历应有尽有,包括乐高日历、茶日历和化妆品日历。

    在传统的降临节日历中,您每天打开一扇门以显示里面的内容。Advent of Code 模仿了这一点,让您从 12 月 1 日到 12 月 25 日每天打开一个谜题。对于您解决的每个难题,您都将获得金星,您可以保留这些星星。

    在本节中,您将更加熟悉 Advent of Code 并瞥见您的第一个谜题。稍后,您将了解如何解决这些难题的详细信息,并练习自己解决一些难题。

    代码谜题的出现

    Advent of Code 是一个在线 Advent 日历,从 12 月 1 日到 12 月 25 日,每天都会发布一个新的谜题。每个谜题都在美国东部时间午夜可用。Advent of Code 谜题有几个典型特征:

    • 每个谜题由两部分组成,但在您完成第一部分之前不会显示第二部分。
    • 每完成一个部分,您将获得一颗金星 (⭐)。这意味着如果您在一年内解决所有难题,您每天可以获得两颗星和五十颗星。
    • 每个人的谜题都是一样的,但您需要根据从 Advent of Code 网站获得的个性化输入来解决它。这意味着您对一个谜题的答案将与其他人的不同,即使您使用相同的代码来计算它。

    您可以参加全球竞赛,成为第一个解决每个难题的人。然而,这里通常挤满了高技能、有竞争力的程序员。如果您将 Code of Code 用作自己的练习,或者如果您向您的朋友和同事发起小型友好竞赛,它可能会更有趣。

    要了解代码出现难题的工作原理,请考虑2020 年的第一天难题:

    在你离开之前,会计精灵只需要你修正你的开支报告(你的拼图输入);显然,有些事情并没有完全加起来。

    具体来说,他们需要您找到总和为的两个条目,2020然后将这两个数字相乘。

    每年,都会有一个非常愚蠢的背景故事将谜题联系在一起。2020 年的故事描述了您尝试离开去度过一个当之无愧的假期,因为您已经连续几年拯救了圣诞节。这个故事通常对谜题没有影响,但跟随它仍然很有趣。

    在故事的情节元素之间,你会发现谜题本身。在此示例中,您要在拼图输入中查找总和为 2,020 的两个条目。在描述问题的解释之后,您通常会找到一个示例,显示您需要执行的计算:

    例如,假设您的费用报告包含以下内容:

    1721
    979
    366
    299
    675
    1456

    在这份名单中,这两个条目总和2020是1721和299。将它们相乘产生1721 * 299 = 514579,所以正确答案是514579

    该示例向您展示了此特定数字列表的答案。如果您要开始解决这个难题,现在您将开始考虑如何在任何有效数字列表中找到这两个条目。但是,在深入研究这个难题之前,您将探索如何使用 Advent of Code 站点。

    如何参与代码的出现

    您已经看到了代码出现难题的示例。接下来,您将了解如何提交答案。您永远不会提交任何代码来解决难题。您只需提交答案,通常是数字或文本字符串。

    通常,您将按照一系列步骤来解决网站上的难题:

    1. 登录Advent of Code网站。您可以使用来自其他服务(如 GitHub、Google、Twitter 或 Reddit)的凭据来执行此操作。
    2. 阅读拼图文字并特别注意给定的例子。您应该确保您了解示例数据的解决方案。
    3. 下载拼图的个性化输入。您将需要此输入才能找到问题的唯一答案。
    4. 编写您的解决方案。这是有趣的部分,您将在本教程的其余部分获得大量练习。
    5. 在拼图页面上输入您对拼图的答案。如果您的答案是正确的,那么您将获得一颗金星,并打开谜题的第二部分。
    6. 对拼图的第二部分重复步骤 2 到 4。第二部分与第一部分类似,但它通常会增加一些需要您调整代码的扭曲。
    7. 在拼图页面上输入您的第二个答案,以获得第二颗星并完成拼图。

    请记住,您不提交任何代码——只提交您的谜题答案。这意味着可以用任何编程语言解决代码难题的出现。许多人使用 Advent of Code 来练习和学习一种新的编程语言。Advent of Code 的创建者Eric Wastl在 2019 年发表了一次演讲,他谈到了参与人员的不同背景和动机等。

    注意:有一个Advent of Code的排行榜。一般来说,你应该忽略这个排行榜!它仅显示在拼图打开后谁提交了前 100 个解决方案。要想跻身排行榜,您需要大量的准备、奉献精神和竞争性编程的经验。

    相反,您应该查看私人排行榜。这些在您登录后可用,它们让您有机会邀请您的朋友和同事加入更轻松的社区。您可以选择基于要么得分您的私人排行榜的困惑基础上得到解决或者干脆数量困惑的人已经解决了的。

    您还可以将您在私人排行榜中的名字链接到您的GitHub帐户,这样您就可以与朋友分享您的解决方案。登录后,您可以通过单击Advent of Code 站点菜单中的设置来进行设置。

    Advent of Code 完全免费使用,但您仍然可以通过几种不同的方式支持该项目:

    • 您可以在您的社交媒体上分享有关 Advent of Code 的信息以宣传。
    • 您可以通过参与r/adventofcode subreddit 或其他论坛来帮助他人
    • 您可以邀请您的朋友参加 Advent of Code,在私人排行榜上分享您的结果。
    • 您可以向 Advent of Code捐款。如果您这样做了,那么您将在网站上的姓名旁边看到一个AoC++徽章。

    在接下来的部分中,您将看到有关如何准备使用 Python 解决代码出现问题的一些建议。还有一个很棒的列表,您可以查看与 Advent of Code 相关的许多不同资源的链接,包括许多其他人的解决方案。

    用 Python 解决代码的出现

    Code of Code 已成为全球许多编码人员的年度亮点。2020 年,超过 170,000人提交了他们的解决方案。自 2015 年 Advent of Code 启动以来,已有超过 380,000 名程序员参与其中。他们中的许多人使用 Python 来解决难题。

    那么,现在轮到你了!前往Advent of Code 网站,查看最新的谜题。然后,返回本教程获取一些提示并帮助开始使用 Python 解决代码出现难题。

    拼图的剖析

    在本节中,您将探索代码出现难题的典型剖析。此外,您将了解一些可用于与之交互的工具。

    每个 Advent of Code 谜题都分为两部分。当您开始处理拼图时,您只会看到第一部分。一旦您提交了第一部分的正确答案,第二部分就会解锁。这通常是您在第一部分解决的问题的转折点。有时,您会发现有必要从第一部分重构您的解决方案,而有时您可以根据您已经完成的工作快速解决第二部分。

    两个部分始终使用相同的拼图输入。您可以从当天的拼图页面下载拼图输入。您会在拼图说明后找到一个链接。

    注意:如前所述,您的拼图输入是个性化的。这意味着如果您与其他人讨论解决方案,他们的最终答案可能与您的不同。

    提交拼图解决方案所需执行的所有操作(实际解决拼图除外)都可以在 Advent of Code 网站上完成。您应该使用它来提交您的第一个解决方案,以便您熟悉流程。

    稍后,您可以使用多种工具来组织 Advent of Code 设置并提高工作效率。例如,您可以使用该advent-of-code-data包下载数据。这是一个可以使用pip安装的 Python 包:

    $ python -m pip install advent-of-code-data

    您可以使用advent-of-code-data其aocd工具在命令行上下载特定的拼图输入集。另一个有趣的可能性是在您的 Python 代码中自动下载和缓存您的个性化拼图输入:

    >>>
    >>> from aocd.models import Puzzle
    >>> puzzle = Puzzle(year=2020, day=1)
    
    >>> # Personal input data. Your data will be different.
    >>> puzzle.input_data[:20]
    '1753\n1858\n1860\n1978\n'

    您需要在环境变量或文件中设置会话 ID,然后才能使用advent-of-code-data. 您将在文档中找到对此的解释。如果您感兴趣,还可以使用advent-of-code-data或aocd提交您的解决方案并查看您之前的答案。

    作为拼图文本的一部分,您还会发现一个或多个示例,这些示例通常是根据比您的个性化输入数据更小的数据来计算的。在开始编码之前,您应该仔细阅读这些示例,并确保您了解要求您执行的操作。

    您可以使用这些示例为您的代码设置测试。一种方法是在示例数据上手动运行您的解决方案并确认您得到了预期的答案。或者,您可以使用类似工具pytest来自动化该过程。

    注意: 测试驱动开发 (TDD)是一个在实现代码之前编写测试的过程。由于 Advent of Code 为您提供了对小示例的预期答案,因此它为您提供了自己尝试测试驱动开发的绝佳机会。

    稍后当您尝试自己解决一些难题时,您将了解有关 TDD 的更多信息。

    您只需使用简单的 Python 和标准库即可解决所有 Advent of Code 难题。但是,有一些软件包可以帮助您整理解决方案:

    • advent-of-code-data 可以下载您的输入数据并提交您的解决方案。
    • pytest 可以自动检查示例数据上的解决方案。
    • parse可以用比正则表达式更简单的语法来解析字符串。
    • numpy 可以有效地计算数字数组。
    • colorama 可以在终端中为您的解决方案设置动画。

    如果您创建了一个虚拟环境并安装了这些包,那么您将拥有一个非常可靠的工具箱,用于您的 Advent of Code 冒险。后来,你会看到你如何使用的例子parse,numpy和colorama解决难题。

    解决方案的结构

    在上一节中,您熟悉了如何阅读和理解 Advent of Code 谜题。在本节中,您将了解如何解决这些问题。在解决“代码出现”难题之前,您无需进行大量设置。

    你有没有想过如何解决你之前看到的难题?回想一下,您正在查找列表中总和为 2,020 的两个数字的乘积。在继续之前,请考虑——也许可以编写代码——如何找到以下列表中哪两个条目的总和为 2,020:

    numbers = [1721, 979, 366, 299, 675, 1456]

    以下脚本显示了解决2020 年第 1 天难题的第一部分的一种方法:

     1for num1 in numbers:
     2    for num2 in numbers:
     3        if num1 < num2 and num1 + num2 == 2020:
     4            print(num1 * num2)

    嵌套for循环从列表中查找两个数字的所有组合。第 3 行的测试实际上比实际需要的稍微复杂一些:您只需要测试数字总和是否为 2,020。但是,通过添加num1应该小于的条件,num2可以避免两次找到解。

    在这个例子中,一个解决方案的模样num1 = 1721和num2 = 299,但因为你可以以任何顺序添加数字,这意味着还num1 = 299和num2 = 1721形成的解决方案。通过额外检查,仅报告后一种组合。

    一旦你有了这个解决方案,你就可以将你的个性化输入数据复制到numbers列表中并计算你的谜题答案。

    注意:有比尝试所有可能性更有效的方法来计算这个答案。但是,从基本方法开始通常是个好主意。引用乔·阿姆斯特朗的话说:

    让它工作,然后让它漂亮,然后如果你真的,真的必须,让它快。90% 的情况下,如果你让它漂亮,它已经很快了。所以真的,只是让它漂亮!(来源)

    —乔·阿姆斯特朗

    既然你已经看到了这个谜题的有效解决方案,你能把它做得漂亮吗?

    当您解决更多难题时,您可能会开始觉得将数据复制到代码中并将其重写为有效的 Python 变得很烦人。类似地,向代码中添加一些函数可为您提供更大的灵活性。例如,您可以使用它们向代码中添加测试。

    Python 有许多强大的字符串解析功能。从长远来看,最好在下载时保留输入数据,让 Python 将它们解析为可用的数据结构。事实上,将代码分成两个函数通常是有益的。一个函数将解析字符串输入,另一个函数将解决这个难题。基于这些原则,你可以重写你的代码:

     1# aoc202001.py
     2
     3import pathlib
     4import sys
     5
     6def parse(puzzle_input):
     7    """Parse input"""
     8    return [int(line) for line in puzzle_input.split()]
     9
    10def part1(numbers):
    11    """Solve part 1"""
    12    for num1 in numbers:
    13        for num2 in numbers:
    14            if num1 < num2 and num1 + num2 == 2020:
    15                return num1 * num2
    16
    17if __name__ == "__main__":
    18    for path in sys.argv[1:]:
    19        print(f"\n{path}:")
    20        puzzle_input = pathlib.Path(path).read_text().strip()
    21
    22        numbers = parse(puzzle_input)
    23        print(part1(numbers))

    在第 12 到 15 行,您将识别出您之前的解决方案。首先,您已将其包装在一个函数中。这使得以后更容易向代码中添加自动测试。您还添加了一个parse()函数,可以将字符串行转换为数字列表。

    在第 20 行,您用于pathlib将文件内容作为文本读取并去除末尾的所有空白行。循环sys.argv为您提供在命令行中输入的所有文件名。

    在您处理解决方案时,这些更改为您提供了更大的灵活性。假设您已将示例数据存储在名为 的文件中,example.txt并将您的个性化输入数据存储在名为input.txt. 然后,您可以通过在命令行上提供它们的名称,在其中任何一个或什至两者上运行您的解决方案:

    $ python aoc202001.py example.txt input.txt
    example.txt:
    514579
    
    input.txt:
    744475

    514579确实是使用示例输入数据时问题的答案。请记住,您的个性化输入数据的解决方案将与上面显示的解决方案不同。

    现在是时候让 Advent of Code 网站一展身手了!转到2020 Advent of Code 日历并找到第 1 天的谜题。如果您还没有,请下载输入数据并计算谜题的解决方案。然后,在网站上输入您的解决方案并点击提交。

    起始模板

    正如您在上面看到的,代码谜题的出现遵循一套结构。因此,为自己创建一个模板是有意义的,您可以在开始编写解决方案时将其用作起点。您在这样的模板中到底想要多少结构是个人品味的问题。首先,您将探索一个基于您在上一节中看到的原则的模板示例:

     1# aoc_template.py
     2
     3import pathlib
     4import sys
     5
     6def parse(puzzle_input):
     7    """Parse input"""
     8
     9def part1(data):
    10    """Solve part 1"""
    11
    12def part2(data):
    13    """Solve part 2"""
    14
    15def solve(puzzle_input):
    16    """Solve the puzzle for the given input"""
    17    data = parse(puzzle_input)
    18    solution1 = part1(data)
    19    solution2 = part2(data)
    20
    21    return solution1, solution2
    22
    23if __name__ == "__main__":
    24    for path in sys.argv[1:]:
    25        print(f"{path}:")
    26        puzzle_input = pathlib.Path(path).read_text().strip()
    27        solutions = solve(puzzle_input)
    28        print("\n".join(str(solution) for solution in solutions))

    该模板具有用于解析输入以及解决谜题的两个部分的单独函数。您根本不需要触及第 15 到 27 行。他们照顾的阅读文本从输入文件,要求parse(),part1()和part2(),然后再报告解决方案控制台。

    您可以创建一个类似的模板来测试您的解决方案。

    注意:如前所述,示例数据对于创建测试很有用,因为它们代表具有相应解决方案的已知数据。

    以下模板pytest用作测试运行程序。它的三个不同的测试,每一个功能的准备parse(),part1()以及part2():

     1# test_aoc_template.py
     2
     3import pathlib
     4import pytest
     5import aoc_template as aoc
     6
     7PUZZLE_DIR = pathlib.Path(__file__).parent
     8
     9@pytest.fixture
    10def example1():
    11    puzzle_input = (PUZZLE_DIR / "example1.txt").read_text().strip()
    12    return aoc.parse(puzzle_input)
    13
    14@pytest.fixture
    15def example2():
    16    puzzle_input = (PUZZLE_DIR / "example2.txt").read_text().strip()
    17    return aoc.parse(puzzle_input)
    18
    19@pytest.mark.skip(reason="Not implemented")
    20def test_parse_example1(example1):
    21    """Test that input is parsed properly"""
    22    assert example1 == ...
    23
    24@pytest.mark.skip(reason="Not implemented")
    25def test_part1_example1(example1):
    26    """Test part 1 on example input"""
    27    assert aoc.part1(example1) == ...
    28
    29@pytest.mark.skip(reason="Not implemented")
    30def test_part2_example2(example2):
    31    """Test part 2 on example input"""
    32    assert aoc.part2(example2) == ...

    你会看到,你如何使用这个模板的例子以后。在此之前,您应该注意以下几点:

    • 如第 1 行所示,您应该pytest使用test_前缀命名您的文件。
    • 类似地,每个测试都在一个以test_前缀命名的函数中实现。您可以在第 20、25 和 30 行看到这些示例。
    • 您应该更改第 5 行的导入以导入您的解决方案代码。
    • 该模板假定示例数据存储在名为example1.txt和 的文件中example2.txt。
    • 当您准备好开始测试时,您应该删除第 19、24 和 29 行的跳过标记。
    • 您需要...根据示例数据和相应的解决方案填写第 22、27 和 32 行的省略号 ( )。

    例如,如果您要将此模板改编为上一节中 2020 年第 1 天谜题第一部分的重写解决方案,则您需要创建一个example1.txt包含以下内容的文件:

    1721
    979
    366
    299
    675
    1456

    接下来,您将删除前两个测试的跳过标记并按如下方式实现它们:

    def test_parse_example1(example1):
        """Test that input is parsed properly"""
        assert example1 == [1721, 979, 366, 299, 675, 1456]
    
    def test_part1_example1(example1):
        """Test part 1 on example input"""
        assert aoc.part1(example1) == 514579

    最后,您需要确保您正在导入您的解决方案。如果您使用了 filename aoc202001.py,那么您应该将第 5 行更改为 import aoc202001:

     5import aoc202001 as aoc

    然后,您将运行pytest以检查您的解决方案。如果您正确地实施了您的解决方案,那么您会看到如下内容:

    $ pytest
    ====================== test session starts =====================
    collected 3 items
    
    test_aoc202001.py ..s                                     [100%]
    ================= 2 passed, 1 skipped in 0.02s =================

    注意... 前面的两个点 ( ) s。它们代表两个通过的测试。如果测试失败,您会看到F而不是每个点,以及出现问题的详细说明。

    Cookiecutter和Copier等工具可以更轻松地处理此类模板。如果您安装了 Copier,那么您可以通过运行以下命令来使用类似于您在此处看到的模板:

    $ copier gh:gahjelle/template-aoc-python advent_of_code

    这将为advent_of_code您计算机上目录的子目录中的一个特定拼图设置模板。

    解决策略

    代码谜题的出现非常多样化。随着日历的推进,您将解决许多不同的问题,并发现许多解决这些问题的不同策略。

    其中一些策略非常通用,可以应用于任何谜题。如果您发现自己被一个谜题卡住了,您可以尝试解决以下问题:

    • 重新阅读说明。代码谜题的出现通常非常明确,但其中一些可能包含大量信息。确保您没有遗漏拼图的重要部分。
    • 积极使用示例数据。确保您了解这些结果是如何实现的,并检查您的代码是否能够重现这些示例。
    • 一些谜题可能会涉及一些。将问题分解为更小的步骤,并单独实施和测试每个步骤。
    • 如果您的代码适用于示例数据但不适用于您的个性化输入数据,那么您可以根据您能够手动计算的数字构建其他测试用例,以查看您的代码是否涵盖所有极端情况。
    • 如果您仍然被卡住,那么在一些致力于代码出现的论坛上与您的朋友和其他解谜者联系,并询问他们如何解决谜题的提示。

    随着您做越来越多的谜题,您将开始认识到一些反复出现的一般谜题。

    一些谜题涉及文本和密码。Python 有几个强大的工具来处理文本字符串,包括许多字符串方法。要读取和解析字符串,了解正则表达式的基础知识会很有帮助。但是,您通常也可以使用第三方parse库。

    例如,假设您有字符串"shiny gold bags contain 2 dark red bags."并希望从中解析相关信息。您可以使用parse及其模式语法:

    >>>
    >>> import parse
    >>> string = "shiny gold bags contain 2 dark red bags."
    >>> pattern = "{outer_color} bags contain {num:d} {inner_color} bags."
    >>> match = parse.search(pattern, string)
    >>> match.named
    {'outer_color': 'shiny gold', 'num': 2, 'inner_color': 'dark red'}

    在后台,parse构建一个正则表达式,但您使用类似于f-strings使用的语法的更简单的语法。

    在其中一些文本问题中,明确要求您使用代码和解析器,通常构建小型自定义汇编语言。解析完代码后,通常需要运行给定的程序。实际上,这意味着您构建了一个小型状态机,可以跟踪其当前状态,包括其内存的内容。

    您可以使用类将状态与行为保持在一起。在 Python 中,数据类非常适合快速设置状态机。以下示例显示了一个可以处理两种不同指令的小型状态机的实现:

     1from dataclasses import dataclass
     2
     3@dataclass
     4class StateMachine:
     5    memory: dict[str, int]
     6    program: list[str]
     7
     8    def run(self):
     9        """Run the program"""
    10        current_line = 0
    11        while current_line < len(self.program):
    12            instruction = self.program[current_line]
    13
    14            # Set a register to a value
    15            if instruction.startswith("set "):
    16                register, value = instruction[4], int(instruction[6:])
    17                self.memory[register] = value
    18
    19            # Increase the value in a register by 1
    20            elif instruction.startswith("inc "):
    21                register = instruction[4]
    22                self.memory[register] += 1
    23
    24            # Move the line pointer
    25            current_line += 1

    这两个指令set并inc进行分析和内处理.run()。请注意,第5 行和第 6 行的类型提示使用更新的语法,该语法仅适用于Python 3.9及更高版本。如果您使用的是旧版本的 Python,那么您可以使用 importDict和Listfromtyping代替。

    要运行您的状态机,您首先使用初始内存对其进行初始化并将程序加载到机器中。接下来,您调用.run(). 程序完成后,您可以检查.memory以查看机器的新状态:

    >>>
    >>> state_machine = StateMachine(
    ...     memory={"g": 0}, program=["set g 44", "inc g"]
    ... )
    >>> state_machine.run()
    >>> state_machine.memory
    {'g': 45}

    该程序首先设置g为 的值44,然后增加它,使其最终值为45。

    一些有趣的谜题涉及网格和迷宫。如果您的网格具有固定大小,那么您可以使用NumPy来获得它的有效表示。迷宫通常有助于可视化。您可以使用Colorama直接在您的终端中绘制:

    import numpy as np
    from colorama import Cursor
    
    grid = np.array(
        [
            [1, 1, 1, 1, 1],
            [1, 0, 0, 0, 1],
            [1, 1, 1, 0, 1],
            [1, 0, 0, 2, 1],
            [1, 1, 1, 1, 1],
        ]
    )
    
    num_rows, num_cols = grid.shape
    for row in range(num_rows):
        for col in range(num_cols):
            symbol = " #o"[grid[row, col]]
            print(f"{Cursor.POS(col + 1, row + 2)}{symbol}")

    此脚本显示了使用 NumPy 数组存储网格,然后使用Cursor.POSfrom Colorama 在终端中定位光标以打印出网格的示例。运行此脚本时,您将看到如下输出:

    #####
    #   #
    ### #
    #  o#
    #####

    在运行时可视化您的代码可能很有趣,并且还可以为您提供一些很好的见解。当您在调试并且不太了解正在发生的事情时,它也可以是非常宝贵的帮助。

    到目前为止,在本教程中,您已经获得了一些关于如何使用 Advent of Code 谜题的一般提示。在接下来的部分中,您将获得更明确的信息并解决早年的两个难题。

    代码实践:2019 年第 1 天

    您将尝试自己解决的第一个难题是2019 年第 1 天,称为火箭方程式的暴政。这是一个典型的第 1 天难题,因为该解决方案并不是很复杂。这是一个很好的练习,可以习惯 Advent of Code 的工作方式并检查您的环境是否已正确设置。

    第 1 部分:拼图说明

    在 2019 年的故事情节中,你将拯救被困在太阳系边缘的圣诞老人。在第一个谜题中,您正在准备发射火箭:

    精灵们迅速将您装入宇宙飞船并准备发射。

    在第一次 Go / No Go 民意调查中,每个 Elf 都是 Go,直到 Fuel Counter-Upper。他们还没有确定所需的燃料量。

    发射给定模块所需的燃料基于其质量。具体来说,要找到模块所需的燃料,取其质量,除以 3,向下取整,然后减去 2。

    示例数据如下所示:

    • 对于质量12,除以 3 并向下取整得到4,然后减去 2 得到2。
    • 对于质量14,除以 3 并四舍五入仍然产生4,因此所需的燃料也是2。
    • 对于质量为1969,所需的燃料为654。
    • 对于质量为100756,所需的燃料为33583。

    您需要计算航天器的总燃料需求:

    Fuel Counter-Upper 需要知道总燃料需求。要找到它,请单独计算每个模块(您的拼图输入)的质量所需的燃料,然后将所有燃料值加在一起。

    您的航天器上所有模块的燃料需求总和是多少?

    现在是时候尝试自己解决难题了!下载您的个性化输入数据并在 Advent of Code 上检查您的解决方案可能是最有趣的,这样您就可以获得星星。但是,如果您还没有准备好登录 Advent of Code,请根据上面提供的示例数据随意解决难题。

    第 1 部分:解决方案

    完成拼图并获得星星后,您可以展开折叠块以查看拼图解决方案的讨论:

    2019 年第 1 天的解决方案,第 1 部分显示隐藏

    您现在已经解决了谜题的第一部分。但是,在进入谜题的第二部分之前,下一部分将展示如何使用之前在解决此问题时看到的模板。

    第 1 部分:使用模板的解决方案

    展开下面的折叠块,查看 2019 年第 1 天代码出现难题第一部分的另一个解决方案——这次使用您之前看到的模板来组织代码并简化测试:

    2019 年第 1 天第 1 部分的模板化解决方案显示隐藏

    您现在可以继续进行拼图的第二部分。你准备好扭转了吗?

    第 2 部分:拼图说明

    每个 Advent of Code 谜题都由两部分组成,只有在您解决第一部分后才会显示第二部分。第二部分始终与第一部分相关,并将使用相同的输入数据。但是,您可能经常需要重新考虑解决谜题前半部分的方法,以便考虑后半部分。

    展开下面折叠的块以查看 2019 年第 1 天代码出现难题的第二部分:

    2019 年第 1 天,第 2 部分显示隐藏

    您将在下一部分看到第二部分的可能解决方案。但是,请先尝试自己解决难题。如果您需要开始的提示,请展开下面的框:

    2019 年第 1 天的提示,第 2 部分显示隐藏

    你怎么做的?你的火箭准备好发射了吗?

    第 2 部分:解决方案

    本节展示了如何解决第二部分,继续使用上面看到的模板:

    2019 年第 1 天的解决方案,第 2 部分显示隐藏

    恭喜!您现在已经解决了整个 Advent of Code 难题。您准备好迎接更具挑战性的挑战了吗?

    代码实践:2020 年第 5 天

    您将尝试解决的第二个难题是2020 年第 5 天的难题,称为Binary Boarding。这个谜题比前一个更具挑战性,但最终的解决方案不需要很多代码。首先查看第一部分的拼图说明。

    第 1 部分:拼图说明

    2020 年,您正在努力前往您当之无愧的度假胜地。在第 5 天,当麻烦接踵而至时,您将要登机:

    你登上飞机却发现一个新问题:你丢了登机牌!你不确定哪个座位是你的,所有的空乘人员都忙着处理突然通过护照检查的人潮。

    您编写了一个快速程序,使用手机的摄像头扫描附近的所有登机牌(您的拼图输入);也许你可以通过淘汰的过程找到你的座位。

    这家航空公司使用二元空间分区来安排座位,而不是区域或组。一个座位可能被指定为FBFBBFFRLR,其中的F意思是“前”,B意思是“后”,L意思是“左”,R意思是“右”。

    前 7 个字符将是F或B; 这些精确指定的一个128行上的平面(编号0通过127)。每个字母都会告诉您给定的座位位于区域的哪一半。

    从整个行列表开始;第一个字母表示座位是在前面(0通过63)还是在后面(64通过127)。下一个字母表示座位位于该区域的哪一半,依此类推,直到您只剩下一排。

    例如,仅考虑 的前七个字符FBFBBFFRLR:

    • 首先考虑整个范围,行0到127.
    • F意味着采取下半部分,保持行0通过63。
    • B意味着采取上半部分,保持行32通过63。
    • F意味着采取下半部分,保持行32通过47。
    • B意味着采取上半部分,保持行40通过47。
    • B保持行44通过47。
    • F保持行44通过45。
    • finalF保留两者中较低的,row44

    最后三个字符将是L或R; 这些精确指定的一个8列的在飞机上的座位(编号0通过7)。再次进行与上述相同的过程,这次只需要三个步骤。L表示保留下半部分,同时R表示保留上半部分

    例如,仅考虑 的最后 3 个字符FBFBBFFRLR:

    • 首先考虑整个范围,列0到7.
    • R意味着采取上半部分,保持列4通过7。
    • L意味着采取下半部分,保持列4通过5。
    • finalR保留两者中的较高者,column5

    因此,解码FBFBBFFRLR显示它是row 44, column5的座位。

    每个座位也有一个唯一的座位 ID:将行乘以 8,然后添加列。在此示例中,座位具有 ID 44 * 8 + 5 = 357

    以下是其他一些登机牌:

    • BFFFBBFRRR:行70,列7,座位ID 567。
    • FFFBBBFRRR:行14,列7,座位ID 119。
    • BBFFBBFRLL:行102,列4,座位ID 820。

    作为健全性检查,请查看您的登机牌清单。登机牌上的最高座位 ID 是多少?

    这个谜题说明中有很多信息!但是,大部分内容都涉及二进制空间分区如何为该特定航空公司工作。

    现在,尝试自己解决难题!请记住,如果您从正确的角度考虑,从登机牌规范到座位 ID 的转换并不像最初看起来那么复杂。如果您发现自己在该部分遇到困难,请展开下面的框以查看有关如何开始的提示。

    2020 年第 5 天的提示,第 1 部分显示隐藏

    完成解决方案后,请查看下一部分以了解有关该难题的讨论。

    第 1 部分:解决方案

    既然您已经自己试过了,您可以继续展开以下块以查看解决难题的一种方法:

    2020 年第 5 天的解决方案,第 1 部分显示隐藏

    是时候进入拼图的第二部分了。你能登机吗?

    第 2 部分:拼图说明

    准备好拼图的第二部分后,展开以下部分:

    2020 年第 5 天,第 2 部分显示隐藏

    花点时间研究第二部分的解决方案。

    第 2 部分:解决方案

    当您准备好将您的解决方案与另一个解决方案进行比较时,请打开下面的框:

    2020 年第 5 天的解决方案,第 2 部分显示隐藏

    恭喜!到目前为止,您已经解决了至少两个 Advent of Code 难题。幸运的是,还有数百个等着你!

    点击关注,第一时间了解华为云新鲜技术~

    展开全文
  • 解决了什么问题 它如何解决 相应的解决工具 协调和服务发现 (Coordination &Service Discovery ) 是什么 解决了什么问题 它如何解决 备注: 相应的解决工具 远程过程调用(RPC) 是什么 解决了什么...

    原文发表于kubernetes中文社区,为作者原创翻译 ,原文地址

    更多kubernetes文章,请多关注kubernetes中文社区

    云原生景观系列

    1.  叮,你收到一份云原生景观简介

    2. 云原生景观:供应层(Provisioning)解决了什么问题?如何解决的?

    3. 云原生景观:运行时层解决了什么问题?如何解决的?

    4. 云原生景观:编排和管理层解决了什么问题?如何解决的?

    5. 云原生景观:应用程序定义和开发层解决了什么问题?如何解决的?

    6. 云原生景观:可观察性和分析解决了什么问题?如何解决的

    目录

    编排和调度( Orchestration & scheduling )

    是什么

    解决了什么问题

    它如何解决

    相应的解决工具

    协调和服务发现 (Coordination &Service Discovery )

    是什么

    解决了什么问题

    它如何解决

    备注:

    相应的解决工具

    远程过程调用(RPC)

    是什么

    解决了什么问题

    它如何解决

    相应的解决工具

    服务代理 ( Service proxy)

    是什么

    解决了什么问题

    它如何解决

    相应的解决工具

    API网关

    是什么

    解决了什么问题

    它如何解决

    相应的解决工具

    服务网格

    是什么

    解决了什么问题

    它如何解决

    相应的解决工具

    结论


    编排和管理层是Cloud Native Computing Foundation的Cloud Native景观的第三层。

    在之前的文章《叮,你收到一份来自CNCF的云原生景观简介》中,我们对CNCF云原生生态系统做了概述。在《云原生景观:供应层(Provisioning)解决了什么问题?如何解决的?》中,我们探讨了供应层,该层主要致力于构建Cloud Native平台和应用程序的基础。

    《云原生景观:运行时层解决了什么问题?如何解决的?》里,我们着重介绍了运行时层,涵盖了容器在云原生环境中运行所需的所有内容,包括容器运行时,容器存储工具,容器网络。

    一旦按照安全性标准自动搭建了基础结构(供应层),并设置了应用程序需要运行的工具(运行时层),工程师就需要知道如何编排和管理其应用程序。

    因此现在,我们必须弄清楚如何将所有应用程序组件作为一个整体来组织和管理。组件还要能够彼此标识才能进行沟通和协调,以实现一个共同的目标。

    查看云原生景观图时,你会注意到一些区别:

    • 大盒子中的项目是CNCF托管的开源项目。有些仍处于孵化阶段(浅蓝色/紫色框),而另一些则是已毕业的项目(深蓝色框)。
    • 白色小盒子中的项目是开源项目。

    • 灰色的盒子是专有产品。

    请注意,即使在撰写本文时,我们也看到有新项目成为CNCF的一部分,因此始终参考实际情况-事情发展很快!

    编排和调度( Orchestration & scheduling )

    是什么

    编排和调度是指在集群中运行和管理容器,这是一种新颖的打包和推送应用程序的方式。

    容器编排器在某种程度上类似于笔记本电脑上的操作系统(OS),它可以管理所有应用程序(例如Microsoft 360,Slack,Zoom等)。操作系统执行你要使用的应用程序,并计划哪个应用程序何时使用电脑的CPU和其他硬件资源。

    虽然在一台机器上运行所有功能都很棒,但是当今大多数现代应用程序都是分布式的,并且需要能够管理在几十个甚至几百个计算机上运行的所有组件。简而言之,你需要一个“集群操作系统”。这就是编排工具的用武之地。

    在大多数情况下,Kubernetes也是容器协调器。容器和Kubernetes都是云原生架构的核心,这就是为什么我们如此了解它们的原因。

    解决了什么问题

    在云原生架构中,应用程序被分解为多个小组件或服务,每个组件或服务都放置在一个容器中。你可能听说过它们被称为微服务。现在,你不再拥有一个大型应用程序,而是拥有多个小型服务,每个服务都需要资源,监视和问题修复。虽然为单个服务手动执行这些操作是可行的,但是当你拥有数百个容器时,你将需要自动化的流程。

    它如何解决

    容器协调器使容器管理自动化。Kubernetes是事实上的容器编排器。

    Kubernetes做一些所谓的理想状态和解。工程师在文件中指定所需状态,并与实际状态进行连续比较。如果期望状态和实际状态不匹配,Kubernetes会通过创建或销毁对象来协调它们。

    相应的解决工具

    Kubernetes与其他容器协调器(例如Docker Swarm和Mesos)一起位于编排和调度部分。它的基本目的是允许你将多个不同的计算机作为一个资源池进行管理。最重要的是,它允许你以声明性的方式管理它们,即,不是告诉Kubernetes如何做某事,而是提供了你要完成的工作的定义。这使你可以在一个或多个YAML文件中维护所需的状态,并将其应用于任何Kubernetes集群。然后,协调器本身会创建缺失的内容或删除不应该存在的任何内容。

    术语热门项目/产品
    集群 调度器 编排Kubernetes Docker Swarm Mesos

    协调和服务发现 (Coordination &Service Discovery )

    是什么

    如我们所见,现代应用程序由多个单独的服务组成,这些服务需要进行协作才能为最终用户提供价值。为了进行协作,他们需要通过网络进行通信。为了进行通信,他们必须首先相互定位。服务发现是弄清楚该如何做的过程。

    解决了什么问题

    云原生体系结构是动态的,可变的,这意味着它们在不断变化。当一个容器在一个节点上崩溃时,一个新的容器会在另一个节点上替换它。或者,当应用扩展时,副本将散布在整个网络中。没有一个地方可以提供特定服务。一切的位置在不断变化。服务发现工具跟踪网络中的服务,以便服务可以在需要时找到彼此。

    它如何解决

    服务发现工具通过提供注册和发现中心来查找和标识单个服务来解决此问题。该类别中基本上有两种工具:

    (1)服务发现引擎是类似于数据库的工具,用于存储存在哪些服务以及如何定位它们的信息。

    (2)名称解析工具(例如, Core DNS )接收服务位置请求并返回网络地址信息。

    备注:

    在Kubernetes中,为了使Pod可达,引入了一个被称为“ service”的工作负载 。service为动态更改的Pod组提供了一个稳定的地址。

    相应的解决工具

    随着分布式系统变得越来越普遍,传统的DNS流程和负载均衡器通常无法跟上不断变化的端点信息。为了弥补这些缺点,创建了服务发现工具来处理各个应用程序实例信息,以快速地对其自身进行注册和注销。

    CoreDNS和etcd是CNCF项目,内置在Kubernetes中。

    术语热门项目/产品

    域名解析(DNS)

    服务发现(Service Discovery)

    CoreDNS

    etcd

    Zookeeper

    Eureka

    远程过程调用(RPC)

    是什么

    远程过程调用(RPC)是一种使应用程序能够相互通信的技术。

    解决了什么问题

    现代应用程序由众多单独的服务组成,这些服务必须进行通信才能进行协作。RPC是处理应用程序之间通信的一种选择。

    RPC要解决的两个问题:

    1. 解决分布式系统中,服务之间的调用问题。

    1. 远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。

    它如何解决

    RPC提供了解决服务之间通信的紧密耦合方式。它的通信高效,并且许多语言支持RPC接口实现。

    相应的解决工具

    gRPC是一种特别流行的RPC实施,已被CNCF采用。

    术语热门项目/产品
    gRPCgRPC

    服务代理 ( Service proxy)

    是什么

    代理的唯一目的是对服务通信施加更多控制,它不会对通信本身添加任何内容。

    服务代理是一种工具,用于拦截进出给定服务的流量,对其应用一些逻辑,然后将该流量转发到另一个服务。它本质上充当“中间人”,收集有关网络流量的信息/或对其应用规则。

    解决了什么问题

    应用程序应以受控方式发送和接收网络流量。为了跟踪流量并可能对其进行转换或重定向,我们需要收集数据。传统上,启用数据收集和网络流量管理的代码嵌入在每个应用程序中。

    服务代理使我们能够“外部化”此功能。它不再需要存在于应用程序中。而是将其嵌入平台层(你的应用程序在其中运行)。这是非常强大的功能,因为它使开发人员可以完全专注于编写应用程序逻辑,而处理流量的通用任务由平台团队管理。通过单个公共位置集中管理和分发全局所需的服务功能(例如,路由或TLS终止),服务之间的通信更加可靠,安全和高效。

    它如何解决

    代理充当用户和服务之间的"看门人"。通过这种独特的定位,代理可以洞悉正在发生的通信类型,他们可以确定将特定请求发送到哪里,甚至完全拒绝该请求。

    代理收集关键数据,管理路由(在服务之间平均分配流量或在某些服务发生故障时重新路由),加密连接信息和缓存数据(减少资源消耗)。

    相应的解决工具

    服务代理的工作原理是拦截服务之间的流量,对它们执行一些逻辑,然后潜在地允许流量继续前进。通过将一组集中控制的功能放入此代理,他们可以收集有关服务间通信的详细指标,防止服务过载,并将其他通用标准应用于服务。

    服务代理是服务网格等其他工具的基础,因为它们提供了对所有网络流量实施更高级别策略的方法。

    请注意,CNCF将负载均衡器和 ingress 提供程序包括在此类别中。Envoy,Contour和BFE都是CNCF项目。

    术语热门项目/产品

    服务代理

    入口

    Envoy

    Contour

    NGINX

    API网关

    是什么

    人们通常通过诸如网页或应用程序之类的GUI(图形用户界面)与计算机程序进行交互,而计算机则通过API(应用程序接口)进行交互。但是,不应将API与API网关混淆。

    API网关允许组织将关键功能(例如授权或限制应用程序之间的请求数量)放置到集中管理的位置。它还用作API使用者的通用接口。

    通过API网关,组织可以集中控制(限制或启用)应用程序之间的交互并跟踪它们,从而实现诸如退款,身份验证之类的功能,并防止服务被过度使用(也称为速率限制)。

    解决了什么问题

    尽管大多数容器和核心应用程序都具有API,但API网关不仅仅是API。API网关简化了组织如何管理规则并将规则应用于所有交互。

    API网关允许开发人员编写和维护较少的自定义代码。他们还使团队能够查看和控制用户与应用程序本身之间的交互。

    它如何解决

    API网关位于用户和应用程序之间。它充当中介,将来自用户的消息(请求)转发给适当的服务。但是在交出请求之前,它会评估是否允许用户执行他们正在尝试做的事情,并记录有关发出请求的用户信息以及发出的请求数量的详细信息。

    简而言之,API网关为用户提供了应用程序的单入口点。它还使你可以将原本在应用程序中实现的任务移交给网关,从而节省了开发人员的时间和金钱。

    相应的解决工具

    API网关的工作原理是拦截对后端服务的调用,执行某种“增值活动“,例如验证授权,收集指标或转换请求,然后执行其认为适当的任何操作。

    API网关是一组下游应用程序的通用入口点,同时提供了一个团队可以在其中注入业务逻辑以处理授权,速率限制和退款的地方。

    术语热门项目/产品/产品
    API网关

    Kong

    Mulesoft

    Ambassador

    服务网格

    是什么

    “继Kubernetes之后,服务网格技术已成为云原生堆栈中最关键的组件。”

    服务网格管理服务之间的流量(即通信)。它们使平台团队能够在集群内运行的所有服务之间统一添加可靠性,可观察性和安全性功能,而无需更改任何代码。

    解决了什么问题

    在云原生世界中, 随着服务数量的增加,我们必须处理它们之间的交互。除了服务之间的通信外,我们还必须处理整个系统运行状况的监视,容错,日志记录和遥测功能,处理多点故障等等。

    在服务网格之前,必须将该功能编码到每个单独的应用程序中。

    有了Service Mesh,我们不必使用任何第三方库/组件,就可以在每个微服务中提供与网络相关的通用功能,例如配置,路由,遥测,记录,断路等。

    它如何解决

    服务网格在平台层上的所有服务之间均匀地增加了可靠性,可观察性和安全性功能,而无需触及应用程序代码。它们与任何编程语言兼容,使开发团队可以专注于编写业务逻辑。

    相应的解决工具

    服务网格通过服务代理将集群上运行的所有服务绑定在一起,从而形成服务网格。这些通过服务网格控制平面进行管理和控制。服务网格允许平台所有者在不要求开发人员编写自定义逻辑的情况下执行常见操作或在应用程序上收集数据。

    服务网格可以定义为处理微服务架构中服务间通信的专用基础结构层 ,它的功能在于无需修改应用程序即可提供关键系统功能的能力。

    服务网格提供了许多有用的功能,包括显示详细指标,加密所有流量,限制由什么服务授权的操作,提供插件的功能等等。有关更多详细信息,请查看服务网格接口规范。

    术语热门项目/产品

    服务网格

    边车(Sidecar)

    数据平面

    控制平面

    Linkerd

    Consul

    Istio

    结论

    如我们所见,该层中的工具将一个个独立的容器化服务作为一个组进行管理。编排和调度工具类似某种集群操作系统,用于管理整个集群中的容器化应用程序。协调和服务发现,服务代理和服务网格可确保服务可以彼此找到并进行有效通信,以便作为一个内聚的应用程序进行协作。API网关是一个附加层,可提供对服务通信的更多控制,尤其是在外部应用程序之间。

    译文链接:The Cloud Native Landscape: The Orchestration and Management Layer – The New Stack

    展开全文
  • 消息队列常见问题解决方案 说明:此文是笔者对中华石衫老师对消息队列讲解的一篇总结包括笔者自己的一些理解 一、为什么使用消息队列? 消息队列使用的场景和中间件有很多,但解决的核心问题主要是:异步、解耦...
  • 作者:telamitelami.cn/2019/springboot-resolve-cors/前后端分离大势所趋,跨域问题更是老生常谈,随便用标题去google或百度一下,能搜出一大片...
  • 第一章 对象的概念 计算机革命起源机器。编程语言就像是那台机器。...从某种程度上来说,问题的复杂度直接取决于抽象的类型和质量。这里的“类型”意思是:抽象的内容是什么?汇编语言是对底层机器的轻微抽象。接
  • 我们都知道,SpringCloud是微服务的一站式解决方案,是众多组件的集合,而因为SpringCloud中几乎所有的组件使用的都是Netflix公司的产品,其中大部分已经进入了停止更新或者维护阶段。我们需要一些别的组件来代替...
  • “胶水语言”一词本身...一直以来有很多人认为“Python是唯一的胶水语言”,甚至以此来吹捧,这个说法不对。 并不是只有Python是胶水语言,还有Lua、Julia、Perl、Erlang、Shell,以及各种Script结尾的(VBscript、Ap
  • 解决了什么问题 它如何解决 相应的解决工具 监视( Monitoring ) 是什么 解决了什么问题 它如何解决 相应的解决工具 跟踪( Tracing ) 是什么 解决了什么问题 它如何解决 相应的解决工具 混沌工程( Chaos...
  • 作者:望宸、木环、溪洋 等审核&校对:不瞋、宏良、张磊、志敏编辑&排版:酒圆容器本质是一项隔离技术,很好的解决了他的前任 - 虚拟化未解决问题:运行环境启动速度慢、资源利...
  • 只要可能,购买而非开发:要降低不断上涨的软件开发成本和风险,最有效的方法就是,购买现成的软件,而不是自己从头开发。 技术优先于工具:一个没规矩的木匠使用了强大的工具,会变成一个危险的没规矩的木匠。一个...
  • 文章目录关于App抓包你需要知道的这些事前言1 抓包工具的选择2 常见问题解决2.1 App正常运行,但是抓包工具中没有对应的请求记录2.1.1 UDP协议进行网络通信2.1.2 无代理模式2.2 App正常运行,但是抓包工具中对应的...
  • 原标题:Python是唯一被称为“胶水语言”的编程语言?事实并非如此!“胶水语言”一词本身没有褒贬性。就算有,在编程界里,那也是多功能性的一种表述。胶水与库数量无关。胶水语言是用来写胶水代码。胶水代码用于...
  • 为了快速定位并解决性能问题,这里选择5个关键性的数据指标,它包含了大多数人在使用Redis上会经常碰到的性能问题。 内存使用率used_memory 上图中used_memory 字段数据表示的是:由Redis分配器分配的内存总量,以...
  • CSS常见布局解决方案说起css布局,那么一定得聊聊盒模型,清除浮动,position,display什么的,但本篇本不是讲这些基础知识的,而是给出各种布局的解决方案。水平居中布局首先我们来看看水平居中1.margin + 定宽Demo...
  • 只不过现在一脚踢的角色从单一工程师拓展至整套解决方案的团队之中,硬件自研、算法自研,就连数据也是自己采集并处理。华为的ADS高阶自动驾驶全栈解决方案魅力就在于“不求人” 华为ADS自动驾驶全栈解决方案 就硬件...
  • 这很容易从主要论文提供的图中看到: 将图像分成小块 我们自己也遇到过模型不能检测到相对较小的物体的问题。任务是检测足球运动员和比赛场上的足球。游戏的分辨率是2K,所以我们有很多细节。但我们用来检测玩家的...
  • 跨平台新明星Flutter推出后,我们团队也尝试引入 Flutter ,做为iOS开发,马上感受到,Flutter 虽然强大,但不能像RN一样动态化是阻碍我们使用她的唯一障碍了。看Google团队对动态化的计划,短期内应该不会上线,...
  • 刀剑乱舞online常见问题解决方法。刀剑乱舞游戏一出来,很多人都在找常见问题解决方法。那下文就让小编跟大家讲刀剑乱舞online常见问题解决办法。伙伴们一定要来看哦!刀剑乱舞online新手指南刀剑乱舞online...
  • 关于oracle中clob字段查询慢的问题解决方法最近在用oracle的过程中用到了对blob字段模糊查询的问题,对oracle来说,我并不是高手,找了很多的资料终于能够查出来了。blob字段直接用 select * from table_name ...
  • 软件安装:装机软件必备包SQL是Structured Query Language...SQL功能强大、简单易学、使用方便,已经成为了数据库操作的基础,并且现在几乎所有的数据库均支持SQL。本文主要给大家介绍了关于MySQL中唯一性约束与NUL...
  • 程序员当然也希望python能够运算得更快,希望python可以更强大。 首先,python相比其他语言具体有多慢,这个不同场景和测试用例,结果肯定是不一样的。这个网址给出了不同语言在各种case下的性能对比,这一页是...
  • 更不用提怎么解决 ● 设计细节:如果大家仔细看那些只是套用主题的桌面环境,就会发现外面看着还可以,但是很多按钮的颜色、留白以及控件的对齐都是有问题的,甚至是粗糙的,为什么?这是由GTK+的主题设计导致的,...
  • 我们可以使用分布式锁加上自旋解决这个问题,本文给出一段示例代码,具体原理和代码实现请参看我之前的文章:流程图+源码深入分析:缓存穿透和击穿问题出现原理以及可落地解决方案 /** * 业务回调 * * @author 微信...
  • 由于Java语言具有平台无关、可移植性好等优点,并且提供了强大的类库,所以Java语言可以辅助我们解决上述问题。Java语言本身采用双字节字符编码,采用大汉字字符集,这就为解决国际化问题提供了很多方便。从设计角度...
  • 通俗来说,递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解。它有如下特点: 一个问题的解可以分解为几个子问题的解 这个问题与分解之后的子问题,除了数据规模...
  • MyBatis-Plus(简称MP)是一个MyBatis的增强... 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 支持 Lambda 形式
  • 原来这才是 Socket

    千次阅读 2021-12-15 09:05:39
    关于对 Socket 的认识,大致分为下面几个主题,Socket 是什么,Socket 是如何创建的,Socket 是如何连接并收发数据的,Socket 套接字的删除等。 Socket 是什么以及创建过程 ...通常某个协议的设计都是为了解决某些问题

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 160,785
精华内容 64,314
关键字:

强大自己是解决问题的唯一