<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>leek 自留地</title>
  
  
  <link href="https://imlike.cc/atom.xml" rel="self"/>
  
  <link href="https://imlike.cc/"/>
  <updated>2025-09-07T07:48:54.163Z</updated>
  <id>https://imlike.cc/</id>
  
  <author>
    <name>leek</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>史诗级调试livy 传参导致 spark jar 提交 yarn显示 Exit code: 13</title>
    <link href="https://imlike.cc/59382937.html"/>
    <id>https://imlike.cc/59382937.html</id>
    <published>2025-09-07T07:40:49.000Z</published>
    <updated>2025-09-07T07:48:54.163Z</updated>
    
    <content type="html"><![CDATA[<p>目前提交批处理任务都是通过 livy提交通过设置参数和 jar来执行,seesion 任务提交没问题,但是遇到提交 batch 任务一直出现Exit code: 13 问了一圈包括 ai都说是权限问题 验证很多遍,最后通过缩减参数最后发现是多了个参数</p><p>这个是  livy batch  提交的批处理任务现在执行失败,我通过 session 提交也可以执行成功</p><p><code>&#123;     &quot;args&quot;: [         &quot; &#123; \&quot;0\&quot;:&#123; \&quot;functionInvocationValue\&quot;:&#123; \&quot;functionName\&quot;:\&quot;Coverage.export\&quot;,\&quot;arguments\&quot;:&#123; \&quot;coverage\&quot;:&#123; \&quot;functionInvocationValue\&quot;:&#123; \&quot;functionName\&quot;:\&quot;Coverage.addStyles\&quot;,\&quot;arguments\&quot;:&#123; \&quot;coverage\&quot;:&#123; \&quot;functionInvocationValue\&quot;:&#123; \&quot;functionName\&quot;:\&quot;Coverage.aspect\&quot;,\&quot;arguments\&quot;:&#123; \&quot;coverage\&quot;:&#123; \&quot;functionInvocationValue\&quot;:&#123; \&quot;functionName\&quot;:\&quot;Service.getCoverage\&quot;,\&quot;arguments\&quot;:&#123; \&quot;coverageID\&quot;:&#123; \&quot;constantValue\&quot;:\&quot;ASTGTM_N28E056\&quot; &#125; ,\&quot;baseUrl\&quot;:&#123; \&quot;constantValue\&quot;:\&quot;http://localhost\&quot; &#125; ,\&quot;productID\&quot;:&#123; \&quot;constantValue\&quot;:\&quot;ASTER_GDEM_DEM30\&quot; &#125;  &#125;  &#125;  &#125; ,\&quot;radius\&quot;:&#123; \&quot;constantValue\&quot;:1 &#125;  &#125;  &#125;  &#125; ,\&quot;min\&quot;:&#123; \&quot;constantValue\&quot;:-1 &#125; ,\&quot;max\&quot;:&#123; \&quot;constantValue\&quot;:1 &#125; ,\&quot;palette\&quot;:&#123; \&quot;constantValue\&quot;:[\&quot;#808080\&quot;,\&quot;#949494\&quot;,\&quot;#a9a9a9\&quot;,\&quot;#bdbebd\&quot;,\&quot;#d3d3d3\&quot;,\&quot;#e9e9e9\&quot;] &#125;  &#125;  &#125;  &#125;  &#125;  &#125;  &#125; ,\&quot;isBatch\&quot;:1 &#125; &quot;,         &quot;f950cff2-07c8-461a-9c24-9162d59e2666_1757072928459_0&quot;,         &quot;f950cff2-07c8-461a-9c24-9162d59e2666&quot;,         &quot;EPSG:4326&quot;,         &quot;1000&quot;,         &quot;result&quot;,         &quot;file_2025_09_05_19_48_47&quot;,         &quot;tif&quot;     ],     &quot;numExecutors&quot;: 3,     &quot;driverMemory&quot;: &quot;2g&quot;,     &quot;executorMemory&quot;: &quot;2g&quot;,     &quot;file&quot;: &quot;local:computation_ogc.jar&quot;,     &quot;driverCores&quot;: 1,     &quot;executorCores&quot;: 4,     &quot;className&quot;: &quot;TriggerBatch&quot;,     &quot;conf&quot;: &#123;         &quot;spark.kryoserializer.buffer.max&quot;: &quot;5g&quot;,         &quot;spark.driver.maxResultSize&quot;: &quot;2g&quot;,         &quot;spark.executor.extraClassPath&quot;: &quot;local://jars/*&quot;,         &quot;spark.driver.extraClassPath&quot;: &quot;local:/jars/*&quot;,         &quot;spark.serializer&quot;: &quot;org.apache.spark.serializer.KryoSerializer&quot;,         &quot;spark.executor.memoryOverhead&quot;: &quot;2g&quot;     &#125; </code></p><p>显示</p><p>Stack trace: ExitCodeException exitCode=13:        </p><p>at org.apache.hadoop.util.Shell.runCommand(Shell.java:582)        </p><p>at org.apache.hadoop.util.Shell.run(Shell.java:479)        </p><p>at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:773)        </p><p>at org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor.launchContainer(DefaultContainerExecutor.java:212)        at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:302)        at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:82)        at java.util.concurrent.FutureTask.run(FutureTask.java:266)        </p><p>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)        </p><p>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)        </p><p>at java.lang.Thread.run(Thread.java:750)  Container exited with a non-zero exit code 13 Failing this attempt.</p><p><img src="../pics/image-20250907154511034.png" alt="image-20250907154511034"></p><p> 我把参数手动提交可以执行成功 <code>/data/server/spark-3.0.0/bin/spark-submit  --verbose  --class TriggerBatch   --conf spark.executor.instances=2  --conf spark.executor.memory=2g  --conf spark.executor.memoryOverhead=2g  --conf spark.serializer=org.apache.spark.serializer.KryoSerializer  --conf spark.driver.memory=8g  --conf spark.yarn.tags=livy-batch-0-mqY0FpT9  --conf spark.driver.cores=2  --conf spark.yarn.submit.waitAppCompletion=false  --conf spark.executor.extraClassPath=local:/jars/*  --conf spark.executor.cores=2  --conf spark.driver.extraClassPath=local:/jars/*  local:/computation_ogc.jar  &#39;&#123;&quot;0&quot;:&#123;&quot;functionInvocationValue&quot;:&#123;&quot;functionName&quot;:&quot;Coverage.export&quot;,&quot;arguments&quot;:&#123;&quot;coverage&quot;:&#123;&quot;functionInvocationValue&quot;:&#123;&quot;functionName&quot;:&quot;Coverage.addStyles&quot;,&quot;arguments&quot;:&#123;&quot;coverage&quot;:&#123;&quot;functionInvocationValue&quot;:&#123;&quot;functionName&quot;:&quot;Coverage.aspect&quot;,&quot;arguments&quot;:&#123;&quot;coverage&quot;:&#123;&quot;functionInvocationValue&quot;:&#123;&quot;functionName&quot;:&quot;Service.getCoverage&quot;,&quot;arguments&quot;:&#123;&quot;coverageID&quot;:&#123;&quot;constantValue&quot;:&quot;ASTGTM_N28E056&quot;&#125;,&quot;baseUrl&quot;:&#123;&quot;constantValue&quot;:&quot;http://localhost&quot;&#125;,&quot;productID&quot;:&#123;&quot;constantValue&quot;:&quot;ASTER_GDEM_DEM30&quot;&#125;&#125;&#125;&#125;,&quot;radius&quot;:&#123;&quot;constantValue&quot;:1&#125;&#125;&#125;&#125;,&quot;min&quot;:&#123;&quot;constantValue&quot;:-1&#125;,&quot;max&quot;:&#123;&quot;constantValue&quot;:1&#125;,&quot;palette&quot;:&#123;&quot;constantValue&quot;:[&quot;#808080&quot;,&quot;#949494&quot;,&quot;#a9a9a9&quot;,&quot;#bdbebd&quot;,&quot;#d3d3d3&quot;,&quot;#e9e9e9&quot;]&#125;&#125;&#125;&#125;&#125;&#125;&#125;,&quot;isBatch&quot;:1&#125;&#39;</code></p><p>查看/data/server/hadoop-2.7.3/logs/yarn-oge-resourcemanager-spark-master.log 日志显示如下</p><p><code>2025-09-05 19:48:51,036 INFO SecurityLogger.org.apache.hadoop.ipc.Server: Auth successful for oge/spark-master.example.com@EXAMPLE.COM (auth:KERBEROS) 2025-09-05 19:48:51,039 INFO SecurityLogger.org.apache.hadoop.security.authorize.ServiceAuthorizationManager: Authorization successful for oge/spark-master.example.com@EXAMPLE.COM (auth:KERBEROS) for protocol=interface org.apache.hadoop.yarn.api.ApplicationClientProtocolPB 2025-09-05 19:48:53,342 INFO SecurityLogger.org.apache.hadoop.ipc.Server: Auth successful for oge/spark-master.example.com@EXAMPLE.COM (auth:KERBEROS) 2025-09-05 19:48:53,348 INFO SecurityLogger.org.apache.hadoop.security.authorize.ServiceAuthorizationManager: Authorization successful for oge/spark-master.example.com@EXAMPLE.COM (auth:KERBEROS) for protocol=interface org.apache.hadoop.yarn.api.ApplicationClientProtocolPB 2025-09-05 19:48:53,363 INFO org.apache.hadoop.yarn.server.resourcemanager.ClientRMService: Allocated new applicationId: 13 2025-09-05 19:48:57,110 WARN org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: The specific max attempts: 0 for application: 13 is invalid, because it is out of the range [1, 2]. Use the global max attempts instead. 2025-09-05 19:48:57,111 INFO org.apache.hadoop.yarn.server.resourcemanager.ClientRMService: Application with id 13 submitted by user oge 2025-09-05 19:48:57,111 INFO org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger: USER=oge      IP=192.200.34.42        OPERATION=Submit Application Request     TARGET=ClientRMService  RESULT=SUCCESS  APPID=application_1757068896457_0013 2025-09-05 19:48:57,111 INFO org.apache.hadoop.yarn.server.resourcemanager.security.DelegationTokenRenewer: application_1757068896457_0013 found existing hdfs token Kind: HDFS_DELEGATION_TOKEN, Service: 192.200.34.42:9000, Ident: (HDFS_DELEGATION_TOKEN token 719 for oge) 2025-09-05 19:48:57,123 INFO org.apache.hadoop.yarn.server.resourcemanager.security.DelegationTokenRenewer: Renewed delegation-token= [Kind: HDFS_DELEGATION_TOKEN, Service: 192.200.34.42:9000, Ident: (HDFS_DELEGATION_TOKEN token 719 for oge);exp=1757159337121; apps=[application_1757068896457_0013]], for [application_1757068896457_0013] 2025-09-05 19:48:57,123 INFO org.apache.hadoop.yarn.server.resourcemanager.security.DelegationTokenRenewer: Renew Kind: HDFS_DELEGATION_TOKEN, Service: 192.200.34.42:9000, Ident: (HDFS_DELEGATION_TOKEN token 719 for oge);exp=1757159337121; apps=[application_1757068896457_0013] in 86399998 ms, appId = [application_1757068896457_0013] 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: Storing application with id application_1757068896457_0013 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: application_1757068896457_0013 State change from NEW to NEW_SAVING 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore: Storing info for app: application_1757068896457_0013 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: application_1757068896457_0013 State change from NEW_SAVING to SUBMITTED 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: Application added - appId: application_1757068896457_0013 user: oge leaf-queue of parent: root #applications: 1 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler: Accepted application application_1757068896457_0013 from user: oge, in queue: default 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: application_1757068896457_0013 State change from SUBMITTED to ACCEPTED 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService: Registering app attempt : appattempt_1757068896457_0013_000001 2025-09-05 19:48:57,124 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000001 State change from NEW to SUBMITTED 2025-09-05 19:48:57,125 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: Application application_1757068896457_0013 from user: oge activated in queue: default 2025-09-05 19:48:57,125 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: Application added - appId: application_1757068896457_0013 user: org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue$User@22aac5cf, leaf-queue: default #user-pending-applications: 0 #user-active-applications: 1 #queue-pending-applications: 0 #queue-active-applications: 1 2025-09-05 19:48:57,125 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler: Added Application Attempt appattempt_1757068896457_0013_000001 to scheduler from user oge in queue default 2025-09-05 19:48:57,128 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000001 State change from SUBMITTED to SCHEDULED 2025-09-05 19:48:57,200 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_01_000001 Container Transitioned from NEW to ALLOCATED 2025-09-05 19:48:57,200 INFO org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger: USER=oge      OPERATION=AM Allocated Container        TARGET=SchedulerApp      RESULT=SUCCESS  APPID=application_1757068896457_0013    CONTAINERID=container_1757068896457_0013_01_000001 2025-09-05 19:48:57,201 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerNode: Assigned container container_1757068896457_0013_01_000001 of capacity &lt;memory:3072, vCores:1&gt; on host spark-slave1.example.com:34599, which has 1 containers, &lt;memory:3072, vCores:1&gt; used and &lt;memory:406528, vCores:89&gt; available after allocation 2025-09-05 19:48:57,201 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: assignedContainer application attempt=appattempt_1757068896457_0013_000001 container=Container: [ContainerId: container_1757068896457_0013_01_000001, NodeId: spark-slave1.example.com:34599, NodeHttpAddress: spark-slave1.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: null, ] queue=default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:0, vCores:0&gt;, usedCapacity=0.0, absoluteUsedCapacity=0.0, numApps=1, numContainers=0 clusterResource=&lt;memory:1228800, vCores:270&gt; type=OFF_SWITCH 2025-09-05 19:48:57,201 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: Re-sorting assigned queue: root.default stats: default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:3072, vCores:1&gt;, usedCapacity=0.0025, absoluteUsedCapacity=0.0025, numApps=1, numContainers=1 2025-09-05 19:48:57,201 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: assignedContainer queue=root usedCapacity=0.0025 absoluteUsedCapacity=0.0025 used=&lt;memory:3072, vCores:1&gt; cluster=&lt;memory:1228800, vCores:270&gt; 2025-09-05 19:48:57,202 INFO org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM: Sending NMToken for nodeId : spark-slave1.example.com:34599 for container : container_1757068896457_0013_01_000001 2025-09-05 19:48:57,203 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_01_000001 Container Transitioned from ALLOCATED to ACQUIRED 2025-09-05 19:48:57,203 INFO org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM: Clear node set for appattempt_1757068896457_0013_000001 2025-09-05 19:48:57,203 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: Storing attempt: AppId: application_1757068896457_0013 AttemptId: appattempt_1757068896457_0013_000001 MasterContainer: Container: [ContainerId: container_1757068896457_0013_01_000001, NodeId: spark-slave1.example.com:34599, NodeHttpAddress: spark-slave1.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.182:34599 &#125;, ] 2025-09-05 19:48:57,203 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000001 State change from SCHEDULED to ALLOCATED_SAVING 2025-09-05 19:48:57,203 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000001 State change from ALLOCATED_SAVING to ALLOCATED 2025-09-05 19:48:57,204 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Launching masterappattempt_1757068896457_0013_000001 2025-09-05 19:48:57,206 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Setting up container Container: [ContainerId: container_1757068896457_0013_01_000001, NodeId: spark-slave1.example.com:34599, NodeHttpAddress: spark-slave1.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.182:34599 &#125;, ] for AM appattempt_1757068896457_0013_000001 2025-09-05 19:48:57,206 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Command to launch container container_1757068896457_0013_01_000001 : &#123;&#123;JAVA_HOME&#125;&#125;/bin/java,-server,-Xmx2048m,-Djava.io.tmpdir=&#123;&#123;PWD&#125;&#125;/tmp,-Dspark.yarn.app.container.log.dir=&lt;LOG_DIR&gt;,org.apache.spark.deploy.yarn.ApplicationMaster,--class,&#39;TriggerBatch&#39;,--jar,local:/computation_ogc.jar,--arg,&#39; &#123; \&quot;0\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Coverage.export\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverage\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Coverage.addStyles\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverage\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Coverage.aspect\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverage\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Service.getCoverage\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverageID\&quot;: &#123; \&quot;constantValue\&quot;:\&quot;ASTGTM_N28E056\&quot; &#125; ,\&quot;baseUrl\&quot;: &#123; \&quot;constantValue\&quot;:\&quot;http://localhost\&quot; &#125; ,\&quot;productID\&quot;: &#123; \&quot;constantValue\&quot;:\&quot;ASTER_GDEM_DEM30\&quot; &#125;  &#125;  &#125;  &#125; ,\&quot;radius\&quot;: &#123; \&quot;constantValue\&quot;:1 &#125;  &#125;  &#125;  &#125; ,\&quot;min\&quot;: &#123; \&quot;constantValue\&quot;:-1 &#125; ,\&quot;max\&quot;: &#123; \&quot;constantValue\&quot;:1 &#125; ,\&quot;palette\&quot;: &#123; \&quot;constantValue\&quot;:[\&quot;#808080\&quot;,\&quot;#949494\&quot;,\&quot;#a9a9a9\&quot;,\&quot;#bdbebd\&quot;,\&quot;#d3d3d3\&quot;,\&quot;#e9e9e9\&quot;] &#125;  &#125;  &#125;  &#125;  &#125;  &#125;  &#125; ,\&quot;isBatch\&quot;:1 &#125; &#39;,--arg,&#39;f950cff2-07c8-461a-9c24-9162d59e2666_1757072928459_0&#39;,--arg,&#39;f950cff2-07c8-461a-9c24-9162d59e2666&#39;,--arg,&#39;EPSG:4326&#39;,--arg,&#39;1000&#39;,--arg,&#39;result&#39;,--arg,&#39;file_2025_09_05_19_48_47&#39;,--arg,&#39;tif&#39;,--properties-file,&#123;&#123;PWD&#125;&#125;/__spark_conf__/__spark_conf__.properties,--dist-cache-conf,&#123;&#123;PWD&#125;&#125;/__spark_conf__/__spark_dist_cache__.properties,1&gt;,&lt;LOG_DIR&gt;/stdout,2&gt;,&lt;LOG_DIR&gt;/stderr 2025-09-05 19:48:57,206 INFO org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager: Create AMRMToken for ApplicationAttempt: appattempt_1757068896457_0013_000001 2025-09-05 19:48:57,206 INFO org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager: Creating password for appattempt_1757068896457_0013_000001 2025-09-05 19:48:57,215 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Done launching container Container: [ContainerId: container_1757068896457_0013_01_000001, NodeId: spark-slave1.example.com:34599, NodeHttpAddress: spark-slave1.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.182:34599 &#125;, ] for AM appattempt_1757068896457_0013_000001 2025-09-05 19:48:57,215 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000001 State change from ALLOCATED to LAUNCHED 2025-09-05 19:48:58,199 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_01_000001 Container Transitioned from ACQUIRED to RUNNING 2025-09-05 19:49:02,233 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_01_000001 Container Transitioned from RUNNING to COMPLETED 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.common.fica.FiCaSchedulerApp: Completed container: container_1757068896457_0013_01_000001 in state: COMPLETED event:FINISHED 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger: USER=oge      OPERATION=AM Released Container TARGET=SchedulerApp      RESULT=SUCCESS  APPID=application_1757068896457_0013    CONTAINERID=container_1757068896457_0013_01_000001 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerNode: Released container container_1757068896457_0013_01_000001 of capacity &lt;memory:3072, vCores:1&gt; on host spark-slave1.example.com:34599, which currently has 0 containers, &lt;memory:0, vCores:0&gt; used and &lt;memory:409600, vCores:90&gt; available, release resources=true 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: default used=&lt;memory:0, vCores:0&gt; numContainers=0 user=oge user-resources=&lt;memory:0, vCores:0&gt; 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: completedContainer container=Container: [ContainerId: container_1757068896457_0013_01_000001, NodeId: spark-slave1.example.com:34599, NodeHttpAddress: spark-slave1.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.182:34599 &#125;, ] queue=default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:0, vCores:0&gt;, usedCapacity=0.0, absoluteUsedCapacity=0.0, numApps=1, numContainers=0 cluster=&lt;memory:1228800, vCores:270&gt; 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: completedContainer queue=root usedCapacity=0.0 absoluteUsedCapacity=0.0 used=&lt;memory:0, vCores:0&gt; cluster=&lt;memory:1228800, vCores:270&gt; 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: Re-sorting completed queue: root.default stats: default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:0, vCores:0&gt;, usedCapacity=0.0, absoluteUsedCapacity=0.0, numApps=1, numContainers=0 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler: Application attempt appattempt_1757068896457_0013_000001 released container container_1757068896457_0013_01_000001 on node: host: spark-slave1.example.com:34599 #containers=0 available=&lt;memory:409600, vCores:90&gt; used=&lt;memory:0, vCores:0&gt; with event: FINISHED 2025-09-05 19:49:02,234 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: Updating application attempt appattempt_1757068896457_0013_000001 with final state: FAILED, and exit status: 13 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000001 State change from LAUNCHED to FINAL_SAVING 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService: Unregistering app attempt : appattempt_1757068896457_0013_000001 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager: Application finished, removing password for appattempt_1757068896457_0013_000001 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000001 State change from FINAL_SAVING to FAILED 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: The number of failed attempts is 1. The max attempts is 2 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService: Registering app attempt : appattempt_1757068896457_0013_000002 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000002 State change from NEW to SUBMITTED 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler: Application Attempt appattempt_1757068896457_0013_000001 is done. finalState=FAILED 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.AppSchedulingInfo: Application application_1757068896457_0013 requests cleared 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: Application removed - appId: application_1757068896457_0013 user: oge queue: default #user-pending-applications: 0 #user-active-applications: 0 #queue-pending-applications: 0 #queue-active-applications: 0 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: Application application_1757068896457_0013 from user: oge activated in queue: default 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: Application added - appId: application_1757068896457_0013 user: org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue$User@5b887260, leaf-queue: default #user-pending-applications: 0 #user-active-applications: 1 #queue-pending-applications: 0 #queue-active-applications: 1 2025-09-05 19:49:02,235 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler: Added Application Attempt appattempt_1757068896457_0013_000002 to scheduler from user oge in queue default 2025-09-05 19:49:02,236 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000002 State change from SUBMITTED to SCHEDULED 2025-09-05 19:49:02,701 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_02_000001 Container Transitioned from NEW to ALLOCATED 2025-09-05 19:49:02,701 INFO org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger: USER=oge      OPERATION=AM Allocated Container        TARGET=SchedulerApp      RESULT=SUCCESS  APPID=application_1757068896457_0013    CONTAINERID=container_1757068896457_0013_02_000001 2025-09-05 19:49:02,701 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerNode: Assigned container container_1757068896457_0013_02_000001 of capacity &lt;memory:3072, vCores:1&gt; on host spark-master.example.com:45563, which has 1 containers, &lt;memory:3072, vCores:1&gt; used and &lt;memory:406528, vCores:89&gt; available after allocation 2025-09-05 19:49:02,701 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: assignedContainer application attempt=appattempt_1757068896457_0013_000002 container=Container: [ContainerId: container_1757068896457_0013_02_000001, NodeId: spark-master.example.com:45563, NodeHttpAddress: spark-master.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: null, ] queue=default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:0, vCores:0&gt;, usedCapacity=0.0, absoluteUsedCapacity=0.0, numApps=1, numContainers=0 clusterResource=&lt;memory:1228800, vCores:270&gt; type=OFF_SWITCH 2025-09-05 19:49:02,701 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: Re-sorting assigned queue: root.default stats: default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:3072, vCores:1&gt;, usedCapacity=0.0025, absoluteUsedCapacity=0.0025, numApps=1, numContainers=1 2025-09-05 19:49:02,701 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: assignedContainer queue=root usedCapacity=0.0025 absoluteUsedCapacity=0.0025 used=&lt;memory:3072, vCores:1&gt; cluster=&lt;memory:1228800, vCores:270&gt; 2025-09-05 19:49:02,701 INFO org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM: Sending NMToken for nodeId : spark-master.example.com:45563 for container : container_1757068896457_0013_02_000001 2025-09-05 19:49:02,703 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_02_000001 Container Transitioned from ALLOCATED to ACQUIRED 2025-09-05 19:49:02,703 INFO org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM: Clear node set for appattempt_1757068896457_0013_000002 2025-09-05 19:49:02,703 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: Storing attempt: AppId: application_1757068896457_0013 AttemptId: appattempt_1757068896457_0013_000002 MasterContainer: Container: [ContainerId: container_1757068896457_0013_02_000001, NodeId: spark-master.example.com:45563, NodeHttpAddress: spark-master.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.42:45563 &#125;, ] 2025-09-05 19:49:02,703 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000002 State change from SCHEDULED to ALLOCATED_SAVING 2025-09-05 19:49:02,703 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000002 State change from ALLOCATED_SAVING to ALLOCATED 2025-09-05 19:49:02,704 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Launching masterappattempt_1757068896457_0013_000002 2025-09-05 19:49:02,717 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Setting up container Container: [ContainerId: container_1757068896457_0013_02_000001, NodeId: spark-master.example.com:45563, NodeHttpAddress: spark-master.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.42:45563 &#125;, ] for AM appattempt_1757068896457_0013_000002 2025-09-05 19:49:02,717 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Command to launch container container_1757068896457_0013_02_000001 : &#123;&#123;JAVA_HOME&#125;&#125;/bin/java,-server,-Xmx2048m,-Djava.io.tmpdir=&#123;&#123;PWD&#125;&#125;/tmp,-Dspark.yarn.app.container.log.dir=&lt;LOG_DIR&gt;,org.apache.spark.deploy.yarn.ApplicationMaster,--class,&#39;TriggerBatch&#39;,--jar,local:/computation_ogc.jar,--arg,&#39; &#123; \&quot;0\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Coverage.export\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverage\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Coverage.addStyles\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverage\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Coverage.aspect\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverage\&quot;: &#123; \&quot;functionInvocationValue\&quot;: &#123; \&quot;functionName\&quot;:\&quot;Service.getCoverage\&quot;,\&quot;arguments\&quot;: &#123; \&quot;coverageID\&quot;: &#123; \&quot;constantValue\&quot;:\&quot;ASTGTM_N28E056\&quot; &#125; ,\&quot;baseUrl\&quot;: &#123; \&quot;constantValue\&quot;:\&quot;http://localhost\&quot; &#125; ,\&quot;productID\&quot;: &#123; \&quot;constantValue\&quot;:\&quot;ASTER_GDEM_DEM30\&quot; &#125;  &#125;  &#125;  &#125; ,\&quot;radius\&quot;: &#123; \&quot;constantValue\&quot;:1 &#125;  &#125;  &#125;  &#125; ,\&quot;min\&quot;: &#123; \&quot;constantValue\&quot;:-1 &#125; ,\&quot;max\&quot;: &#123; \&quot;constantValue\&quot;:1 &#125; ,\&quot;palette\&quot;: &#123; \&quot;constantValue\&quot;:[\&quot;#808080\&quot;,\&quot;#949494\&quot;,\&quot;#a9a9a9\&quot;,\&quot;#bdbebd\&quot;,\&quot;#d3d3d3\&quot;,\&quot;#e9e9e9\&quot;] &#125;  &#125;  &#125;  &#125;  &#125;  &#125;  &#125; ,\&quot;isBatch\&quot;:1 &#125; &#39;,--arg,&#39;f950cff2-07c8-461a-9c24-9162d59e2666_1757072928459_0&#39;,--arg,&#39;f950cff2-07c8-461a-9c24-9162d59e2666&#39;,--arg,&#39;EPSG:4326&#39;,--arg,&#39;1000&#39;,--arg,&#39;result&#39;,--arg,&#39;file_2025_09_05_19_48_47&#39;,--arg,&#39;tif&#39;,--properties-file,&#123;&#123;PWD&#125;&#125;/__spark_conf__/__spark_conf__.properties,--dist-cache-conf,&#123;&#123;PWD&#125;&#125;/__spark_conf__/__spark_dist_cache__.properties,1&gt;,&lt;LOG_DIR&gt;/stdout,2&gt;,&lt;LOG_DIR&gt;/stderr 2025-09-05 19:49:02,717 INFO org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager: Create AMRMToken for ApplicationAttempt: appattempt_1757068896457_0013_000002 2025-09-05 19:49:02,717 INFO org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager: Creating password for appattempt_1757068896457_0013_000002 2025-09-05 19:49:02,726 INFO org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher: Done launching container Container: [ContainerId: container_1757068896457_0013_02_000001, NodeId: spark-master.example.com:45563, NodeHttpAddress: spark-master.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.42:45563 &#125;, ] for AM appattempt_1757068896457_0013_000002 2025-09-05 19:49:02,726 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000002 State change from ALLOCATED to LAUNCHED 2025-09-05 19:49:03,701 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_02_000001 Container Transitioned from ACQUIRED to RUNNING 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainerImpl: container_1757068896457_0013_02_000001 Container Transitioned from RUNNING to COMPLETED 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.common.fica.FiCaSchedulerApp: Completed container: container_1757068896457_0013_02_000001 in state: COMPLETED event:FINISHED 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger: USER=oge      OPERATION=AM Released Container TARGET=SchedulerApp      RESULT=SUCCESS  APPID=application_1757068896457_0013    CONTAINERID=container_1757068896457_0013_02_000001 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerNode: Released container container_1757068896457_0013_02_000001 of capacity &lt;memory:3072, vCores:1&gt; on host spark-master.example.com:45563, which currently has 0 containers, &lt;memory:0, vCores:0&gt; used and &lt;memory:409600, vCores:90&gt; available, release resources=true 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: default used=&lt;memory:0, vCores:0&gt; numContainers=0 user=oge user-resources=&lt;memory:0, vCores:0&gt; 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: completedContainer container=Container: [ContainerId: container_1757068896457_0013_02_000001, NodeId: spark-master.example.com:45563, NodeHttpAddress: spark-master.example.com:8042, Resource: &lt;memory:3072, vCores:1&gt;, Priority: 0, Token: Token &#123; kind: ContainerToken, service: 192.200.34.42:45563 &#125;, ] queue=default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:0, vCores:0&gt;, usedCapacity=0.0, absoluteUsedCapacity=0.0, numApps=1, numContainers=0 cluster=&lt;memory:1228800, vCores:270&gt; 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: completedContainer queue=root usedCapacity=0.0 absoluteUsedCapacity=0.0 used=&lt;memory:0, vCores:0&gt; cluster=&lt;memory:1228800, vCores:270&gt; 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: Re-sorting completed queue: root.default stats: default: capacity=1.0, absoluteCapacity=1.0, usedResources=&lt;memory:0, vCores:0&gt;, usedCapacity=0.0, absoluteUsedCapacity=0.0, numApps=1, numContainers=0 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler: Application attempt appattempt_1757068896457_0013_000002 released container container_1757068896457_0013_02_000001 on node: host: spark-master.example.com:45563 #containers=0 available=&lt;memory:409600, vCores:90&gt; used=&lt;memory:0, vCores:0&gt; with event: FINISHED 2025-09-05 19:49:07,673 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: Updating application attempt appattempt_1757068896457_0013_000002 with final state: FAILED, and exit status: 13 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000002 State change from LAUNCHED to FINAL_SAVING 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService: Unregistering app attempt : appattempt_1757068896457_0013_000002 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager: Application finished, removing password for appattempt_1757068896457_0013_000002 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl: appattempt_1757068896457_0013_000002 State change from FINAL_SAVING to FAILED 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: The number of failed attempts is 2. The max attempts is 2 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: Updating application application_1757068896457_0013 with final state: FAILED 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: application_1757068896457_0013 State change from ACCEPTED to FINAL_SAVING 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore: Updating info for app: application_1757068896457_0013 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler: Application Attempt appattempt_1757068896457_0013_000002 is done. finalState=FAILED 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.AppSchedulingInfo: Application application_1757068896457_0013 requests cleared 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue: Application removed - appId: application_1757068896457_0013 user: oge queue: default #user-pending-applications: 0 #user-active-applications: 0 #queue-pending-applications: 0 #queue-active-applications: 0 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: Application application_1757068896457_0013 failed 2 times due to AM Container for appattempt_1757068896457_0013_000002 exited with  exitCode: 13 For more detailed output, check application tracking page:http://spark-master:8088/cluster/app/application_1757068896457_0013Then, click on links to logs of each attempt. Diagnostics: Exception from container-launch. Container id: container_1757068896457_0013_02_000001 Exit code: 13 Stack trace: ExitCodeException exitCode=13:        at org.apache.hadoop.util.Shell.runCommand(Shell.java:582)        at org.apache.hadoop.util.Shell.run(Shell.java:479)        at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:773)        at org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor.launchContainer(DefaultContainerExecutor.java:212)        at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:302)        at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:82)        at java.util.concurrent.FutureTask.run(FutureTask.java:266)        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)        at java.lang.Thread.run(Thread.java:750)  Container exited with a non-zero exit code 13 Failing this attempt. Failing the application. 2025-09-05 19:49:07,674 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: application_1757068896457_0013 State change from FINAL_SAVING to FAILED 2025-09-05 19:49:07,675 INFO org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.ParentQueue: Application removed - appId: application_1757068896457_0013 user: oge leaf-queue of parent: root #applications: 0 2025-09-05 19:49:07,675 WARN org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger: USER=oge      OPERATION=Application Finished - Failed TARGET=RMAppManager      RESULT=FAILURE  DESCRIPTION=App failed with state: FAILED       PERMISSIONS=Application application_1757068896457_0013 failed 2 times due to AM Container for appattempt_1757068896457_0013_000002 exited with  exitCode: 13 For more detailed output, check application tracking page:http://spark-master:8088/cluster/app/application_1757068896457_0013Then, click on links to logs of each attempt. Diagnostics: Exception from container-launch. Container id: container_1757068896457_0013_02_000001 Exit code: 13 Stack trace: ExitCodeException exitCode=13:        at org.apache.hadoop.util.Shell.runCommand(Shell.java:582)        at org.apache.hadoop.util.Shell.run(Shell.java:479)        at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:773)        at org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor.launchContainer(DefaultContainerExecutor.java:212)        at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:302)        at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:82)        at java.util.concurrent.FutureTask.run(FutureTask.java:266)        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)        at java.lang.Thread.run(Thread.java:750)  Container exited with a non-zero exit code 13 Failing this attempt. Failing the application.  APPID=application_1757068896457_0013 2025-09-05 19:49:07,676 INFO org.apache.hadoop.yarn.server.resourcemanager.RMAppManager$ApplicationSummary: appId=application_1757068896457_0013,name=TriggerBatch,user=oge,queue=default,state=FAILED,trackingUrl=http://spark-master:8088/cluster/app/application_1757068896457_0013,appMasterHost=N/A,startTime=1757072937110,finishTime=1757072947674,finalStatus=FAILED,memorySeconds=30734,vcoreSeconds=9,preemptedAMContainers=0,preemptedNonAMContainers=0,preemptedResources=&lt;memory:0\, vCores:0&gt;,applicationType=SPARK 2025-09-05 19:49:11,054 INFO org.apache.hadoop.ipc.Server: IPC Server handler 35 on 8032, call org.apache.hadoop.yarn.api.ApplicationClientProtocolPB.getContainerReport from 192.200.34.42:44582 Call#44 Retry#0 org.apache.hadoop.yarn.exceptions.ContainerNotFoundException: Container with id &#39;container_1757068896457_0013_02_000001&#39; doesn&#39;t exist in RM.        at org.apache.hadoop.yarn.server.resourcemanager.ClientRMService.getContainerReport(ClientRMService.java:464)        at org.apache.hadoop.yarn.api.impl.pb.service.ApplicationClientProtocolPBServiceImpl.getContainerReport(ApplicationClientProtocolPBServiceImpl.java:394)        at org.apache.hadoop.yarn.proto.ApplicationClientProtocol$ApplicationClientProtocolService$2.callBlockingMethod(ApplicationClientProtocol.java:445)        at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)        at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2049)        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2045)        at java.security.AccessController.doPrivileged(Native Method)        at javax.security.auth.Subject.doAs(Subject.java:422)        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1698)        at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2043) </code> 权限信息如下 <code>[oge@spark-master ~]$ cd /data/data/hadoop_data/  dfs/ nm-local-dir/  [oge@spark-master ~]$ cd /data/data/hadoop_data/nm-local-dir/  filecache/ nmPrivate/ usercache/  [oge@spark-master ~]$ cd /data/data/hadoop_data/nm-local-dir/usercache/  [oge@spark-master usercache]$ ll  total 0  drwxr-x--- 4 oge oge 39 Sep 5 18:45 oge  [oge@spark-master usercache]$ ll oge  total 4.0K  drwx--x--- 2 oge oge 6 Sep 5 19:30 appcache  drwx--x--- 72 oge oge 4.0K Sep 5 19:30 filecache  [oge@spark-master usercache]$ ll oge/appcache/  total 0  [oge@spark-master usercache]$ ll oge/filecache/  total 0  drwxr-xr-x 3 oge oge 24 Sep 5 18:45 10 </code></p><p>一直以为是权限问题排查了半天分别试了如下办法</p><ol><li><p>增加 yarn debug 的日志</p></li><li><p>查看application_1757068896457_0013 的本地日志没有设置的 30 分钟回收,使用 hdfs -logs  也没有</p></li><li><p>因为是 json 的问题</p></li><li><p>因为是权限的 jar包</p><p>namei /computation_ogc.jar</p><p>ls -l /computation_ogc.jar</p><p>ls -l /jars 都没问题</p></li><li><p>最后是在 ai建议下用了个空参数来试</p></li></ol><p><code>&#123;   &quot;file&quot;: &quot;local:/computation_ogc.jar&quot;,   &quot;className&quot;: &quot;TriggerBatch&quot;,   &quot;args&quot;: [&quot;test&quot;],   &quot;numExecutors&quot;: 1,   &quot;driverMemory&quot;: &quot;1g&quot;,   &quot;executorMemory&quot;: &quot;1g&quot;,   &quot;driverCores&quot;: 1,   &quot;executorCores&quot;: 1 &#125;</code></p><p>发现是”spark.kryoserializer.buffer.max”: “5g”, 导致的,由于任务没在 yarn 上怎么运行没有显示具体的错误在 resourcemanager 和 nodemanage 上都看不出来</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;目前提交批处理任务都是通过 livy提交通过设置参数和 jar来执行,seesion 任务提交没问题,但是遇到提交 batch 任务一直出现Exit code: 13 问了一圈包括 ai都说是权限问题 验证很多遍,最后通过缩减参数最后发现是多了个参数&lt;/p&gt;
&lt;p&gt;这个是 </summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>spark yarn 集群端口情况梳理</title>
    <link href="https://imlike.cc/330c7fde.html"/>
    <id>https://imlike.cc/330c7fde.html</id>
    <published>2025-09-07T07:25:48.000Z</published>
    <updated>2025-09-07T07:48:54.163Z</updated>
    
    <content type="html"><![CDATA[<p>如果 driver 设置用 4040那后续在对应节点有数据的时候需要注意什么</p><p><a href="https://claude.ai/chat/13ce7be9-dddb-4146-8dd4-a1239554d039">Spark YARN HDFS Firewall Configuration - Claude</a></p><p>在部署了Spark、YARN和HDFS的环境中，需要开放以下关键端口来确保服务正常运行：</p><h2 id="HDFS相关端口"><a href="#HDFS相关端口" class="headerlink" title="HDFS相关端口"></a>HDFS相关端口</h2><ul><li><strong>9000/8020</strong>: NameNode RPC端口（客户端连接）</li><li><strong>9870/50070</strong>: NameNode Web UI端口</li><li><strong>9864/50075</strong>: DataNode数据传输端口</li><li><strong>9866/50010</strong>: DataNode RPC端口</li><li><strong>9867/50020</strong>: DataNode IPC端口</li><li><strong>9868/50090</strong>: Secondary NameNode HTTP端口</li></ul><h2 id="YARN相关端口"><a href="#YARN相关端口" class="headerlink" title="YARN相关端口"></a>YARN相关端口</h2><ul><li><strong>8032</strong>: ResourceManager scheduler端口</li><li><strong>8030</strong>: ResourceManager端口</li><li><strong>8031</strong>: ResourceManager resource-tracker端口</li><li><strong>8033</strong>: ResourceManager admin端口</li><li><strong>8088</strong>: ResourceManager Web UI端口</li><li><strong>8040</strong>: NodeManager localizer端口</li><li><strong>8042</strong>: NodeManager Web UI端口</li><li><strong>8041</strong>: NodeManager端口</li><li><strong>10020</strong>: JobHistory Server RPC端口</li><li><strong>19888</strong>: JobHistory Server Web UI端口</li></ul><h2 id="Spark相关端口"><a href="#Spark相关端口" class="headerlink" title="Spark相关端口"></a>Spark相关端口</h2><ul><li><strong>7077</strong>: Spark Master端口</li><li><strong>8080</strong>: Spark Master Web UI端口</li><li><strong>8081</strong>: Spark Worker Web UI端口</li><li><strong>4040-4044</strong>: Spark应用程序Web UI端口范围</li><li><strong>18080</strong>: Spark History Server端口</li><li><strong>6066</strong>: Spark Master REST端口</li></ul><h2 id="动态端口范围"><a href="#动态端口范围" class="headerlink" title="动态端口范围"></a>动态端口范围</h2><ul><li><strong>1024-65535</strong>: 建议为YARN和Spark的动态端口分配开放一个范围，或者配置固定端口范围</li></ul><h2 id="安全注意事项"><a href="#安全注意事项" class="headerlink" title="安全注意事项"></a>安全注意事项</h2><ol><li><strong>网络隔离</strong>: 尽量将这些端口限制在内部网络访问，避免暴露到公网</li><li><strong>访问控制</strong>: 使用防火墙规则限制特定IP段访问</li><li><strong>认证配置</strong>: 启用Kerberos等认证机制</li><li><strong>加密传输</strong>: 配置SSL/TLS加密</li><li><strong>监控日志</strong>: 定期检查访问日志和异常连接</li></ol><p>建议根据你的具体集群配置和网络拓扑，逐步开放必要端口并进行测试验证。</p><p><a href="https://grok.com/c/e2d9b273-ea7c-4388-9138-2fade66487a2">Spark YARN HDFS 防火墙端口配置 - Grok</a></p><p>在部署了 Spark、YARN 和 HDFS 的环境中，如果防火墙需要一直开启（例如使用 firewalld 或 iptables），你需要确保集群节点之间（包括 Master 和 Slave 节点）的内部通信顺畅，同时限制外部访问。关键是根据组件的角色（如 NameNode、DataNode、ResourceManager 等）放开必要的端口。以下是主要注意事项和推荐放开的端口列表。</p><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li><strong>端口类型区分</strong>：端口包括 RPC/IPC（用于内部通信）、HTTP/HTTPS（用于 Web UI 和监控）和数据传输。集群内部节点之间必须互相放开这些端口，但外部访问（如客户端）只需放开少量端口（如 NameNode 的 8020 和 ResourceManager 的 8088）。</li><li><strong>Spark on YARN 的特殊性</strong>：Spark 运行在 YARN 上时，会依赖 YARN 的资源管理，但 Spark 的 Driver、Executor 和 Block Manager 默认使用随机端口（ephemeral ports）。这可能导致防火墙阻塞，建议在 spark-defaults.conf 中配置固定端口或端口范围（如 spark.driver.port=40002, spark.executor.port=40003, spark.port.maxRetries=10），然后在防火墙中放开该范围。</li><li><strong>HA 配置</strong>：如果启用了 HDFS 或 YARN 的高可用（HA），需额外放开 JournalNode 或 Failover Controller 的端口。</li><li><strong>安全考虑</strong>：只放开必要的端口，并使用 –zone=internal 等指定内部网络接口。定期检查日志（如 /var/log/hadoop），确保没有端口冲突。测试时，可以临时关闭防火墙验证问题。</li><li><strong>版本差异</strong>：端口可能因 Hadoop/Spark 版本而异（以下基于常见默认值，如 Hadoop 3.x 和 Spark 3.x/4.x）。建议检查你的配置文件（如 core-site.xml, yarn-site.xml, spark-defaults.conf）。</li><li><strong>命令示例</strong>：使用 firewalld 时，放开端口命令如 <code>sudo firewall-cmd --permanent --add-port=8020/tcp --zone=internal</code>，然后 <code>sudo firewall-cmd --reload</code>。对于范围：<code>--add-port=40000-40010/tcp</code>。</li><li><strong>外部 shuffle 服务</strong>：如果启用（spark.shuffle.service.enabled=true），放开 7337 端口。</li><li><strong>监控和调试</strong>：放开 Web UI 端口后，可通过浏览器访问（如 http://<resourcemanager-ip>:8088）监控。</li></ul><h3 id="需要放开的端口列表"><a href="#需要放开的端口列表" class="headerlink" title="需要放开的端口列表"></a>需要放开的端口列表</h3><p>以下表格总结了 HDFS、YARN 和 Spark 的关键端口（基于官方文档和常见配置）。端口分为内部通信（节点间必须开放）和外部可选（客户端访问）。</p><h4 id="HDFS-端口"><a href="#HDFS-端口" class="headerlink" title="HDFS 端口"></a>HDFS 端口</h4><table><thead><tr><th>组件</th><th>端口</th><th>协议</th><th>用途</th><th>类型</th></tr></thead><tbody><tr><td>NameNode</td><td>8020</td><td>TCP</td><td>客户端 IPC 通信（文件操作）</td><td>内部/外部</td></tr><tr><td>NameNode</td><td>9870</td><td>TCP</td><td>HTTP Web UI</td><td>外部</td></tr><tr><td>NameNode</td><td>9871</td><td>TCP</td><td>HTTPS Web UI</td><td>外部</td></tr><tr><td>NameNode</td><td>8022</td><td>TCP</td><td>服务 RPC（可选，HA 时用）</td><td>内部</td></tr><tr><td>DataNode</td><td>9866</td><td>TCP</td><td>数据传输</td><td>内部</td></tr><tr><td>DataNode</td><td>9864</td><td>TCP</td><td>HTTP 地址</td><td>内部/外部</td></tr><tr><td>DataNode</td><td>9865</td><td>TCP</td><td>HTTPS 地址</td><td>内部/外部</td></tr><tr><td>DataNode</td><td>9867</td><td>TCP</td><td>IPC 服务器</td><td>内部</td></tr><tr><td>Secondary NameNode</td><td>9868</td><td>TCP</td><td>HTTP 地址</td><td>内部/外部</td></tr><tr><td>Secondary NameNode</td><td>9869</td><td>TCP</td><td>HTTPS 地址</td><td>内部/外部</td></tr><tr><td>JournalNode (HA)</td><td>8485</td><td>TCP</td><td>RPC 服务器</td><td>内部</td></tr><tr><td>JournalNode (HA)</td><td>8480</td><td>TCP</td><td>HTTP 地址</td><td>内部/外部</td></tr><tr><td>JournalNode (HA)</td><td>8481</td><td>TCP</td><td>HTTPS 地址</td><td>内部/外部</td></tr></tbody></table><h4 id="YARN-端口"><a href="#YARN-端口" class="headerlink" title="YARN 端口"></a>YARN 端口</h4><table><thead><tr><th>组件</th><th>端口</th><th>协议</th><th>用途</th><th>类型</th></tr></thead><tbody><tr><td>ResourceManager</td><td>8032</td><td>TCP</td><td>客户端应用程序接口</td><td>内部/外部</td></tr><tr><td>ResourceManager</td><td>8088</td><td>TCP</td><td>Web UI</td><td>外部</td></tr><tr><td>ResourceManager</td><td>8090</td><td>TCP</td><td>HTTPS Web UI</td><td>外部</td></tr><tr><td>ResourceManager</td><td>8030</td><td>TCP</td><td>调度器接口</td><td>内部</td></tr><tr><td>ResourceManager</td><td>8031</td><td>TCP</td><td>资源跟踪器</td><td>内部</td></tr><tr><td>ResourceManager</td><td>8033</td><td>TCP</td><td>Admin 接口</td><td>内部</td></tr><tr><td>NodeManager</td><td>8040</td><td>TCP</td><td>本地化 IPC</td><td>内部</td></tr><tr><td>NodeManager</td><td>8042</td><td>TCP</td><td>Web UI</td><td>外部</td></tr><tr><td>NodeManager</td><td>8044</td><td>TCP</td><td>HTTPS Web UI</td><td>外部</td></tr><tr><td>NodeManager</td><td>8041</td><td>TCP</td><td>容器管理（默认 0，可配置）</td><td>内部</td></tr><tr><td>Timeline Service</td><td>10200</td><td>TCP</td><td>RPC 服务器</td><td>内部</td></tr><tr><td>Timeline Service</td><td>8188</td><td>TCP</td><td>Web UI</td><td>外部</td></tr></tbody></table><h4 id="Spark-端口（Spark-on-YARN-时）"><a href="#Spark-端口（Spark-on-YARN-时）" class="headerlink" title="Spark 端口（Spark on YARN 时）"></a>Spark 端口（Spark on YARN 时）</h4><table><thead><tr><th>组件</th><th>端口</th><th>协议</th><th>用途</th><th>类型</th></tr></thead><tbody><tr><td>Spark Driver/Executor</td><td>随机（或配置）</td><td>TCP</td><td>Driver/Executor 通信。建议配置 spark.driver.port、spark.executor.port 为固定（如 40002-40010）</td><td>内部</td></tr><tr><td>Block Manager</td><td>随机（或配置）</td><td>TCP</td><td>块管理。配置 spark.blockManager.port（如 40000）</td><td>内部</td></tr><tr><td>Spark UI</td><td>4040</td><td>TCP</td><td>应用仪表盘（可配置 spark.ui.port）</td><td>外部</td></tr><tr><td>External Shuffle Service</td><td>7337</td><td>TCP</td><td>外部 shuffle 服务（如果启用）</td><td>内部</td></tr><tr><td>History Server</td><td>18080</td><td>TCP</td><td>历史服务器 Web UI</td><td>外部</td></tr><tr><td>Thrift Server (如果使用)</td><td>2304</td><td>TCP</td><td>Thrift 服务器</td><td>内部/外部</td></tr></tbody></table><h4 id="Kerberos-安全环境"><a href="#Kerberos-安全环境" class="headerlink" title="Kerberos 安全环境"></a>Kerberos 安全环境</h4><ul><li><strong>Kerberos KDC</strong>: <code>88</code> (TCP/UDP)。如果集群启用了 Kerberos 认证，所有节点都需要能够访问 KDC（密钥分发中心）。</li><li><strong>Kerberos Admin Server</strong>: <code>749</code> (TCP)。用于 Kerberos 数据库管理</li></ul><p>如果你的配置不同（如自定义端口），请检查日志或配置文件调整防火墙规则。如果问题持续，建议提供更多细节如版本号或错误日志。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;如果 driver 设置用 4040那后续在对应节点有数据的时候需要注意什么&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://claude.ai/chat/13ce7be9-dddb-4146-8dd4-a1239554d039&quot;&gt;Spark YARN HDFS Firew</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>CentOS 系防火墙放开端口范围限制</title>
    <link href="https://imlike.cc/ae983347.html"/>
    <id>https://imlike.cc/ae983347.html</id>
    <published>2025-09-07T07:21:32.000Z</published>
    <updated>2025-09-07T07:48:54.162Z</updated>
    
    <content type="html"><![CDATA[<p>需要特定 ip 能被相互访问目前有两种方案</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">sudo firewall-cmd --permanent --add-rich-rule&#x3D;&#39;rule family&#x3D;&quot;ipv4&quot; source address&#x3D;&quot;192.200.34.42&quot; port port&#x3D;&quot;1000-50000&quot; protocol&#x3D;&quot;tcp&quot; accept&#39;</span><br><span class="line"></span><br><span class="line">sudo firewall-cmd --permanent --add-rich-rule&#x3D;&#39;rule family&#x3D;&quot;ipv4&quot; source address&#x3D;&quot;192.200.34.182&quot; port port&#x3D;&quot;1000-50000&quot; protocol&#x3D;&quot;tcp&quot; accept&#39;</span><br><span class="line"></span><br><span class="line">sudo firewall-cmd --permanent --add-rich-rule&#x3D;&#39;rule family&#x3D;&quot;ipv4&quot; source address&#x3D;&quot;192.200.34.51&quot; port port&#x3D;&quot;1000-50000&quot; protocol&#x3D;&quot;tcp&quot; accept&#39;</span><br><span class="line"></span><br><span class="line">sudo firewall-cmd --reload</span><br><span class="line"></span><br><span class="line">sudo firewall-cmd --list-all</span><br></pre></td></tr></table></figure><p>sudo firewall-cmd –permanent  –remove-rich-rule=’ rule family=”ipv4” source address=”203.0.113.55” port port=”22-60000” protocol=”tcp” accept’</p><p>方案 二:</p><p>sudo firewall-cmd –permanent –new-zone=cluster-internal</p><p>sudo firewall-cmd –permanent –zone=cluster-internal –set-target=ACCEPT</p><p>sudo firewall-cmd –permanent –zone=cluster-internal –add-source=203.0.113.55</p><p>sudo firewall-cmd –permanent –zone=cluster-internal –add-source=203.0.113.182</p><p>sudo firewall-cmd –permanent –zone=cluster-internal –add-source=203.0.113.51</p><p>sudo firewall-cmd –reload</p><p>sudo firewall-cmd –list-all</p><p># 列出永久规则中的端口</p><p>sudo firewall-cmd –permanent –list-ports</p><p># 列出永久规则中的服务</p><p>sudo firewall-cmd –permanent –list-services</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;需要特定 ip 能被相互访问目前有两种方案&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>非 root用户 kerbos启动Hadoop集群</title>
    <link href="https://imlike.cc/5501e4be.html"/>
    <id>https://imlike.cc/5501e4be.html</id>
    <published>2025-09-07T07:20:23.000Z</published>
    <updated>2025-09-07T07:48:54.164Z</updated>
    
    <content type="html"><![CDATA[<h1 id="非-root用户-kerbos启动Hadoop集群"><a href="#非-root用户-kerbos启动Hadoop集群" class="headerlink" title="非 root用户 kerbos启动Hadoop集群"></a>非 root用户 kerbos启动Hadoop集群</h1><p>首先停止 hadoop 集群</p><p>使用 hasdop 下 <a href="https://stop-all.sh/">stop-all.sh</a>可能存在杀不死的情况需要手动 ps -ef|grep data,我是后面发觉有些 datanode 还是 root启动</p><p>下面配置都需要同步到其他节点</p><h2 id="oge用户环境变量修改"><a href="#oge用户环境变量修改" class="headerlink" title="oge用户环境变量修改"></a><strong>oge用户环境变量修改</strong></h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"># jdk</span><br><span class="line">export JAVA_HOME&#x3D;&#x2F;data&#x2F;server&#x2F;jdk</span><br><span class="line">export JRE_HOME&#x3D;$&#123;JAVA_HOME&#125;&#x2F;jre</span><br><span class="line">export CLASSPATH&#x3D;.:$&#123;JAVA_HOME&#125;&#x2F;lib:$&#123;JRE_HOME&#125;&#x2F;lib:$CLASSPATH</span><br><span class="line">export JAVA_PATH&#x3D;$&#123;JAVA_HOME&#125;&#x2F;bin:$&#123;JRE_HOME&#125;&#x2F;bin</span><br><span class="line">export PATH&#x3D;$PATH:$&#123;JAVA_PATH&#125;</span><br><span class="line"># scala</span><br><span class="line">export SCALA_HOME&#x3D;&#x2F;data&#x2F;server&#x2F;scala&#x2F;</span><br><span class="line">export PATH&#x3D;$PATH:$SCALA_HOME&#x2F;bin</span><br><span class="line"># hadoop</span><br><span class="line">export HADOOP_HOME&#x3D;&#x2F;data&#x2F;server&#x2F;hadoop-2.7.3</span><br><span class="line">export PATH&#x3D;$PATH:$HADOOP_HOME&#x2F;bin:$HADOOP_HOME&#x2F;sbin</span><br><span class="line">export HADOOP_LOG_DIR&#x3D;&#x2F;data&#x2F;server&#x2F;hadoop-2.7.3&#x2F;logs</span><br><span class="line">export YARN_LOG_DIR&#x3D;$HADOOP_LOG_DIR</span><br><span class="line">export HADOOP_PREFIX&#x3D;&#x2F;data&#x2F;server&#x2F;hadoop-2.7.3&#x2F;</span><br><span class="line"># spark</span><br><span class="line">export SPARK_HOME&#x3D;&#x2F;data&#x2F;server&#x2F;spark-3.0.0</span><br><span class="line">export PATH&#x3D;$PATH:$SPARK_HOME&#x2F;bin</span><br><span class="line"># livy</span><br><span class="line">export LIVY_HOME&#x3D;&#x2F;data&#x2F;server&#x2F;livy</span><br><span class="line">export PATH&#x3D;$PATH:$LIVY_HOME&#x2F;bin</span><br><span class="line"></span><br><span class="line"># kerberos</span><br><span class="line">export KRB5CCNAME&#x3D;FILE:&#x2F;tmp&#x2F;krb5cc_$(id -u)</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="kerbos-认证"><a href="#kerbos-认证" class="headerlink" title="kerbos 认证"></a><strong>kerbos 认证</strong></h2><p> kerbos登录用户需要申请 oge这个用户</p><p>docker exec krb5 kadmin.local -q “addprinc -randkey oge/spark-master.example.com@EXAMPLE.COM”</p><p>docker exec krb5 kadmin.local -q “addprinc -randkey oge/spark-slave1.example.com@EXAMPLE.COM”</p><p>docker exec krb5 kadmin.local -q “addprinc -randkey oge/spark-slave2.example.com@EXAMPLE.COM”</p><p>docker exec krb5 kadmin.local -q “ktadd -k /etc/security/keytabs/oge.keytab oge/spark-master.example.com@EXAMPLE.COM oge/spark-slave1.example.com@EXAMPLE.COM oge/spark-slave2.example.com@EXAMPLE.COM”</p><h3 id="master-节点"><a href="#master-节点" class="headerlink" title="master 节点"></a><strong>master 节点</strong></h3><p>kinit -kt   kdc/keytabs/oge.keytab     oge/spark-master.example.com@EXAMPLE.COM</p><h3 id="slave1-节点"><a href="#slave1-节点" class="headerlink" title="slave1 节点"></a><strong>slave1 节点</strong></h3><p>kinit -kt   kdc/keytabs/oge.keytab     oge/spark-slave1.example.com@EXAMPLE.COM</p><h2 id="slave2-节点"><a href="#slave2-节点" class="headerlink" title="slave2 节点"></a><strong>slave2 节点</strong></h2><p>kinit -kt   kdc/keytabs/oge.keytab     oge/spark-slave2.example.com@EXAMPLE.COM</p><p>切换oge用户后需要删除 /tmp/krb5cc_0 否则会出现</p><p>kinit: Failed to store credentials: Internal credentials cache error (filename: /tmp/krb5cc_0) while getting initial credentials</p><h2 id="hadoop-spark-所有者修改-每个节点执行"><a href="#hadoop-spark-所有者修改-每个节点执行" class="headerlink" title="hadoop,spark 所有者修改(每个节点执行)"></a><strong>hadoop,spark 所有者修改(每个节点执行)</strong></h2><p>chown -R oge:oge ddd/Hadoop</p><p>chown -R oge:oge ddd/spark-3.0.0</p><h3 id="hdfs-site-xml"><a href="#hdfs-site-xml" class="headerlink" title="hdfs-site.xml"></a>hdfs-site.xml</h3><p>修改原有hdfs认证登录的内容</p><p>下面的对应的目录需要修改</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;property&gt;</span><br><span class="line">       &lt;name&gt;dfs.namenode.name.dir&lt;&#x2F;name&gt;</span><br><span class="line">       &lt;value&gt;&#x2F;data&#x2F;data&#x2F;hadoop_data&#x2F;dfs&#x2F;name&lt;&#x2F;value&gt;</span><br><span class="line">  &lt;&#x2F;property&gt;</span><br><span class="line">  &lt;property&gt;</span><br><span class="line">       &lt;name&gt;dfs.datanode.data.dir&lt;&#x2F;name&gt;</span><br><span class="line">       &lt;value&gt;&#x2F;data&#x2F;data&#x2F;hadoop_data&#x2F;dfs&#x2F;data&lt;&#x2F;value&gt;</span><br><span class="line">  &lt;&#x2F;property&gt;</span><br></pre></td></tr></table></figure><p> 修改权限 chmod 700</p><p>namenode,Namenode每个节点存储数据</p><p>chown -R oge:oge /data/data/hadoop_data</p><p> chmod -R 700 /data/data/hadoop_data/dfs/name</p><p> chmod -R 700 /data/data/hadoop_data/dfs/data</p><h3 id="hadoop-log权限和所有者-每个节点"><a href="#hadoop-log权限和所有者-每个节点" class="headerlink" title="hadoop log权限和所有者(每个节点)"></a><strong>hadoop log权限和所有者(每个节点)</strong></h3><p>chown -R oge:oge /data/server/hadoop-2.7.3/logs</p><p>chmod -R 755  /data/server/hadoop-2.7.3/logs</p><h3 id="yarn-site-xml"><a href="#yarn-site-xml" class="headerlink" title="yarn-site.xml"></a><strong>yarn-site.xml</strong></h3><p>修改原有hdfs认证登录的内容</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;property&gt;</span><br><span class="line">  &lt;name&gt;yarn.nodemanager.keytab&lt;&#x2F;name&gt;</span><br><span class="line">  &lt;value&gt;kdc&#x2F;keytabs&#x2F;hdfs.keytab&lt;&#x2F;value&gt;</span><br><span class="line">&lt;&#x2F;property&gt;</span><br></pre></td></tr></table></figure><p>修改对应路径的权限</p><h2 id="livy配置修改"><a href="#livy配置修改" class="headerlink" title="livy配置修改"></a><strong>livy配置修改</strong></h2><p>也是修改登录人用的 keytable 文件和和账号</p><h2 id="start-dfs-sh"><a href="#start-dfs-sh" class="headerlink" title="start-dfs,sh"></a><strong>start-dfs,sh</strong></h2><p>这个时候由于 hdfs启动,有用用户</p><p>hdfs put 文件显示 name node  is in safe mode 需要怎么解决</p><p>常见的配置 权限</p><h4 id="文件权限和目录所有权注意事项"><a href="#文件权限和目录所有权注意事项" class="headerlink" title="文件权限和目录所有权注意事项"></a>文件权限和目录所有权注意事项</h4><p>Hadoop 目录需归属于运行服务的用户（这里为 oge），权限过松可能导致 Kerberos 认证失败或安全漏洞。以下是标准推荐的本地文件系统和 HDFS 路径权限（基于 Hadoop 文档）。使用 chown -R oge:hadoop <path> 和 chmod 调整。如果原本是 root，所有权需递归切换。</p><table><thead><tr><th><strong>路径类型</strong></th><th><strong>示例路径</strong></th><th><strong>所有者 (owner:group)</strong></th><th><strong>权**</strong>限**</th><th><strong>说明</strong></th></tr></thead><tbody><tr><td><strong>本地文件系统 (Local FS)</strong></td><td>dfs.namenode.name.dir (e.g., /hadoop/hdfs/name)</td><td>oge:hadoop</td><td>drwx—— (700)</td><td>NameNode 元数据目录，需严格私有。</td></tr><tr><td></td><td>dfs.datanode.data.dir (e.g., /hadoop/hdfs/data)</td><td>oge:hadoop</td><td>drwx—— (700)</td><td>DataNode 数据块目录，防止未授权访问。</td></tr><tr><td></td><td>$HADOOP_LOG_DIR (e.g., /var/log/hadoop)</td><td>oge:hadoop</td><td>drwxrwxr-x (775)</td><td>日志目录，组内可写。</td></tr><tr><td></td><td>$YARN_LOG_DIR (e.g., /var/log/hadoop-yarn)</td><td>oge:hadoop</td><td>drwxrwxr-x (775)</td><td>YARN 日志。</td></tr><tr><td></td><td>yarn.nodemanager.local-dirs (e.g., /hadoop/yarn/local)</td><td>oge:hadoop</td><td>drwxr-xr-x (755)</td><td>YARN 临时文件。</td></tr><tr><td></td><td>yarn.nodemanager.log-dirs (e.g., /hadoop/yarn/log)</td><td>oge:hadoop</td><td>drwxr-xr-x (755)</td><td>YARN 应用日志。</td></tr><tr><td></td><td>container-executor 二进制文件 (e.g., /opt/hadoop/bin/container-executor)</td><td>root:hadoop</td><td>● -Sr-s–* (4750 或类似)</td><td>YARN 容器执行器，需 root 拥有，但组为 hadoop（oge 需在组内）。</td></tr><tr><td></td><td>conf/container-executor.cfg</td><td>root:hadoop</td><td>r——-* (400)</td><td>配置需 root，只读。</td></tr><tr><td><strong>HDFS</strong></td><td>/ (根目录)</td><td>oge:hadoop</td><td>drwxr-xr-x (755)</td><td>HDFS 根，oge 作为 superuser。</td></tr><tr><td></td><td>/tmp</td><td>oge:hadoop</td><td>drwxrwxrwxt (1777)</td><td>临时目录，sticky bit 防止删除他人文件。</td></tr><tr><td></td><td>/user</td><td>oge:hadoop</td><td>drwxr-xr-x (755)</td><td>用户目录父路径。</td></tr><tr><td></td><td>/user/oge</td><td>oge:hadoop</td><td>drwxr-xr-x (755)</td><td>为 oge 创建个人目录：hdfs dfs -mkdir /user/oge &amp;&amp; hdfs dfs -chown oge:hadoop /user/oge。</td></tr><tr><td></td><td>yarn.nodemanager.remote-app-log-dir (e.g., /tmp/logs)</td><td>oge:hadoop</td><td>drwxrwxrwxt (1777)</td><td>YARN 远程日志。</td></tr><tr><td></td><td>mapreduce.jobhistory.intermediate-done-dir (e.g., /mr-history/tmp)</td><td>oge:hadoop</td><td>drwxrwxrwxt (1777)</td><td>MapReduce 中间结果。</td></tr><tr><td></td><td>mapreduce.jobhistory.done-dir (e.g., /mr-history/done)</td><td>oge:hadoop</td><td>drwxr-x— (750)</td><td>完成作业历史。</td></tr></tbody></table><p>● <strong>注意</strong>： 使用 chown -R 和 chmod -R 递归应用，但测试后避免过度权限（如 777）。</p><p>○ 如果集群有多个节点，需在所有节点同步目录所有权（使用 rsync 或脚本）。</p><p>○ Spark 相关目录（如 spark.local.dir）类似 YARN，设为 oge:hadoop，权限 755。</p><p>○ Kerberos 启用后，HDFS 权限由 Kerberos principal 映射到 OS 用户（通过 hadoop.security.auth_to_local 配置规则，默认规则如 RULE:<a href="oge@REALM">2:$1@$0</a>s/.*/oge/）。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;非-root用户-kerbos启动Hadoop集群&quot;&gt;&lt;a href=&quot;#非-root用户-kerbos启动Hadoop集群&quot; class=&quot;headerlink&quot; title=&quot;非 root用户 kerbos启动Hadoop集群&quot;&gt;&lt;/a&gt;非 root用户 ke</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>的几种授权流程()</title>
    <link href="https://imlike.cc/undefined.html"/>
    <id>https://imlike.cc/undefined.html</id>
    <published>2025-07-27T05:23:15.000Z</published>
    <updated>2025-07-27T05:24:59.573Z</updated>
    
    <content type="html"><![CDATA[<p>转载来源<a href="https://www.raychase.net/8015">OAuth2.0 的几种授权流程 – 四火的唠叨</a></p><p>首先，从高维度看，OAuth 是要解决什么问题？</p><p>OAuth 要解决的是客户端在不知道和不使用用户密码的情况下，怎么样安全访问并获取用户所拥有的资源的问题。</p><p>顺带说一句，经常和 OAuth 一起谈到的 OIDC 则是解决了用户信息（profile）获取的问题。简单说，OAuth 解决了 Authorization 的问题，OIDC 解决了 Authentication 的问题。</p><p>OAuth 有几种角色：</p><ul><li>Resource Owner：资源的拥有者，比方说终端用户；</li><li>Resource Server：资源服务器，比如用户想要调用的 API；</li><li>Client：就是用户来进行鉴权和资源操作的客户端，比方说浏览器或者 CLI；</li><li>Authorization Server：就是专门授权的服务器。</li></ul><p>所以 OAuth 就是用户想通过某种机制，通过 Client 和 Authorization Server 交互来获得能够访问资源的 token。</p><p>对于 OAuth2.0 的授权流程，可以根据 <a href="https://oauth.net/2/grant-types/">grant type</a> 来做个归类。下面的图示全部都来自 Auth0 的<a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow">官方文档</a>。</p><p><strong>1. Authorization Code</strong>：用户访问 web app，web app 的后端请求 auth server，于是重定向到登录页面，用户输入登录信息，auth server 就给 web app 一个授权码，这个授权码通过 callback URL 返回，而这个参数一般放在这个 url 的参数中，比如：http://…/callback?token=TOKEN。之后 web app 就可以拿着授权码去取 token 了。这种方式不需要用户这边存放任何 secret，但是需要用户参与 consent，并且具备 web app 的后端，因为和 auth server 的交互主要都是 web app 后端完成的。</p><p><img src="https://www.raychase.net/wp-content/uploads/2025/07/image-1024x641.png" alt="img"></p><p>但是这种方法存在一些 concern，比如说，这个 code 如果在返回途中被截获怎么办，截获者就可以使用这个 code 来获取 token 了。</p><p><strong>2. PKCE</strong>：对于上述问题，有一个改进的办法，就是使用 PKCE（Proof Key for Code Exchange）来给它增强。基本原理是，客户端生成一个随机字符串 code verifier，根据一个算法 code challenge method 来生成它的 hash（challenge），获取授权码 code 的时候需要把这个 method 和 challenge 带过去；接着，code 正常返回，但之后客户端拿着 code 去获取 token 的时候，需要带上这个 code verifier，这样 auth server 就可以根据之前拿到的 method 和 challenge，以及刚得到的 code 和 code verifier，来校验用户是不是可以得到这个 token。</p><p>在这种情况下，如果 code 被劫持，那么对方拿到了 code，却没有 code verifier，也就没什么用。</p><p><img src="https://www.raychase.net/wp-content/uploads/2025/07/image-3-1024x833.png" alt="img"></p><p>这种方法是比较推荐的，对于一些 CLI 登录使用这种方法的时候，重定向 URL 可以是一个带有 code 的指向 localhost 的地址以被 CLI 捕获。</p><p><strong>3. Device Code</strong>：前面说到的 Authorization Code 这种方法还有一个变体，就是对于一些需要用户参与，但是又没有浏览器（或者自动打开浏览器）的场景下，这个重定向到浏览器来获取用户 consent 的过程，被其它方式来取代，这种变体可看做名为 Device Authorization 的流程：</p><p><img src="https://www.raychase.net/wp-content/uploads/2025/07/image-5-995x1024.png" alt="img"></p><p>可以看到，上面的浏览器重定向的过程被替换成了返回 code 和 verification url，然后用户使用 verification URL 加上这个 user code 来完成 consent 的过程，在这个过程完成之后，这个 device 才被授权。在这个过程完成之前，需要 app 不断去 poll 检查是不是 device 已经被授权了。</p><p><strong>4. Client Credential</strong>：前面说到的 Authorization Code 虽然好用，但是需要用户手动登录确认的过程，对于一些没有人参与的 M2M（machine-to-machine）系统而言，这是不现实的。因此在 client id 的基础上，再加上一个 client secret，一样可以完成 auth 的流程。这种场景其实就相当于是 client 和 resource owner 是同一个了：</p><p><img src="https://www.raychase.net/wp-content/uploads/2025/07/image-4-1024x611.png" alt="img"></p><p><strong>5. Implicit</strong>：这种其实就是上面 Authorization Code 的简化版，去掉了 code 的环节，直接发 code。这种方式在 app 只有前端的场景下（比如 SPA）使用，因为它没法进行后端和 Auth Server 的通信。但是这种方式因为安全性低，因而不推荐，因为即便是 SPA，还是可以用前面说的那种 PKCE 增强的 Authorization Code 方式来实现。</p><p><img src="https://www.raychase.net/wp-content/uploads/2025/07/image-1-1024x486.png" alt="img"></p><p>再来看这个 callback 的 URL，和前面提到的 Authorization Code 流程不一样的是，它返回的 token 放在 URL 的 fragment 里面，而不是 query 里面，比如：http://…/callback#token=TOKEN，这样做的好处是这个 TOKEN 不会在浏览器跳转的时候送到服务器，就不容易泄露。</p><p><strong>6. Password</strong>：这种方式其实就是让 client 获知用户的用户名和密码，属于风险比较大的做法，要求这个 app 是用户百分百信任的——这也就是说，它没有解决 OAuth 本身应该解决的问题，因此很少使用。</p><p><img src="https://www.raychase.net/wp-content/uploads/2025/07/image-2-1024x610.png" alt="img"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;转载来源&lt;a href=&quot;https://www.raychase.net/8015&quot;&gt;OAuth2.0 的几种授权流程 – 四火的唠叨&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;首先，从高维度看，OAuth 是要解决什么问题？&lt;/p&gt;
&lt;p&gt;OAuth 要解决的是客户端在不知道和不使用用户密</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>selfhost自部署指南</title>
    <link href="https://imlike.cc/1974fd9f.html"/>
    <id>https://imlike.cc/1974fd9f.html</id>
    <published>2025-06-21T00:37:36.000Z</published>
    <updated>2025-06-21T00:41:51.847Z</updated>
    
    <content type="html"><![CDATA[<p>参考链接</p><p><a href="https://tcoo.cc/">Tcoo.cc - 精选开源自托管项目推荐与指南</a></p><p><a href="https://selfh.st/apps/">Self-Hosted Software and Apps</a></p><p>主要是适合自己自部署的服务推荐还有两个自托管项目的网站</p><p>目前可以在Paas服务类似 fly.io和 render ,国内有aliyun,tencent云,但是完全没有限额</p><p>也可以使用esc,云主机来运行容器或者二进制文件</p><p>下面一fly.io的例子</p><h2 id="bitwarden-self-host"><a href="#bitwarden-self-host" class="headerlink" title="bitwarden/self-host"></a>bitwarden/self-host</h2><p>使用bitwarden/self-host:2024.2.0-beta 来维护密码,之前经历过 lastpass 服务很慢,而且虽然声明加密但是也出现过泄密的情况,后面都是用的chrome,但是跨平台支持不行,而且在安卓和iOS下填充支持不足,后面一直使用 microsoft authenticator 有多个原因</p><ol><li>大厂出品,而且微软在国内访问还算稳定</li><li>支持多平台</li><li>加密和支持two-factor 两步验证</li><li>对outlook账号安全相关的功能很全</li></ol><p>但是目前2025.1 月不支持chrome,没有办法又要考虑下替代的选择</p><p>用了这么多密码管理器基本需求都清楚,主要是</p><ol><li>可以自己部署(速度,安全,方便备份)</li><li>支持多客户端</li><li>支持多种登录协议方便后续拓展 两步验证,账号密码,passkey,存储 token和其他的账号信息</li></ol><p>最后基本bitwarden是最符合</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=ZGMwZDA1OGQwNTAwZjgzN2RhYzVhYTRmNjc2MTFiNjBfTGpIbVpPYWpPOUFXcTA5d1lBa0dIck54THp6eDJGa2VfVG9rZW46RTNnNGJqUFlJb0hTZW14M0h2amNhNkd5blJjXzE3NTA0NjYyMDc6MTc1MDQ2OTgwN19WNA" alt="img"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">app = <span class="string">&quot;keep-pass&quot;</span></span><br><span class="line">primary_region = <span class="string">&quot;hkg&quot;</span></span><br><span class="line">swap_size_mb = 1024</span><br><span class="line"></span><br><span class="line">[build]</span><br><span class="line">image = <span class="string">&quot;bitwarden/self-host:2024.2.0-beta&quot;</span></span><br><span class="line"></span><br><span class="line">[env]</span><br><span class="line">BW_DB_PROVIDER = <span class="string">&quot;sqlite&quot;</span></span><br><span class="line">BW_DOMAIN = <span class="string">&quot;bitwarden.fly.dev&quot;</span></span><br><span class="line">BW_ENABLE_EVENTS = <span class="string">&quot;true&quot;</span></span><br><span class="line">BW_ENABLE_SCIM = <span class="string">&quot;true&quot;</span></span><br><span class="line">BW_ENABLE_SSO = <span class="string">&quot;true&quot;</span></span><br><span class="line">BW_ICONS_PROXY_TO_CLOUD = <span class="string">&quot;true&quot;</span></span><br><span class="line">HOSTNAME = <span class="string">&quot;0.0.0.0&quot;</span></span><br><span class="line">BW_INSTALLATION_ID = <span class="string">&quot;&quot;</span></span><br><span class="line">BW_INSTALLATION_KEY = <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">[http_service]</span><br><span class="line">auto_start_machines = <span class="literal">false</span></span><br><span class="line">auto_stop_machines = <span class="literal">false</span></span><br><span class="line">internal_port = 8080</span><br><span class="line">min_machines_running = 1</span><br><span class="line">processes = [<span class="string">&quot;app&quot;</span>]</span><br><span class="line"></span><br><span class="line">[http_service.concurrency]</span><br><span class="line">hard_limit = 200</span><br><span class="line">soft_limit = 200</span><br><span class="line"><span class="built_in">type</span> = <span class="string">&quot;connections&quot;</span></span><br><span class="line"></span><br><span class="line">[[mounts]]</span><br><span class="line">destination = <span class="string">&quot;/etc/bitwarden&quot;</span></span><br><span class="line"><span class="built_in">source</span> = <span class="string">&quot;bitwarden_data&quot;</span></span><br><span class="line"></span><br><span class="line">[[services]]</span><br><span class="line">internal_port = 8080</span><br><span class="line">protocol = <span class="string">&quot;tcp&quot;</span></span><br><span class="line"></span><br><span class="line">[[services.ports]]</span><br><span class="line">handlers = [<span class="string">&quot;http&quot;</span>]</span><br><span class="line">port = 80</span><br><span class="line"></span><br><span class="line">[[services.ports]]</span><br><span class="line">handlers = [<span class="string">&quot;http&quot;</span>, <span class="string">&quot;tls&quot;</span>]</span><br><span class="line">port = 443</span><br></pre></td></tr></table></figure><h2 id="RSS搜集"><a href="#RSS搜集" class="headerlink" title="RSS搜集"></a>RSS搜集</h2><p>Freshrss</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">app = <span class="string">&quot;fresh-rss&quot;</span></span><br><span class="line">kill_signal = <span class="string">&quot;SIGINT&quot;</span></span><br><span class="line">kill_timeout = <span class="string">&quot;5s&quot;</span></span><br><span class="line">primary_region = <span class="string">&quot;hkg&quot;</span></span><br><span class="line"></span><br><span class="line">[build]</span><br><span class="line">image = <span class="string">&quot;freshrss/freshrss:1.20.1&quot;</span></span><br><span class="line"></span><br><span class="line">[env]</span><br><span class="line">ADMIN_API_PASSWORD = <span class="string">&quot;freshrss&quot;</span></span><br><span class="line">ADMIN_PASSWORD = <span class="string">&quot;freshrss&quot;</span></span><br><span class="line">CRON_MIN = <span class="string">&quot;*/20&quot;</span></span><br><span class="line"></span><br><span class="line">[experimental]</span><br><span class="line">auto_rollback = <span class="literal">true</span></span><br><span class="line"></span><br><span class="line">[[mounts]]</span><br><span class="line">destination = <span class="string">&quot;/var/www/FreshRSS/data&quot;</span></span><br><span class="line"><span class="built_in">source</span> = <span class="string">&quot;freshrss_data&quot;</span></span><br><span class="line"></span><br><span class="line">[[services]]</span><br><span class="line">internal_port = 80</span><br><span class="line">processes = [ <span class="string">&quot;app&quot;</span> ]</span><br><span class="line">protocol = <span class="string">&quot;tcp&quot;</span></span><br><span class="line"></span><br><span class="line">[services.concurrency]</span><br><span class="line">hard_limit = 25</span><br><span class="line">soft_limit = 20</span><br><span class="line"><span class="built_in">type</span> = <span class="string">&quot;connections&quot;</span></span><br><span class="line"></span><br><span class="line">[[services.ports]]</span><br><span class="line">force_https = <span class="literal">true</span></span><br><span class="line">handlers = [ <span class="string">&quot;http&quot;</span> ]</span><br><span class="line">port = 80</span><br><span class="line"></span><br><span class="line">[[services.ports]]</span><br><span class="line">handlers = [ <span class="string">&quot;tls&quot;</span>, <span class="string">&quot;http&quot;</span> ]</span><br><span class="line">port = 443</span><br><span class="line"></span><br><span class="line">[[services.tcp_checks]]</span><br><span class="line">grace_period = <span class="string">&quot;1s&quot;</span></span><br><span class="line">interval = <span class="string">&quot;15s&quot;</span></span><br><span class="line">timeout = <span class="string">&quot;2s&quot;</span></span><br><span class="line"></span><br><span class="line">[[vm]]</span><br><span class="line">cpu_kind = <span class="string">&quot;shared&quot;</span></span><br><span class="line">cpus = 1</span><br><span class="line">memory_mb = 256</span><br></pre></td></tr></table></figure><h2 id="照片同步"><a href="#照片同步" class="headerlink" title="照片同步"></a>照片同步</h2><p>todo</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;参考链接&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tcoo.cc/&quot;&gt;Tcoo.cc - 精选开源自托管项目推荐与指南&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://selfh.st/apps/&quot;&gt;Self-Hosted Software and Apps</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>并发队列实现</title>
    <link href="https://imlike.cc/bf4abafd.html"/>
    <id>https://imlike.cc/bf4abafd.html</id>
    <published>2025-06-21T00:34:01.000Z</published>
    <updated>2025-06-21T00:41:51.848Z</updated>
    
    <content type="html"><![CDATA[<p>每次提交的任务先走到内部队列,在livy执行完成后有资源的情况下将队列的任务提交到livy</p><p>同时使用future等待的特性,最大增加并发能力</p><p>使用的算法是  令牌桶来实现  还有漏桶的算法也一起介绍</p><p>异步队列</p><ol><li>特定节点的阻塞等待,因为是基于Servlet ,目前阻塞但是不用一直去轮询可以等待回调结果</li></ol><p>​      如果是reactio下的springflux 的异步的容器应该效率可以提高更快</p><ol><li>同时对于队列的任务执行依赖于 caffine或者其他的管理</li><li>对于实际执行的livy的任务时间执行情况依赖于定时轮询这个需要优化为回调或者勾着函数来拿到对应结果</li></ol><p>a服务调用B服务需要阻塞等待拿到结果有几种方式来实现</p><ol><li> <strong>同步阻塞调用 (Synchronous Blocking) 调用接口阻塞等待返回结果 调用方调用接口实时返回</strong></li><li><strong>异步**</strong>回调** <strong>(Asynchronous with</strong> <strong>Callback**</strong>)** 阻塞轮询拉到结果后执行 ,接口能有注册回调的的函数或者接口</li><li><strong>阻塞**</strong>轮询** <strong>(Blocking</strong> <strong>Polling**</strong>)** 触发后异步等待回调后触发后续的计算和执行,需要额外的状态接口</li><li><strong>基于**</strong>消息队列**<strong>的请求/响应模式 (Request/Reply over</strong> <strong>Message Queue**</strong>)**</li><li> <strong>Future/Promise 的异步阻塞 (Asynchronous Blocking with Future/Promise)</strong> 拿到Future后 执行其他任务需要结果的时候 future.get()等待结果</li></ol><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YzE0OGZhZDczNzQzODhiMjMwMDI5ZDIwOWJhOTFkYTVfZG1NNXBXeDZCWVZQNjRXNng5dWFCUUkyNXY4MlFacVpfVG9rZW46V0JiSGJLaGo3b3lRSFZ4bUN0dmNQTTAybmplXzE3NTA0NjYwMDQ6MTc1MDQ2OTYwNF9WNA" alt="img"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;每次提交的任务先走到内部队列,在livy执行完成后有资源的情况下将队列的任务提交到livy&lt;/p&gt;
&lt;p&gt;同时使用future等待的特性,最大增加并发能力&lt;/p&gt;
&lt;p&gt;使用的算法是  令牌桶来实现  还有漏桶的算法也一起介绍&lt;/p&gt;
&lt;p&gt;异步队列&lt;/p&gt;
&lt;ol&gt;
&lt;l</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>权限系统通用的设计模型(转载)</title>
    <link href="https://imlike.cc/389ed4f9.html"/>
    <id>https://imlike.cc/389ed4f9.html</id>
    <published>2025-06-21T00:29:01.000Z</published>
    <updated>2025-06-21T00:41:51.848Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>🔗 原文链接： <a href="https://yindongliang.com/posts/permission-system-models/">https://yindongliang.com/posts/perm…</a></p></blockquote><h5 id=""><a href="#" class="headerlink" title=""></a></h5><p>权限系统是一个比较通用的系统，几乎所有的后台业务都会涉及到，关于权限系统的设计经过一些最佳实践也已经被总结成各种模型，比如 ACL、RBAC、ABAC、PBAC等，下面开始详细介绍。</p><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><p>在很多权限系统的框架和服务，包括 <a href="https://casbin.org/zh-CN/">Casbin </a>、 <a href="https://www.authing.cn/">Authing </a>里面，都有下面这些名词作为基础，所以在开始之前，还要先理解这些概念。</p><h3 id="主体（Subject）"><a href="#主体（Subject）" class="headerlink" title="主体（Subject）"></a>主体（Subject）</h3><p>想要访问资源的主体，可以先理解为用户。</p><h3 id="对象（Object）"><a href="#对象（Object）" class="headerlink" title="对象（Object）"></a>对象（Object）</h3><p>用户要访问（或更改）的资源。</p><h3 id="动作（Action）"><a href="#动作（Action）" class="headerlink" title="动作（Action）"></a>动作（Action）</h3><p>用户对资源执行的操作，比如文件的读写，数据是否能访问、操作。</p><h2 id="ACL"><a href="#ACL" class="headerlink" title="ACL"></a>ACL</h2><p>权限控制表简称 ACL（Access-Control List），ACL 记录了哪些 <strong>资源</strong> 可以被哪些 <strong>主体</strong> 进行哪些 <strong>操作</strong> ，是一个关系表，大部分的权限系统里都会有这张表。而在一个 ACL 表里，一般会有主体、对象和动作三个要素，设计出来的库表一般为：</p><table><thead><tr><th>id</th><th>subject</th><th>object</th><th>action</th></tr></thead><tbody><tr><td>1</td><td>user1</td><td>文档 1</td><td>查看</td></tr><tr><td>2</td><td>user1</td><td>文档 2</td><td>编辑</td></tr><tr><td>3</td><td>user2</td><td>文档 2</td><td>删除</td></tr></tbody></table><h3 id="DAC"><a href="#DAC" class="headerlink" title="DAC"></a>DAC</h3><p>自主访问控制简称 DAC（Discretionary Access Control），DAC 是 ACL 的一种实现，里面的主体就是用户。这样的设计简单直接，查询效率很高，强调自主是因为 DAC 模型将授权的权利下放，允许拥有指定权限的用户可以自主地将权限授予给其他用户。比如，在纯粹 ACL 模型下，每次新人培训，人事总监都要通知 IT 部，将培训文档的访问权限授予新人。在 DAC 模型下，人事总监只需将文档的访问权限授予人事专员。之后，每次新人培训，由人事专员将文档的访问权限授予不同的新人。</p><p>DAC 的缺点也很明显，比如在一家公司，每有一个新人入职，就需要人事专员给新人添加各种系统的权限，这些工作的重复性很大，而且文档越多，工作量越大。</p><h3 id="MAC"><a href="#MAC" class="headerlink" title="MAC"></a>MAC</h3><p>强制访问控制简称 MAC（Mandatory Access Control），是为了弥补 DAC 权限控制过于分散的问题而诞生的，在 MAC 模型中，会对资源进行类别划分、对主体进行等级划分。在进行权限校验时，会同时对主体的等级和资源的类别进行匹配，实现资源与主体的双重验证，确保资源的交叉隔离，提高安全性。比如情报局的任务有秘密级、机密级、绝密级，角色有007、M 和 Q，MAC 非常适合机密机构或者其他等级观念强烈的行业，但对于类似商业服务系统，则因为不够灵活而不能适用。</p><p>MAC的权限库表设计可能为：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">资源配置表</span><br><span class="line">  资源: 财务文档</span><br><span class="line"><span class="code">    主体: 财务人员</span></span><br><span class="line"><span class="code">    等级：经理级</span></span><br><span class="line"><span class="code">    操作：查看</span></span><br><span class="line"><span class="code">主体配置表</span></span><br><span class="line"><span class="code">        主体: 李女士</span></span><br><span class="line"><span class="code">          类别: 财务人员</span></span><br><span class="line"><span class="code">          等级：经理级</span></span><br></pre></td></tr></table></figure><h2 id="RBAC"><a href="#RBAC" class="headerlink" title="RBAC"></a>RBAC</h2><p>基于角色的访问控制简称 RBAC（Role-Based Access Control）。在 RBAC 里面，一个人有了一些固定的权限后，他就是一个角色，于是引入了“角色”的概念，可以理解为角色就是一组权限的集合。这个模型有效的解决了 ACL 模型里面管理员给每一个新人逐个系统加权限的问题，只需要在最初配置好角色所拥有的权限，在新人入职时给新人分配一个角色就可以了，大大减少重复性操作负担。需要注意的是，实现时要验证角色是否有某个权限，而不是去验证用户是否是某个角色。</p><p>引入角色概念后，RBAC 演进出了 4 种细分模型：RBAC0、RBAC1、RBAC2、RBAC3。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=N2IxMDUxMmVlZTI2NGYzZWIwOTg3MTIwNjc3NzAzNTRfUDZrS1NacldSMUViaXZwcWFuSjR1a0R6TTRQT3dobTVfVG9rZW46WFVRb2JkdjNLb3YzSWN4c0d3Q2NRRlhrbkdiXzE3NTA0NjU3ODU6MTc1MDQ2OTM4NV9WNA" alt="img"></p><h3 id="RBAC0"><a href="#RBAC0" class="headerlink" title="RBAC0"></a>RBAC0</h3><p>RBAC0 就是上面说的最基础的 RBAC 模型，只引入了角色的概念，在这个模型下，用户和角色是多对多的关系，角色和权限之间也是多对多的关系，角色实现了用户和权限间的解耦：</p><h3 id="RBAC1"><a href="#RBAC1" class="headerlink" title="RBAC1"></a>RBAC1</h3><p>RBAC1 模型是 RBAC0 的升级版，它对角色这层元素上进行了细分，引入 <strong>角色继承</strong> 的概念，也就是可以继承某个基础角色生成子角色。RBAC1 模型可以更好地在角色层面进行细分，更好地映射了企业组织架构中的职能的权限，根据实际的管理权限对相似职能的角色进行删减以达到级别分明的效果。</p><p><strong>应用场景</strong> ：市场经理岗位可能会分为总监级别、经理级别、副经理级别，这时候如果小陈只是一个副经理级别的，那么他所拥有的市场经理的权限肯定就没有总监级别的多 1 。</p><h3 id="RBAC2"><a href="#RBAC2" class="headerlink" title="RBAC2"></a>RBAC2</h3><p>在 RBAC2 中对角色层面增加了 <strong>职责分离</strong> 的限制：</p><p>（1）静态职责分离（Static Separation of Duty)）</p><ul><li>角色互斥：相同用户不能同时拥有互斥关系的角色，例如会计和出纳两个角色就是互斥的</li><li>基数约束：角色被分配到的用户有数量上限，例如公司中只有一个 CEO 职位，那么这个角色的数量就是有限的</li><li>先决条件角色：要拥有更高级别的角色权限，需要先获取到相对来说低级别的一些权限，例如副经理要想获取到总监级别权限，那么他需要先获取到经理级别的权限。</li></ul><p>（2）动态职责分离（Dynamic Separation of Duty）</p><p>用户在一次会话（Session）中不能同时激活自身所拥有的、互相有冲突的角色，只能选择其一。</p><h3 id="RBAC3"><a href="#RBAC3" class="headerlink" title="RBAC3"></a>RBAC3</h3><p>RBAC3 模型就是 <code>RBAC1 + RBAC2</code> 两个模型的合集，所以 RBAC3 既有 RBAC1 的角色等级划分，也有 RBAC2 的角色限制。这种模型只有在系统比较复杂的时候才派得上用场，不然设计得过度复杂，对开发和后期维护也不是好事情。</p><h3 id="RBAC-的优缺点"><a href="#RBAC-的优缺点" class="headerlink" title="RBAC 的优缺点"></a>RBAC 的优缺点</h3><p>RBAC 的优点很明显就是只需要分配一次角色，大大减少了重复性操作负担，解耦了用户和权限的关系。</p><p>但是 RBAC 并不总能满足所有权限的场景。比如，我们无法对销售角色进行个体定制。比如，销售角色拥有创建、删除的权限。如果我们要对销售小李，去掉删除的权限。那么，我们就必须创建另一个角色，来满足需求。如果这种情况很频繁，就会丧失角色的统一性，降低系统的可维护性。</p><h3 id="用户组"><a href="#用户组" class="headerlink" title="用户组"></a>用户组</h3><p>很多情况下权限系统还会在 <code>用户&lt;--&gt;角色&lt;--&gt;权限</code> 的基础上引入 <strong>用户组</strong> 的概念，用户组就是用户（主体）的集合，打个比方，在一家公司需要将岗位 A 的所有人都调配到岗位 B，如果单纯的更改用户的角色，操作量还是很大，加入用户组的概念后，只需要将一个用户组的角色从岗位 A 改为岗位 B 就可以了。</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">用户<span class="xml"><span class="tag">&lt;<span class="name">=关系表=</span>&gt;</span></span>用户组<span class="xml"><span class="tag">&lt;<span class="name">=关系表=</span>&gt;</span></span>角色<span class="xml"><span class="tag">&lt;<span class="name">=关系表=</span>&gt;</span></span>权限</span><br></pre></td></tr></table></figure><h4 id="角色和组的区别"><a href="#角色和组的区别" class="headerlink" title="角色和组的区别"></a>角色和组的区别</h4><p>角色和组两个概念可能会让人混淆，这里做个区分：</p><ul><li>主体可以是用户，也可以是组，角色赋予的是主体。</li><li>角色是权限的集合。</li><li>组是用户的集合</li></ul><h2 id="ABAC"><a href="#ABAC" class="headerlink" title="ABAC"></a>ABAC</h2><p>基于属性的访问控制（Attribute-Based Access Control，简称 ABAC）是一种非常灵活的授权模型，不同于 RBAC，在 ABAC 中，一个操作是否被允许是基于对象、资源、操作和环境信息共同动态计算决定的 2 。</p><ul><li>对象：对象是当前请求访问资源的用户。用户的属性包括ID，个人资源，角色，部门和组织成员身份等；</li><li>资源：资源是当前访问用户要访问的资产或对象（例如文件，数据，服务器，甚至API）。资源属性包含文件的创建日期，文件所有者，文件名和类型以及数据敏感性等等；</li><li>操作：操作是用户试图对资源进行的操作。常见的操作包括“读取”，“写入”，“编辑”，“复制”和“删除”；</li><li>环境：环境是每个访问请求的上下文。环境属性包含访问尝试的时间和位置，对象的设备，通信协议和加密强度等。</li></ul><h3 id="如何使用属性进行动态计算"><a href="#如何使用属性进行动态计算" class="headerlink" title="如何使用属性进行动态计算"></a>如何使用属性进行动态计算</h3><p>在 ABAC 的决策语句的执行过程中，决策引擎会根据定义好的决策语句，结合对象、资源、操作、环境等因素动态计算出决策结果。每当发生访问请求时，ABAC 决策系统都会分析属性值是否与已建立的策略匹配。如果有匹配的策略，访问请求就会被通过。</p><p>例如，策略「当一个文档的所属部门跟用户的部门相同时，用户可以访问这个文档」会被以下属性匹配：</p><ul><li>对象（用户）的部门 = 资源的所属部门；</li><li>资源 = “文档”；</li><li>操作 = “访问”；</li></ul><p>策略「早上九点前禁止 A 部门的人访问B系统；」会被以下属性匹配：</p><ul><li>对象的部门 = A 部门；</li><li>资源 = “B 系统”；</li><li>操作 = “访问”；</li><li>环境 = “时间是早上 9 点”。</li></ul><p>浓缩到一句话，在 ABAC 模型下你可以 <strong>细粒度地授权在何种情况下对某个资源具备某个特定的权限。</strong></p><h3 id="优缺点"><a href="#优缺点" class="headerlink" title="优缺点"></a>优缺点</h3><p>基于了这些属性，就可以进行规则的定制，可见灵活但是复杂，配置的工作量根据实际业务的复杂度成正比。kubernetes 也因为其过于复杂改用了 RBAC 3 。</p><blockquote><p>ABAC, Attribute Based Access Control, is a powerful concept. However, as implemented in Kubernetes, ABAC is difficult to manage and understand. It requires ssh and root filesystem access on the master VM of the cluster to make authorization policy changes. For permission changes to take effect the cluster API server must be restarted.</p></blockquote><p>RBAC 也相应解决了使用 ABAC 时面临的问题：</p><blockquote><p>RBAC permission policies are configured using kubectl or the Kubernetes API directly. Users can be authorized to make authorization policy changes using RBAC itself, making it possible to delegate resource management without giving away ssh access to the cluster master. RBAC policies map easily to the resources and operations used in the Kubernetes API.</p></blockquote><p>除了维护难度高以外，ABAC 的规则判断是实时执行，规则过多或者需求复杂时需要关注性能问题。</p><h3 id="选择-RBAC-还是-ABAC"><a href="#选择-RBAC-还是-ABAC" class="headerlink" title="选择 RBAC 还是 ABAC"></a>选择 RBAC 还是 ABAC</h3><p>在这里，组织的规模是至关重要的因素。由于 ABAC 最初的设计和实施困难，对于小型企业而言，考虑起来可能太复杂了。</p><p>对于中小型企业，RBAC 是 ABAC 的简单替代方案。每个用户都有一个唯一的角色，并具有相应的权限和限制。当用户转移到新角色时，其权限将更改为新职位的权限。这意味着，在明确定义角色的层次结构中，可以轻松管理少量内部和外部用户。</p><p>但是，当必须手动建立新角色时，对于大型组织而言，效率不高。一旦定义了属性和规则，当用户和利益相关者众多时，ABAC 的策略就更容易应用，同时还降低了安全风险。</p><p>简而言之，如果满足以下条件，请选择 ABAC：</p><ul><li>你在一个拥有许多用户的大型组织中；</li><li>你需要深入的特定访问控制功能；</li><li>你有时间投资远距离的模型；</li><li>你需要确保隐私和安全合规；</li></ul><p>但是，如果满足以下条件，请考虑 RBAC：</p><ul><li>你所在的是中小型企业；</li><li>你的访问控制策略广泛；</li><li>你的外部用户很少，并且你的组织角色得到了明确定义。</li></ul><h3 id="PBAC"><a href="#PBAC" class="headerlink" title="PBAC"></a>PBAC</h3><p>PBAC（Policy-Based Access Control）是基于策略的权限控制，其实 ABAC 里已经开始有策略的味道了，PBAC 就是相对于传统的 ABAC 更加强调策略（Policy），故 PBAC 也是 ABAC。参考维基百科 XACML 里的描述 4 ：</p><blockquote><p>XACML is primarily an <a href="https://en.wikipedia.org/wiki/Attribute-based_access_control">attribute-based access control </a>system (ABAC), also known as a policy-based access control (PBAC) system, where attributes (bits of data) associated with a user or action or resource are inputs into the decision of whether a given user may access a given resource in a particular way.</p></blockquote><h2 id="框架实现"><a href="#框架实现" class="headerlink" title="框架实现"></a>框架实现</h2><h3 id="Casbin"><a href="#Casbin" class="headerlink" title="Casbin"></a>Casbin</h3><p>Casbin 是一个强大的、高效的开源访问控制框架，其权限管理机制支持多种访问控制模型。上述的权限模型，都可以通过 Casbin 来实现，非常好上手，文档提供了工作原理 5 的介绍，可以进行详细了解。</p><p>不过注意，Casbin 没有以下功能：</p><ol><li>身份认证 authentication（即验证用户的用户名和密码），Casbin 只负责访问控制。应该有其他专门的组件负责身份认证，然后由 Casbin 进行访问控制，二者是相互配合的关系。</li><li>管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适， 用户通常有他们的密码，但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储 RBAC 方案中用户和角色之间的映射关系。</li></ol><h3 id="Shiro"><a href="#Shiro" class="headerlink" title="Shiro"></a>Shiro</h3><p>Apache Shiro 是一个强大而灵活的开源安全框架，可以干净地处理身份验证、授权、企业会话管理和加密，是 Java 技术栈，感兴趣可以了解下。</p><h3 id="Spring-Security"><a href="#Spring-Security" class="headerlink" title="Spring Security"></a>Spring Security</h3><p>Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架，也是 Java 技术栈，感兴趣可以了解下。</p><h3 id="Django"><a href="#Django" class="headerlink" title="Django"></a>Django</h3><p>Django 是一个 Web 框架，因为以前用过 Django 比较了解，顺便说一下，Django 自带的基础功能也实现了一层针对 Model 层数据的 RBAC，可以在此基础上做一些业务开发。另外我也在其 Admin 的基础上做了一个针对 API 的权限校验，感兴趣可以看下： <a href="https://github.com/tcitry/django-api-permission">django-api-permission </a>。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>不过 Shiro 和 Spring Security 甚至 Django 都不支持 ABAC 模型，需要另外开发业务逻辑，Casbin 可以通过模型配置文件的方式原生支持，且常用语言都提供了 SDK。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;🔗 原文链接： &lt;a href=&quot;https://yindongliang.com/posts/permission-system-models/&quot;&gt;https://yindongliang.com/posts/perm…&lt;/a&gt;&lt;/p&gt;
&lt;/b</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>SSH配置访问</title>
    <link href="https://imlike.cc/e9de1b97.html"/>
    <id>https://imlike.cc/e9de1b97.html</id>
    <published>2025-05-21T08:14:49.000Z</published>
    <updated>2025-06-21T00:25:05.872Z</updated>
    
    <content type="html"><![CDATA[<p> ssh -vvvT <a href="mailto:&#103;&#x69;&#x74;&#x40;&#103;&#x69;&#116;&#104;&#117;&#98;&#x2e;&#99;&#111;&#109;">&#103;&#x69;&#x74;&#x40;&#103;&#x69;&#116;&#104;&#117;&#98;&#x2e;&#99;&#111;&#109;</a></p><p> OpenSSH_9.9p2, LibreSSL 3.3.6</p><p>debug1: Reading configuration data /etc/ssh/ssh_config</p><p>debug1: /etc/ssh/ssh_config line 21: include /etc/ssh/ssh_config.d/* matched no files</p><p>debug1: /etc/ssh/ssh_config line 54: Applying options for *</p><p>debug3: expanded UserKnownHostsFile ‘~/.ssh/known_hosts’ -&gt; ‘/Users/kuolee/.ssh/known_hosts’</p><p>debug3: expanded UserKnownHostsFile ‘~/.ssh/known_hosts2’ -&gt; ‘/Users/kuolee/.ssh/known_hosts2’</p><p>debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling</p><p>debug3: channel_clear_timeouts: clearing</p><p>debug1: Connecting to github.com port 22.</p><p>debug1: Connection established.</p><p>debug1: identity file /Users/kuolee/.ssh/id_rsa type 0</p><p>debug1: identity file /Users/kuolee/.ssh/id_rsa-cert type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ecdsa type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ecdsa-cert type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ecdsa_sk type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ecdsa_sk-cert type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ed25519 type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ed25519-cert type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ed25519_sk type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_ed25519_sk-cert type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_xmss type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_xmss-cert type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_dsa type -1</p><p>debug1: identity file /Users/kuolee/.ssh/id_dsa-cert type -1</p><p>debug1: Local version string SSH-2.0-OpenSSH_9.9</p><p>kex_exchange_identification: Connection closed by remote host</p><p>Connection closed by 198.18.0.64 port 22</p><p>$ ssh -T <a href="mailto:&#103;&#x69;&#x74;&#64;&#103;&#105;&#x74;&#104;&#117;&#98;&#x2e;&#x63;&#x6f;&#109;">&#103;&#x69;&#x74;&#64;&#103;&#105;&#x74;&#104;&#117;&#98;&#x2e;&#x63;&#x6f;&#109;</a><br>ssh: connect to host github.com port 22: Connection refused</p><p>$ ssh -T -p 443 <a href="mailto:&#103;&#x69;&#116;&#64;&#x73;&#x73;&#x68;&#x2e;&#x67;&#105;&#116;&#x68;&#117;&#98;&#46;&#99;&#111;&#x6d;">&#103;&#x69;&#116;&#64;&#x73;&#x73;&#x68;&#x2e;&#x67;&#105;&#116;&#x68;&#117;&#98;&#46;&#99;&#111;&#x6d;</a></p><p>The authenticity of host ‘[ssh.github.com]:443 ([198.18.26.76]:443)’ can’t be established.<br>ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.<br>This key is not known by any other names.<br>Are you sure you want to continue connecting (yes/no/[fingerprint])? yes<br>Warning: Permanently added ‘[ssh.github.com]:443’ (ED25519) to the list of known hosts.<br>Hi bigleek! You’ve successfully authenticated, but GitHub does not provide shell access.</p><p>kuolee at leek in ~<br>$ vi ~/.ssh/config</p><p>kuolee at leek in ~<br>$ ssh -T <a href="mailto:&#x67;&#x69;&#116;&#64;&#103;&#x69;&#116;&#x68;&#x75;&#x62;&#x2e;&#99;&#111;&#x6d;">&#x67;&#x69;&#116;&#64;&#103;&#x69;&#116;&#x68;&#x75;&#x62;&#x2e;&#99;&#111;&#x6d;</a><br>Hi bigleek! You’ve successfully authenticated, but GitHub does not provide shell access.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt; ssh -vvvT &lt;a href=&quot;mailto:&amp;#103;&amp;#x69;&amp;#x74;&amp;#x40;&amp;#103;&amp;#x69;&amp;#116;&amp;#104;&amp;#117;&amp;#98;&amp;#x2e;&amp;#99;&amp;#111;&amp;#109;&quot;&gt;&amp;#103;&amp;#x69;&amp;#x74;&amp;#x40;&amp;#</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>计算机符号和原码和反码以及位运算</title>
    <link href="https://imlike.cc/9bee7e85.html"/>
    <id>https://imlike.cc/9bee7e85.html</id>
    <published>2025-04-10T03:02:51.000Z</published>
    <updated>2025-04-21T11:23:36.569Z</updated>
    
    <content type="html"><![CDATA[<h2 id="为什么1bit对应-8-byte"><a href="#为什么1bit对应-8-byte" class="headerlink" title="为什么1bit对应 8 byte"></a>为什么1bit对应 8 byte</h2><p>此处引用至 <a href="https://zhuanlan.zhihu.com/p/572877610">一文读懂字符编码 - 知乎</a></p><p>ASCII 编码字符串都是这样</p><p>我们知道计算机的世界只有0和1，如果没有字符编码，我们看到的就是一串”110010100101100111001….”，我们的沟通就好像是在对牛弹琴，我看不懂它，它看不懂我。字符编码就好比人类和机器之间的翻译程序，把我们熟知的字符文字翻译成机器能读懂的二进制，同时把二进制翻译成我们能看懂的字符。以下是百科对字符编码的解释</p><blockquote><p>字符编码（Character encoding）也称字集码，是把字符集中的字符，编码为指定集合中的某一对象（例如：比特模式、自然数序列、8位组或者电脉冲），以便文本在计算机中存储或者通信网络的传递。常见的例子是将拉丁字母表编码成摩斯电码和ASCII，比如ASCII编码是将字母、数字和其它符号进行编号，并用7比特的二进制来表示这个整数。字符集（Character set）是多个字符的集合，字符集种类较多，每个字符集包含的字符个数不同，常见字符集名称：ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字，就需要进行字符编码，以便计算机能够识别和存储各种文字。</p></blockquote><h2 id="为什么计算机需要编码"><a href="#为什么计算机需要编码" class="headerlink" title="为什么计算机需要编码"></a>为什么计算机需要编码</h2><p><strong>编码</strong>（Encode）是信息从一种形式转换为另一种形式的过程，比如用预先规定的方法将字符（文字、数字、符号等）、图像、声音或其它对象转换成规定的电脉冲信号或二进制数字。我们现在看到的一幅幅图画，听到的一首首音乐，甚至我们写的一行行代码，敲下的一个个字符，所看到的所听到的都是那么的真实，但其实在背后都是一串「01」的数字，你昨天在手机上看到的那个心动女孩，真实世界中并不存在，只是计算机用「01」数字帮你生成的“骷髅”而已。</p><table><thead><tr><th align="center"><a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%BF%9B%E5%88%B6">二进制</a></th><th align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8D%81%E8%BF%9B%E5%88%B6">十进制</a></th><th align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8D%81%E5%85%AD%E8%BF%9B%E5%88%B6">十六进制</a></th><th align="center"><a href="https://zh.wikipedia.org/wiki/%E7%BC%A9%E5%86%99">缩写</a></th><th align="center"><a href="https://zh.wikipedia.org/wiki/Unicode">Unicode</a> 表示法</th><th align="center"><a href="https://zh.wikipedia.org/wiki/%E8%84%AB%E5%87%BA%E5%AD%97%E5%85%83">脱出字符</a> 表示法</th><th align="center">名称／意义</th></tr></thead><tbody><tr><td align="center">0000 0000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/0">0</a></td><td align="center">00</td><td align="center">NUL</td><td align="center">␀</td><td align="center">^@</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E7%A9%BA%E5%AD%97%E7%AC%A6">空字符</a>（Null）</td></tr><tr><td align="center">0000 0001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/1">1</a></td><td align="center">01</td><td align="center">SOH</td><td align="center">␁</td><td align="center">^A</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E6%A0%87%E9%A2%98%E5%BC%80%E5%A7%8B&action=edit&redlink=1">标题开始</a></td></tr><tr><td align="center">0000 0010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/2">2</a></td><td align="center">02</td><td align="center">STX</td><td align="center">␂</td><td align="center">^B</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E6%9C%AC%E6%96%87%E5%BC%80%E5%A7%8B&action=edit&redlink=1">本文开始</a></td></tr><tr><td align="center">0000 0011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/3">3</a></td><td align="center">03</td><td align="center">ETX</td><td align="center">␃</td><td align="center">^C</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E6%9C%AC%E6%96%87%E7%BB%93%E6%9D%9F&action=edit&redlink=1">本文结束</a></td></tr><tr><td align="center">0000 0100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/4">4</a></td><td align="center">04</td><td align="center">EOT</td><td align="center">␄</td><td align="center">^D</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E5%82%B3%E8%BC%B8%E7%BB%93%E6%9D%9F&action=edit&redlink=1">传输结束</a></td></tr><tr><td align="center">0000 0101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/5">5</a></td><td align="center">05</td><td align="center">ENQ</td><td align="center">␅</td><td align="center">^E</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E8%AF%B7%E6%B1%82&action=edit&redlink=1">请求</a></td></tr><tr><td align="center">0000 0110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/6">6</a></td><td align="center">06</td><td align="center">ACK</td><td align="center">␆</td><td align="center">^F</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E7%A2%BA%E8%AA%8D%E5%9B%9E%E6%87%89">确认回应</a></td></tr><tr><td align="center">0000 0111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/7">7</a></td><td align="center">07</td><td align="center">BEL</td><td align="center">␇</td><td align="center">^G</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E5%93%8D%E9%93%83%E5%AD%97%E7%AC%A6&action=edit&redlink=1">响铃</a></td></tr><tr><td align="center">0000 1000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/8">8</a></td><td align="center">08</td><td align="center">BS</td><td align="center">␈</td><td align="center">^H</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E9%80%80%E6%A0%BC%E9%8D%B5">退格</a></td></tr><tr><td align="center">0000 1001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/9">9</a></td><td align="center">09</td><td align="center">HT</td><td align="center">␉</td><td align="center">^I</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%88%B6%E8%A1%A8%E9%94%AE#%E5%AE%9A%E4%BD%8D%E7%AC%A6%E5%8F%B7">水平定位符号</a></td></tr><tr><td align="center">0000 1010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/10">10</a></td><td align="center">0A</td><td align="center">LF</td><td align="center">␊</td><td align="center">^J</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E6%8F%9B%E8%A1%8C">换行键</a></td></tr><tr><td align="center">0000 1011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/11">11</a></td><td align="center">0B</td><td align="center">VT</td><td align="center">␋</td><td align="center">^K</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E5%9E%82%E7%9B%B4%E5%AE%9A%E4%BD%8D%E7%AC%A6%E8%99%9F&action=edit&redlink=1">垂直定位符号</a></td></tr><tr><td align="center">0000 1100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/12">12</a></td><td align="center">0C</td><td align="center">FF</td><td align="center">␌</td><td align="center">^L</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E6%8F%9B%E9%A0%81%E9%8D%B5&action=edit&redlink=1">换页键</a></td></tr><tr><td align="center">0000 1101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/13">13</a></td><td align="center">0D</td><td align="center">CR</td><td align="center">␍</td><td align="center">^M</td><td align="center"><a href="https://zh.wikipedia.org/wiki/CR_(%E5%AD%97%E5%85%83)">CR (字符)</a></td></tr><tr><td align="center">0000 1110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/14">14</a></td><td align="center">0E</td><td align="center">SO</td><td align="center">␎</td><td align="center">^N</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8F%96%E6%B6%88%E8%AE%8A%E6%8D%A2">取消变换</a>（Shift out）</td></tr><tr><td align="center">0000 1111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/15">15</a></td><td align="center">0F</td><td align="center">SI</td><td align="center">␏</td><td align="center">^O</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%90%AF%E7%94%A8%E8%AE%8A%E6%8D%A2">启用变换</a>（Shift in）</td></tr><tr><td align="center">0001 0000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/16">16</a></td><td align="center">10</td><td align="center">DLE</td><td align="center">␐</td><td align="center">^P</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E8%B7%B3%E5%87%BA%E6%95%B0%E6%8D%AE%E9%80%9A%E8%AE%AF&action=edit&redlink=1">跳出数据通讯</a></td></tr><tr><td align="center">0001 0001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/17">17</a></td><td align="center">11</td><td align="center">DC1</td><td align="center">␑</td><td align="center">^Q</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E8%A8%AD%E5%82%99%E6%8E%A7%E5%88%B6&action=edit&redlink=1">设备控制</a>一（<a href="https://zh.wikipedia.org/w/index.php?title=XON&action=edit&redlink=1">XON</a> <a href="https://zh.wikipedia.org/w/index.php?title=%E5%95%9F%E7%94%A8%E8%BB%9F%E9%AB%94%E9%80%9F%E5%BA%A6%E6%8E%A7%E5%88%B6&action=edit&redlink=1">激活软件速度控制</a>）</td></tr><tr><td align="center">0001 0010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/18">18</a></td><td align="center">12</td><td align="center">DC2</td><td align="center">␒</td><td align="center">^R</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E8%A8%AD%E5%82%99%E6%8E%A7%E5%88%B6&action=edit&redlink=1">设备控制</a>二</td></tr><tr><td align="center">0001 0011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/19">19</a></td><td align="center">13</td><td align="center">DC3</td><td align="center">␓</td><td align="center">^S</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E8%A8%AD%E5%82%99%E6%8E%A7%E5%88%B6&action=edit&redlink=1">设备控制</a>三（<a href="https://zh.wikipedia.org/w/index.php?title=XOFF&action=edit&redlink=1">XOFF</a> <a href="https://zh.wikipedia.org/w/index.php?title=%E5%81%9C%E7%94%A8%E8%BB%9F%E9%AB%94%E9%80%9F%E5%BA%A6%E6%8E%A7%E5%88%B6&action=edit&redlink=1">停用软件速度控制</a>）</td></tr><tr><td align="center">0001 0100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/20">20</a></td><td align="center">14</td><td align="center">DC4</td><td align="center">␔</td><td align="center">^T</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E8%A8%AD%E5%82%99%E6%8E%A7%E5%88%B6&action=edit&redlink=1">设备控制</a>四</td></tr><tr><td align="center">0001 0101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/21">21</a></td><td align="center">15</td><td align="center">NAK</td><td align="center">␕</td><td align="center">^U</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E7%A2%BA%E8%AA%8D%E5%A4%B1%E6%95%97%E5%9B%9E%E6%87%89">确认失败回应</a></td></tr><tr><td align="center">0001 0110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/22">22</a></td><td align="center">16</td><td align="center">SYN</td><td align="center">␖</td><td align="center">^V</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E5%90%8C%E6%AD%A5%E7%94%A8%E6%9A%AB%E5%81%9C&action=edit&redlink=1">同步用暂停</a></td></tr><tr><td align="center">0001 0111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/23">23</a></td><td align="center">17</td><td align="center">ETB</td><td align="center">␗</td><td align="center">^W</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E5%8D%80%E5%A1%8A%E5%82%B3%E8%BC%B8%E7%BB%93%E6%9D%9F&action=edit&redlink=1">区块传输结束</a></td></tr><tr><td align="center">0001 1000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/24">24</a></td><td align="center">18</td><td align="center">CAN</td><td align="center">␘</td><td align="center">^X</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E5%8F%96%E6%B6%88&action=edit&redlink=1">取消</a></td></tr><tr><td align="center">0001 1001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/25">25</a></td><td align="center">19</td><td align="center">EM</td><td align="center">␙</td><td align="center">^Y</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E9%80%A3%E7%B7%9A%E4%BB%8B%E8%B4%A8%E4%B8%AD%E6%96%AD&action=edit&redlink=1">连线介质中断</a></td></tr><tr><td align="center">0001 1010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/26">26</a></td><td align="center">1A</td><td align="center">SUB</td><td align="center">␚</td><td align="center">^Z</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E6%9B%BF%E4%BB%A3%E5%AD%97%E7%AC%A6">替换</a></td></tr><tr><td align="center">0001 1011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/27">27</a></td><td align="center">1B</td><td align="center">ESC</td><td align="center">␛</td><td align="center">^[</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E9%80%80%E5%87%BA%E9%94%AE">退出键</a></td></tr><tr><td align="center">0001 1100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/28">28</a></td><td align="center">1C</td><td align="center">FS</td><td align="center">␜</td><td align="center">^\</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E6%96%87%E4%BB%B6%E5%88%86%E5%89%B2%E7%AC%A6&action=edit&redlink=1">文件分割符</a></td></tr><tr><td align="center">0001 1101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/29">29</a></td><td align="center">1D</td><td align="center">GS</td><td align="center">␝</td><td align="center">^]</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E7%BE%A4%E7%B5%84%E5%88%86%E9%9A%94%E7%AC%A6&action=edit&redlink=1">组群分隔符</a></td></tr><tr><td align="center">0001 1110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/30">30</a></td><td align="center">1E</td><td align="center">RS</td><td align="center">␞</td><td align="center">^^</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E8%AE%B0%E5%BD%95%E5%88%86%E9%9A%94%E7%AC%A6&action=edit&redlink=1">记录分隔符</a></td></tr><tr><td align="center">0001 1111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/31">31</a></td><td align="center">1F</td><td align="center">US</td><td align="center">␟</td><td align="center">^_</td><td align="center"><a href="https://zh.wikipedia.org/w/index.php?title=%E5%8D%95%E5%85%83%E5%88%86%E9%9A%94%E7%AC%A6&action=edit&redlink=1">单元分隔符</a></td></tr><tr><td align="center">0111 1111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/127">127</a></td><td align="center">7F</td><td align="center">DEL</td><td align="center">␡</td><td align="center">^?</td><td align="center"><a href="https://zh.wikipedia.org/wiki/Delete%E5%AD%97%E7%AC%A6">Delete字符</a></td></tr></tbody></table><table><thead><tr><th align="center"><a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%BF%9B%E5%88%B6">二进制</a></th><th align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8D%81%E8%BF%9B%E5%88%B6">十进制</a></th><th align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8D%81%E5%85%AD%E8%BF%9B%E5%88%B6">十六进制</a></th><th align="center"><a href="https://zh.wikipedia.org/wiki/%E5%9B%BE%E5%BD%A2">图形</a></th></tr></thead><tbody><tr><td align="center">0010 0000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/32">32</a></td><td align="center">20</td><td align="center">(<a href="https://zh.wikipedia.org/wiki/%E7%A9%BA%E6%A0%BC">space</a>)</td></tr><tr><td align="center">0010 0001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/33">33</a></td><td align="center">21</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E6%83%8A%E5%8F%B9%E5%8F%B7">!</a></td></tr><tr><td align="center">0010 0010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/34">34</a></td><td align="center">22</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8F%8C%E5%BC%95%E5%8F%B7">“</a></td></tr><tr><td align="center">0010 0011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/35">35</a></td><td align="center">23</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E4%BA%95%E5%8F%B7">#</a></td></tr><tr><td align="center">0010 0100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/36">36</a></td><td align="center">24</td><td align="center"><a href="https://zh.wikipedia.org/wiki/$">$</a></td></tr><tr><td align="center">0010 0101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/37">37</a></td><td align="center">25</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E7%99%BE%E5%88%86%E6%AF%94">%</a></td></tr><tr><td align="center">0010 0110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/38">38</a></td><td align="center">26</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%26">&amp;</a></td></tr><tr><td align="center">0010 0111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/39">39</a></td><td align="center">27</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8D%95%E5%BC%95%E5%8F%B7">‘</a></td></tr><tr><td align="center">0010 1000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/40">40</a></td><td align="center">28</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E6%8B%AC%E8%99%9F">(</a></td></tr><tr><td align="center">0010 1001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/41">41</a></td><td align="center">29</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E6%8B%AC%E8%99%9F">)</a></td></tr><tr><td align="center">0010 1010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/42">42</a></td><td align="center">2A</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E6%98%9F%E5%8F%B7">*</a></td></tr><tr><td align="center">0010 1011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/43">43</a></td><td align="center">2B</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8A%A0%E5%8F%B7">+</a></td></tr><tr><td align="center">0010 1100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/44">44</a></td><td align="center">2C</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E9%80%97%E5%8F%B7">,</a></td></tr><tr><td align="center">0010 1101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/45">45</a></td><td align="center">2D</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%87%8F%E5%8F%B7">-</a></td></tr><tr><td align="center">0010 1110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/46">46</a></td><td align="center">2E</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%8F%A5%E7%82%B9">.</a></td></tr><tr><td align="center">0010 1111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/47">47</a></td><td align="center">2F</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E6%96%9C%E7%B7%9A">/</a></td></tr><tr><td align="center">0011 0000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/48">48</a></td><td align="center">30</td><td align="center"><a href="https://zh.wikipedia.org/wiki/0">0</a></td></tr><tr><td align="center">0011 0001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/49">49</a></td><td align="center">31</td><td align="center"><a href="https://zh.wikipedia.org/wiki/1">1</a></td></tr><tr><td align="center">0011 0010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/50">50</a></td><td align="center">32</td><td align="center"><a href="https://zh.wikipedia.org/wiki/2">2</a></td></tr><tr><td align="center">0011 0011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/51">51</a></td><td align="center">33</td><td align="center"><a href="https://zh.wikipedia.org/wiki/3">3</a></td></tr><tr><td align="center">0011 0100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/52">52</a></td><td align="center">34</td><td align="center"><a href="https://zh.wikipedia.org/wiki/4">4</a></td></tr><tr><td align="center">0011 0101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/53">53</a></td><td align="center">35</td><td align="center"><a href="https://zh.wikipedia.org/wiki/5">5</a></td></tr><tr><td align="center">0011 0110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/54">54</a></td><td align="center">36</td><td align="center"><a href="https://zh.wikipedia.org/wiki/6">6</a></td></tr><tr><td align="center">0011 0111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/55">55</a></td><td align="center">37</td><td align="center"><a href="https://zh.wikipedia.org/wiki/7">7</a></td></tr><tr><td align="center">0011 1000</td><td align="center"><a href="https://zh.wikipedia.org/wiki/56">56</a></td><td align="center">38</td><td align="center"><a href="https://zh.wikipedia.org/wiki/8">8</a></td></tr><tr><td align="center">0011 1001</td><td align="center"><a href="https://zh.wikipedia.org/wiki/57">57</a></td><td align="center">39</td><td align="center"><a href="https://zh.wikipedia.org/wiki/9">9</a></td></tr><tr><td align="center">0011 1010</td><td align="center"><a href="https://zh.wikipedia.org/wiki/58">58</a></td><td align="center">3A</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%86%92%E5%8F%B7">:</a></td></tr><tr><td align="center">0011 1011</td><td align="center"><a href="https://zh.wikipedia.org/wiki/59">59</a></td><td align="center">3B</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%88%86%E5%8F%B7">;</a></td></tr><tr><td align="center">0011 1100</td><td align="center"><a href="https://zh.wikipedia.org/wiki/60">60</a></td><td align="center">3C</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%B0%8F%E6%96%BC%E8%99%9F">&lt;</a></td></tr><tr><td align="center">0011 1101</td><td align="center"><a href="https://zh.wikipedia.org/wiki/61">61</a></td><td align="center">3D</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E7%AD%89%E5%8F%B7">=</a></td></tr><tr><td align="center">0011 1110</td><td align="center"><a href="https://zh.wikipedia.org/wiki/62">62</a></td><td align="center">3E</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E5%A4%A7%E6%96%BC%E8%99%9F">&gt;</a></td></tr><tr><td align="center">0011 1111</td><td align="center"><a href="https://zh.wikipedia.org/wiki/63">63</a></td><td align="center">3F</td><td align="center"><a href="https://zh.wikipedia.org/wiki/%E9%97%AE%E5%8F%B7">?</a></td></tr></tbody></table><table><thead><tr><th>0100 0000</th><th><a href="https://zh.wikipedia.org/wiki/64">64</a></th><th>40</th><th><a href="https://zh.wikipedia.org/wiki/@">@</a></th></tr></thead><tbody><tr><td>0100 0001</td><td><a href="https://zh.wikipedia.org/wiki/65">65</a></td><td>41</td><td><a href="https://zh.wikipedia.org/wiki/A">A</a></td></tr><tr><td>0100 0010</td><td><a href="https://zh.wikipedia.org/wiki/66">66</a></td><td>42</td><td><a href="https://zh.wikipedia.org/wiki/B">B</a></td></tr><tr><td>0100 0011</td><td><a href="https://zh.wikipedia.org/wiki/67">67</a></td><td>43</td><td><a href="https://zh.wikipedia.org/wiki/C">C</a></td></tr><tr><td>0100 0100</td><td><a href="https://zh.wikipedia.org/wiki/68">68</a></td><td>44</td><td><a href="https://zh.wikipedia.org/wiki/D">D</a></td></tr><tr><td>0100 0101</td><td><a href="https://zh.wikipedia.org/wiki/69">69</a></td><td>45</td><td><a href="https://zh.wikipedia.org/wiki/E">E</a></td></tr><tr><td>0100 0110</td><td><a href="https://zh.wikipedia.org/wiki/70">70</a></td><td>46</td><td><a href="https://zh.wikipedia.org/wiki/F">F</a></td></tr><tr><td>0100 0111</td><td><a href="https://zh.wikipedia.org/wiki/71">71</a></td><td>47</td><td><a href="https://zh.wikipedia.org/wiki/G">G</a></td></tr><tr><td>0100 1000</td><td><a href="https://zh.wikipedia.org/wiki/72">72</a></td><td>48</td><td><a href="https://zh.wikipedia.org/wiki/H">H</a></td></tr><tr><td>0100 1001</td><td><a href="https://zh.wikipedia.org/wiki/73">73</a></td><td>49</td><td><a href="https://zh.wikipedia.org/wiki/I">I</a></td></tr><tr><td>0100 1010</td><td><a href="https://zh.wikipedia.org/wiki/74">74</a></td><td>4A</td><td><a href="https://zh.wikipedia.org/wiki/J">J</a></td></tr><tr><td>0100 1011</td><td><a href="https://zh.wikipedia.org/wiki/75">75</a></td><td>4B</td><td><a href="https://zh.wikipedia.org/wiki/K">K</a></td></tr><tr><td>0100 1100</td><td><a href="https://zh.wikipedia.org/wiki/76">76</a></td><td>4C</td><td><a href="https://zh.wikipedia.org/wiki/L">L</a></td></tr><tr><td>0100 1101</td><td><a href="https://zh.wikipedia.org/wiki/77">77</a></td><td>4D</td><td><a href="https://zh.wikipedia.org/wiki/M">M</a></td></tr><tr><td>0100 1110</td><td><a href="https://zh.wikipedia.org/wiki/78">78</a></td><td>4E</td><td><a href="https://zh.wikipedia.org/wiki/N">N</a></td></tr><tr><td>0100 1111</td><td><a href="https://zh.wikipedia.org/wiki/79">79</a></td><td>4F</td><td><a href="https://zh.wikipedia.org/wiki/O">O</a></td></tr><tr><td>0101 0000</td><td><a href="https://zh.wikipedia.org/wiki/80">80</a></td><td>50</td><td><a href="https://zh.wikipedia.org/wiki/P">P</a></td></tr><tr><td>0101 0001</td><td><a href="https://zh.wikipedia.org/wiki/81">81</a></td><td>51</td><td><a href="https://zh.wikipedia.org/wiki/Q">Q</a></td></tr><tr><td>0101 0010</td><td><a href="https://zh.wikipedia.org/wiki/82">82</a></td><td>52</td><td><a href="https://zh.wikipedia.org/wiki/R">R</a></td></tr><tr><td>0101 0011</td><td><a href="https://zh.wikipedia.org/wiki/83">83</a></td><td>53</td><td><a href="https://zh.wikipedia.org/wiki/S">S</a></td></tr><tr><td>0101 0100</td><td><a href="https://zh.wikipedia.org/wiki/84">84</a></td><td>54</td><td><a href="https://zh.wikipedia.org/wiki/T">T</a></td></tr><tr><td>0101 0101</td><td><a href="https://zh.wikipedia.org/wiki/85">85</a></td><td>55</td><td><a href="https://zh.wikipedia.org/wiki/U">U</a></td></tr><tr><td>0101 0110</td><td><a href="https://zh.wikipedia.org/wiki/86">86</a></td><td>56</td><td><a href="https://zh.wikipedia.org/wiki/V">V</a></td></tr><tr><td>0101 0111</td><td><a href="https://zh.wikipedia.org/wiki/87">87</a></td><td>57</td><td><a href="https://zh.wikipedia.org/wiki/W">W</a></td></tr><tr><td>0101 1000</td><td><a href="https://zh.wikipedia.org/wiki/88">88</a></td><td>58</td><td><a href="https://zh.wikipedia.org/wiki/X">X</a></td></tr><tr><td>0101 1001</td><td><a href="https://zh.wikipedia.org/wiki/89">89</a></td><td>59</td><td><a href="https://zh.wikipedia.org/wiki/Y">Y</a></td></tr><tr><td>0101 1010</td><td><a href="https://zh.wikipedia.org/wiki/90">90</a></td><td>5A</td><td><a href="https://zh.wikipedia.org/wiki/Z">Z</a></td></tr><tr><td>0101 1011</td><td><a href="https://zh.wikipedia.org/wiki/91">91</a></td><td>5B</td><td>[<a href="https://zh.wikipedia.org/wiki/%E6%8B%AC%E8%99%9F"></a></td></tr><tr><td>0101 1100</td><td><a href="https://zh.wikipedia.org/wiki/92">92</a></td><td>5C</td><td>[](<a href="https://zh.wikipedia.org/wiki/%E5%8F%8D%E6%96%9C%E7%BA%BF">https://zh.wikipedia.org/wiki/反斜线</a>)</td></tr><tr><td>0101 1101</td><td><a href="https://zh.wikipedia.org/wiki/93">93</a></td><td>5D</td><td>[]](<a href="https://zh.wikipedia.org/wiki/%E6%8B%AC%E8%99%9F">https://zh.wikipedia.org/wiki/括號</a>)</td></tr><tr><td>0101 1110</td><td><a href="https://zh.wikipedia.org/wiki/94">94</a></td><td>5E</td><td><a href="https://zh.wikipedia.org/wiki/%E8%84%B1%E5%AD%97%E7%AC%A6">^</a></td></tr><tr><td>0101 1111</td><td><a href="https://zh.wikipedia.org/wiki/95">95</a></td><td>5F</td><td><a href="https://zh.wikipedia.org/wiki/%E5%BA%95%E7%B7%9A">_</a></td></tr></tbody></table><table><thead><tr><th>0110 0000</th><th><a href="https://zh.wikipedia.org/wiki/96">96</a></th><th>60</th><th>[`](<a href="https://zh.wikipedia.org/wiki/%E9%87%8D%E9%9F%B3%E7%AC%A6">https://zh.wikipedia.org/wiki/重音符</a>)</th></tr></thead><tbody><tr><td>0110 0001</td><td><a href="https://zh.wikipedia.org/wiki/97">97</a></td><td>61</td><td><a href="https://zh.wikipedia.org/wiki/A">a</a></td></tr><tr><td>0110 0010</td><td><a href="https://zh.wikipedia.org/wiki/98">98</a></td><td>62</td><td><a href="https://zh.wikipedia.org/wiki/B">b</a></td></tr><tr><td>0110 0011</td><td><a href="https://zh.wikipedia.org/wiki/99">99</a></td><td>63</td><td><a href="https://zh.wikipedia.org/wiki/C">c</a></td></tr><tr><td>0110 0100</td><td><a href="https://zh.wikipedia.org/wiki/100">100</a></td><td>64</td><td><a href="https://zh.wikipedia.org/wiki/D">d</a></td></tr><tr><td>0110 0101</td><td><a href="https://zh.wikipedia.org/wiki/101">101</a></td><td>65</td><td><a href="https://zh.wikipedia.org/wiki/E">e</a></td></tr><tr><td>0110 0110</td><td><a href="https://zh.wikipedia.org/wiki/102">102</a></td><td>66</td><td><a href="https://zh.wikipedia.org/wiki/F">f</a></td></tr><tr><td>0110 0111</td><td><a href="https://zh.wikipedia.org/wiki/103">103</a></td><td>67</td><td><a href="https://zh.wikipedia.org/wiki/G">g</a></td></tr><tr><td>0110 1000</td><td><a href="https://zh.wikipedia.org/wiki/104">104</a></td><td>68</td><td><a href="https://zh.wikipedia.org/wiki/H">h</a></td></tr><tr><td>0110 1001</td><td><a href="https://zh.wikipedia.org/wiki/105">105</a></td><td>69</td><td><a href="https://zh.wikipedia.org/wiki/I">i</a></td></tr><tr><td>0110 1010</td><td><a href="https://zh.wikipedia.org/wiki/106">106</a></td><td>6A</td><td><a href="https://zh.wikipedia.org/wiki/J">j</a></td></tr><tr><td>0110 1011</td><td><a href="https://zh.wikipedia.org/wiki/107">107</a></td><td>6B</td><td><a href="https://zh.wikipedia.org/wiki/K">k</a></td></tr><tr><td>0110 1100</td><td><a href="https://zh.wikipedia.org/wiki/108">108</a></td><td>6C</td><td><a href="https://zh.wikipedia.org/wiki/L">l</a></td></tr><tr><td>0110 1101</td><td><a href="https://zh.wikipedia.org/wiki/109">109</a></td><td>6D</td><td><a href="https://zh.wikipedia.org/wiki/M">m</a></td></tr><tr><td>0110 1110</td><td><a href="https://zh.wikipedia.org/wiki/110">110</a></td><td>6E</td><td><a href="https://zh.wikipedia.org/wiki/N">n</a></td></tr><tr><td>0110 1111</td><td><a href="https://zh.wikipedia.org/wiki/111">111</a></td><td>6F</td><td><a href="https://zh.wikipedia.org/wiki/O">o</a></td></tr><tr><td>0111 0000</td><td><a href="https://zh.wikipedia.org/wiki/112">112</a></td><td>70</td><td><a href="https://zh.wikipedia.org/wiki/P">p</a></td></tr><tr><td>0111 0001</td><td><a href="https://zh.wikipedia.org/wiki/113">113</a></td><td>71</td><td><a href="https://zh.wikipedia.org/wiki/Q">q</a></td></tr><tr><td>0111 0010</td><td><a href="https://zh.wikipedia.org/wiki/114">114</a></td><td>72</td><td><a href="https://zh.wikipedia.org/wiki/R">r</a></td></tr><tr><td>0111 0011</td><td><a href="https://zh.wikipedia.org/wiki/115">115</a></td><td>73</td><td><a href="https://zh.wikipedia.org/wiki/S">s</a></td></tr><tr><td>0111 0100</td><td><a href="https://zh.wikipedia.org/wiki/116">116</a></td><td>74</td><td><a href="https://zh.wikipedia.org/wiki/T">t</a></td></tr><tr><td>0111 0101</td><td><a href="https://zh.wikipedia.org/wiki/117">117</a></td><td>75</td><td><a href="https://zh.wikipedia.org/wiki/U">u</a></td></tr><tr><td>0111 0110</td><td><a href="https://zh.wikipedia.org/wiki/118">118</a></td><td>76</td><td><a href="https://zh.wikipedia.org/wiki/V">v</a></td></tr><tr><td>0111 0111</td><td><a href="https://zh.wikipedia.org/wiki/119">119</a></td><td>77</td><td><a href="https://zh.wikipedia.org/wiki/W">w</a></td></tr><tr><td>0111 1000</td><td><a href="https://zh.wikipedia.org/wiki/120">120</a></td><td>78</td><td><a href="https://zh.wikipedia.org/wiki/X">x</a></td></tr><tr><td>0111 1001</td><td><a href="https://zh.wikipedia.org/wiki/121">121</a></td><td>79</td><td><a href="https://zh.wikipedia.org/wiki/Y">y</a></td></tr><tr><td>0111 1010</td><td><a href="https://zh.wikipedia.org/wiki/122">122</a></td><td>7A</td><td><a href="https://zh.wikipedia.org/wiki/Z">z</a></td></tr><tr><td>0111 1011</td><td><a href="https://zh.wikipedia.org/wiki/123">123</a></td><td>7B</td><td><a href="https://zh.wikipedia.org/wiki/%E6%8B%AC%E8%99%9F">{</a></td></tr><tr><td>0111 1100</td><td><a href="https://zh.wikipedia.org/wiki/124">124</a></td><td>7C</td><td><a href="https://zh.wikipedia.org/wiki/%E8%B1%8E%E7%B7%9A">|</a></td></tr><tr><td>0111 1101</td><td><a href="https://zh.wikipedia.org/wiki/125">125</a></td><td>7D</td><td><a href="https://zh.wikipedia.org/wiki/%E6%8B%AC%E8%99%9F">}</a></td></tr><tr><td>0111 1110</td><td><a href="https://zh.wikipedia.org/wiki/126">126</a></td><td>7E</td><td><a href="https://zh.wikipedia.org/wiki/%E6%B3%A2%E6%B5%AA%E8%99%9F">~</a></td></tr></tbody></table><h2 id="计算机数字表示"><a href="#计算机数字表示" class="headerlink" title="计算机数字表示"></a>计算机数字表示</h2><p>在计算机中，有符号数和无符号数的区别主要体现在以下三个方面：</p><ol><li><p><strong>符号位的定义与数值范围</strong><br>有符号数的最高位（二进制最左侧位）被定义为符号位：<br>• <strong>0 表示正数</strong>，其余位表示数值大小（如 <code>01111111</code> 表示 +127）<br>• <strong>1 表示负数</strong>，其余位存储补码形式的数值（如 <code>10101111</code> 表示 -81）<br>而无符号数所有位都用于表示数值大小，因此 <strong>正数范围比同位数有符号数大一倍</strong>（例如 8 位无符号数范围是 0-255，而有符号数范围是 -128~127）</p></li><li><p><strong>补码转换规则</strong><br>负数在计算机中以补码形式存储。补码的计算步骤为：<br>• <strong>原码 → 符号位不变，其余位取反 → 末位 +1</strong><br>例如 <code>-81</code> 的补码转换过程：<br>原码：<code>10100001</code> → 取反后：<code>11011110</code> → 加 1 → <code>11011111</code>（即 <code>0xAF</code>）<br>补码的作用是统一加减法运算逻辑，简化硬件设计</p></li><li><p><strong>类型转换时的截断与符号扩展</strong><br>当长位数据（如 <code>Int</code>）转换为短位类型（如 <code>Byte</code>）时：<br>• <strong>截断规则</strong>：直接保留低位字节（如 <code>0xFFFFFFAF</code> → <code>0xAF</code>）<br>• <strong>符号位识别</strong>：目标类型若为有符号，则最高位决定正负（如 <code>0xAF</code> 的最高位为 1，解析为负数）<br>在 Scala 中，<code>Byte</code> 默认是有符号类型，因此 <code>0xAF</code> 会被解析为 <code>-81</code>。若需无符号处理，需通过 <code>&amp; 0xFF</code> 强制转换为正数</p></li></ol><p><strong>具体代码分析</strong>  </p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">println((<span class="number">-81.</span>toInt).toByte)  <span class="comment">// 输出 -81</span></span><br></pre></td></tr></table></figure><p>• <code>-81.toInt</code> 的补码是 <code>0xFFFFFFAF</code>（32位）<br>• <code>.toByte</code> 截断后保留 <code>0xAF</code>（二进制 <code>10101111</code>）<br>• 有符号 <code>Byte</code> 将最高位 <code>1</code> 识别为负号，剩余位 <code>0101111</code> 的补码还原为 <code>81</code>，最终结果为 <code>-81</code></p><p><strong>无符号处理对比</strong><br>若强制转换为无符号数（例如使用 <code>(pd(0) &amp; 0xFF)</code>）：  </p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">val</span> byteValue: <span class="type">Byte</span> = <span class="number">0xAF</span>.toByte  <span class="comment">// -81（有符号）</span></span><br><span class="line"><span class="keyword">val</span> unsignedValue = byteValue &amp; <span class="number">0xFF</span>  <span class="comment">// 175（无符号）</span></span><br></pre></td></tr></table></figure><p>此时 <code>0xAF</code> 会被视为 <code>175</code>，因为 <code>&amp; 0xFF</code> 将符号位清零，并扩展为 32 位整数</p><p><strong>总结</strong><br>有符号/无符号的区分本质是<strong>程序对二进制位的解释规则不同</strong>，而计算机存储的二进制数据本身没有符号属性。这一特性在涉及跨数据类型转换（如 <code>Int</code> → <code>Byte</code>）或位运算时需要特别注意。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;为什么1bit对应-8-byte&quot;&gt;&lt;a href=&quot;#为什么1bit对应-8-byte&quot; class=&quot;headerlink&quot; title=&quot;为什么1bit对应 8 byte&quot;&gt;&lt;/a&gt;为什么1bit对应 8 byte&lt;/h2&gt;&lt;p&gt;此处引用至 &lt;a href=</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>idea-mac激活</title>
    <link href="https://imlike.cc/63e78f83.html"/>
    <id>https://imlike.cc/63e78f83.html</id>
    <published>2025-04-09T11:07:44.000Z</published>
    <updated>2025-04-21T11:15:30.112Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://yby6.com/archives/ja-netfilte">https://yby6.com/archives/ja-netfilte</a></p><p>Could not set environment: 150: Operation not permitted while System Integrity Protection is engaged</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://yby6.com/archives/ja-netfilte&quot;&gt;https://yby6.com/archives/ja-netfilte&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Could not set environment: 150: Operatio</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>anthropic(Claude) promote 推荐</title>
    <link href="https://imlike.cc/12713d51.html"/>
    <id>https://imlike.cc/12713d51.html</id>
    <published>2025-03-13T08:19:45.000Z</published>
    <updated>2025-04-09T07:47:42.466Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://docs.anthropic.com/zh-CN/prompt-library">https://docs.anthropic.com/zh-CN/prompt-library</a></p><p>这个网站汇集了很多的promote 非常实用 </p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://docs.anthropic.com/zh-CN/prompt-library&quot;&gt;https://docs.anthropic.com/zh-CN/prompt-library&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个网站汇集了很多的promote 非常</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>学习的步骤讨论</title>
    <link href="https://imlike.cc/9de51b87.html"/>
    <id>https://imlike.cc/9de51b87.html</id>
    <published>2025-03-07T02:51:01.000Z</published>
    <updated>2025-04-09T07:47:42.467Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247539111&idx=1&sn=ef5e1cd2237732f2af4b515dbb66e26f&">跟着ChatGPT4o学全栈，我看到未来“学习”的模样</a></p><p><strong>在讨论之前，我们先了解下学习过程</strong></p><h3 id=""><a href="#" class="headerlink" title=""></a></h3><p>学习是一个复杂而多阶段的过程，每个阶段都有其独特的特点和目标。我们可以将学习过程分为以下几个阶段：</p><p>1.<strong>接触（Exposure）：</strong>学习的起点。首先，我们需要注意新的信息、知识或技能，并对其产生兴趣。</p><p>2.<strong>收集（Gathering）：</strong>系统地广泛地获取更多相关的信息和资源，以便更全面地理解新知识或技能。</p><p>3.<strong>理解（Understanding）：</strong>指将所收集的信息进行消化、分析和综合，以便形成对新知识或技能的全面认识。</p><p>4.<strong>记忆（Memorization）：</strong>涉及将理解的知识或技能存储在长期记忆中，以便将来可以方便地检索和应用。知识的理解程度对记忆的影响非常大。</p><p>5.<strong>应用（Application）：</strong>指将所学的知识或技能在实际情境中加以运用，以解决问题或完成任务。</p><p>6.<strong>反馈（Feedback）：</strong>根据应用的结果和他人的评价，反思和改进学习方法和策略。﻿</p><p><strong>失败的学习随处可见</strong></p><h3 id="-1"><a href="#-1" class="headerlink" title=""></a></h3><p>众所周知，学习过程中最耗费精力的是收集资料。寻找资料源、筛选高质量资料、系统化组织资料，这些任务不仅耗时费力，而且结果往往不尽如人意。﻿</p><p>在理解知识的过程中，我们需要大量的阅读、训练和思考。由于缺乏系统指导，学习者常常感到困惑和迷茫。</p><p>长周期的学习需要及时反馈。比如，学习一门新的编程语言，从基本语法开始逐步掌握，可能需要一到两个月才能开始实际操作项目。这么长的学习周期可能让我们失去目标感，增加中途放弃的风险，最终可能感到挫败。﻿</p><p>在学习过程中，缺乏足够的动力、信息过载、容易陷入单调重复、缺乏实践应用场景、反馈时间过长或无法得到反馈等都是障碍。这些问题都可能导致人们放弃学习。因此，我们常常看到失败的学习案例，而成功有效的学习案例则寥寥无几。﻿</p><p><strong>大模型让学习更容易成功</strong></p><h3 id="-2"><a href="#-2" class="headerlink" title=""></a></h3><p>通过上述演示，我们可以看到大型模型在各个学习环节中都能提供巨大的帮助，甚至在某些方面产生颠覆性的影响，这些影响能够提高学习成功的几率。</p><p>在资源收集方面，传统的模式（主要是搜索）需要在许多来源中收集。</p><p>﻿<img src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naKPoosibNYPZkOR1ko6REmAoKrum6Me7akP6VeKPn7LcDzHmUu8LebpnZtNkGic11kZm2TQe7Tn8p1w/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片">﻿</p><p>在此基础上还需要进一步做筛选和判断，这将消耗大量的精力。﻿</p><p>然而，大模型在资源收集上有两个优势：</p><ul><li><strong>高度整合的知识：</strong>大模型拥有大量的高质量知识，尤其在编程方面；</li><li><strong>按需定制：</strong>大模型可以根据个人水平实现定制化的教学课程；</li></ul><p>当然，GPT在这里也有一些限制：</p><ul><li><strong>知识更新不及时：</strong>通用的大模型不会使用未经验证的知识进行训练，虽然如此，但目前大模型的知识水平已经足够应对大部分的学习需求了。</li><li><strong>知识缺乏系统化：</strong>大型模型就像一只具有优秀记忆力的鹦鹉，它本身并未形成系统化的知识，需要借助prompt（像本文中学习前端的例子）或agent来实现结构化和系统化。</li></ul><p>我们都知道，<strong>理解是形成长期记忆的关键，而通过知识的类比和迁移来理解新知识是一种有效的方法。</strong>﻿</p><p>然而，建立类比和迁移这座连接新旧知识的桥梁并不容易。这不仅需要学习者理解新的概念，还需要将这些概念与已有的知识结构相结合，以便在新的情境中使用。如果对新概念理解不足，或者旧知识基础薄弱，就无法建立这种联系。</p><p><strong>大型模型在我们理解知识的过程中带来了新的启示，它具备非常强的知识类比能力。</strong>大模型以Java工程师的角度解释了如何理解React组件生命周期。它通过类比Java类的生命周期来讲解React组件，这个方法非常有效。我相信只有既熟悉前端又熟悉后端的人才能如此解释，而GPT的回答如此自然。﻿</p><p>同样，当我们尝试用类比（如将state与Java的成员变量进行比较）来理解新知识时，它会给我们提供更丰富的建议，更深入的解释，以及更多样的案例。﻿</p><p>反馈对于学习的重要性，毋庸再言。在这一阶段，大模型同样展现出强大的能力。</p><ul><li><strong>实时反馈：</strong>大型模型能够提供即时反馈，让学习者在学习过程中随时了解自己的表现。例如，当我们完成一段代码或者一个功能时，大型模型可以立即进行审查并提供改进建议。这并不止是效率的提升，更重要的是，它可能会引发更深层的变革。</li></ul><p>学习是反人性的，人类也并不擅长学习，重要的原因是学习过程充满未知，可预期性差。尽管人类天生好奇，但遗憾的是这种好奇心并不能维持很长时间。聪明的教育者会运用各种技巧来提升学习的可预期性（更明确的奖赏），以尽可能地延长好奇心的持续时间。</p><p><strong>提升反馈效率不仅表面上会提升效率，同时也会提升学习的可预期性，可能大模型会使学习这件事情不那么反人性。</strong></p><ul><li><strong>多样化的案例：</strong>大模型能够提供多种多样的案例，甚至我们可以用大模型创造案例；</li></ul><p>面向未来</p><h2 id="-3"><a href="#-3" class="headerlink" title=""></a></h2><p><strong>既然模型“全知全能”，我们还要不要学习知识？</strong></p><h3 id="-4"><a href="#-4" class="headerlink" title=""></a></h3><p>答案是肯定的：我们仍然需要学习知识。</p><p>多年前就有人提出了一个类似的问题：“在现代社会，为什么我们需要记忆呢？我们可以在几秒钟内通过互联网查找到任何需要的事实性信息。”这并不是大数据模型时代特有的问题。我认为，我们仍然需要学习，并应该利用大数据模型来加速学习进程。﻿</p><p>首先，<strong>知识是思考的基础，没有知识就无法谈论分析能力或批判性思维等高级能力。</strong>许多人认为思考过程类似于计算器的功能，计算器具有一系列的函数（如加法、乘法等），这些函数可以应用于任何数据。它的数据和函数是完全分开的。因此，一旦学习了新的函数，就可以处理所有的数字。</p><p>然而，人类的思考方式并非如此，至少对大多数人来说，功能（模型）和数据是无法完全分离的。例如，我们能够批判性地思考欧洲地缘政治如何导致第二次世界大战，并不意味着我们也能批判性地思 考中东当前的局势。再比如，我们知道在使用金字塔模型进行分类时，应确保每个分类之间既无重叠也无遗漏。然而，即使我们在某个领域成功实现了这一点，但在仅仅理解模型的情况下，并不能保证在另一个领域也能做到无重无漏。﻿</p><p>其次，<strong>通过知识的学习，可以提高我们的记忆力。</strong>我们把人脑分成工作记忆和长期记忆，<strong>工作记忆的空间是有限的，它的上限决定了我们的推理能力。</strong>这一点其实也很容易理解，当我们涉足到非常专业的领域时，会遇到大量的专有名词。例如，在营销运营领域，我们会遇到像“招选搭投”、“盘货池”这样的专有名词。这些名词都包含大量的背景知识。如果我们不清楚这些知识，我们根本是无法讨论问题（判断、推理、分析、决策等）的。</p><p>让我们想象一下，在不熟悉背景知识的情况下，我们如何探讨“直接将盘货池暴露给搭建页面是否合理？”时，首先，我要解释一下什么是盘货池，它是根据特定的商品指标规则圈选的商品集合。然后，我会介绍什么是搭建，在这一通输出之后，估计大家的脑子已经炸了。可是，我们还没有开始讨论真正有意义的内容。</p><p><strong>发散一下：这种情况是不是跟当今的大模型所遇到的困境非常像？</strong></p><p>实际上，我们可以通过学习知识来解决这个问题。我们可以将知识压缩成一小块一小块，然后存入长期记忆中。当我们需要时，可以随时调取。例如，当我提到”盘货池”这个概念，我们的脑海中立刻会想到”按指标圈选的商品集合”。而且，我们还可以联想到更多，例如它的存储形式，它在数据流向中的位置等等。我们能联想到的内容完全取决于我们的大脑中存储了多少信息。这样，<strong>我们就大大节省了工作记忆空间，从而变相地突破了工作记忆空间的限制。</strong>另外，学习知识还能更容易地触发长期记忆，也就是说，学得越多，记忆力越好。由于篇幅原因，我就不再详细说明这一点了。﻿</p><p><strong>在大模型时代，要怎么学习？</strong></p><h3 id="-5"><a href="#-5" class="headerlink" title=""></a></h3><p>前面，花了大量的篇幅在论证，我们要不要学习，接下来，我们阐述一下，应该怎么学习。﻿</p><h4 id="与机器赛跑，仅仅靠技能型学习是不够的"><a href="#与机器赛跑，仅仅靠技能型学习是不够的" class="headerlink" title="与机器赛跑，仅仅靠技能型学习是不够的"></a>与机器赛跑，仅仅靠技能型学习是不够的</h4><p>模型最擅长的是什么？显然，大型模型在重复型技能学习方面表现出色。无论是对某种模式的判断，还是执行某些套路化的动作，模型都能高效而准确地完成。在这些领域，人类难以与大模型竞争。</p><p>令人沮丧的是，这些技能我们并不能抛弃，并且他们非常重要。就像篮球运动员必须具备扎实的基本功，才能完成复杂的动作一样，<strong>基本技能是我们掌握高级能力的基础。没有这些基本技能，任何高层次的应用和创新都无从谈起。</strong></p><p>然而，在这个时代，仅仅依赖这些基本技能是不够的。面对“与机器赛跑”的挑战，我们需要培养更高等级的能力，如分析、判断、决策和创新。这些能力能够让我们在与大模型的竞争中脱颖而出。</p><p>未来也不全是坏事儿，值得高兴的是，<strong>在大模型的加持下，技能型学习过程将显著加快</strong>，从而提高这一阶段的学习效率。通过高度整合的、定制化的知识，提供多样化的案例，并及时给予学习者反馈，学习者可以更快地掌握基本技能。这不仅节省了大量的时间和精力，同时也使我们能够将更多的资源投入到更高层次的分析、判断和创新中，促进整体学习效果的提升。</p><h4 id="要从技能型学习到专家型学习的转变"><a href="#要从技能型学习到专家型学习的转变" class="headerlink" title="要从技能型学习到专家型学习的转变"></a>要从技能型学习到专家型学习的转变</h4><p>专家型学习这个概念不太容易定义，首先解释一下什么是专家能力，以帮助大家理解什么是专家型学习。</p><p>不要误解，此专家非彼专家。</p><p>首先，<strong>专家具备概念框架和分析能力。</strong></p><p>当专家面对一个问题时，他们首先会运用概念框架来锚定问题的类型。例如，在处理一个需要在多个服务器之间共享数据的系统时，专家首先会锚定这是一个分布式问题，然后再进一步锚定是分布式当中数据一致性的问题，其后才会着手解决数据如何在不同节点之间实现一致。</p><p>其次，<strong>专家能够清晰地识别模式、关系和差异。</strong></p><p>这一点或许有些抽象。专家不仅能应用概念模型，还能在复杂情境中看清楚各方关系和角色。比如，在设计复杂的软件系统时，专家能识别核心服务和辅助服务，理解它们如何协同工作，并优化接口和数据流。他们能预见扩展系统时的挑战，并提前设计解决方案。﻿</p><p>再次，<strong>专家具备扎实的基础知识，并能够顺畅地提取和运用这些知识。</strong></p><p>扎实的基础是专家型学习的基石。假设一个人连基本的概念都无法理解，就无法指望他能深入分析和解决问题。﻿</p><p>那么，什么是专家型学习，或者换句话说，如何通过学习达到专家能力？</p><p>扎实的基础知识是专家型学习的第一步，这一步是可以通过系统的学习和反复练习来实现的。然而，令人沮丧的是，后续的高级能力——如分析能力、系统化思维、批判性思维、决策和创新等——并不能通过简单的学习获得。</p><p>这些高级能力需要大量实践来培养，<strong>我相信阿里的“借事修人”的理念，但是这首先需要我们“躬身入局”</strong>。具体来说，主动承担有挑战性的任务，尝试跨领域学习和应用，迫使自己运用高级能力；持续反思和总结经验，改进策略，不断输出，寻求反馈；这样才有可能将高级能力内化为自己的技能。</p><h4 id="软实力从来没有变得像今天那么重要"><a href="#软实力从来没有变得像今天那么重要" class="headerlink" title="软实力从来没有变得像今天那么重要"></a>软实力从来没有变得像今天那么重要</h4><p>在现今社会，许多技术性的任务可能被机器取代，但判断和决策仍然需要人来完成。因此，在可预见的未来，软实力（沟通能力、同理心、逆商、团队精神、领导力等）的重要性将变得更为突出，比以往任何时候都更为关键。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247539111&amp;idx=1&amp;sn=ef5e1cd2237732f2af4b515dbb66e26f&amp;&quot;&gt;跟着ChatGPT4o学全栈，我看到未</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>mac软件汇集(转载)</title>
    <link href="https://imlike.cc/27d3a647.html"/>
    <id>https://imlike.cc/27d3a647.html</id>
    <published>2025-03-07T02:46:10.000Z</published>
    <updated>2025-04-09T07:47:42.467Z</updated>
    
    <content type="html"><![CDATA[<p>转载地址 <a href="https://weekly.howie6879.com/soft/mac.html">https://weekly.howie6879.com/soft/mac.html</a></p><h1 id="mac-soft"><a href="#mac-soft" class="headerlink" title="mac-soft"></a>mac-soft</h1><blockquote><p>记录我在使用 <code>macOS</code> 过程中使用&amp;看到的软件项目，本文会持续更新，同时也开源在 <a href="https://github.com/howie6879/mac-soft">GitHub</a>，欢迎 <code>Star</code> ❤️</p></blockquote><h2 id="基础工具"><a href="#基础工具" class="headerlink" title="基础工具"></a>基础工具</h2><ul><li><p>Alfred</p><p>：本地搜索及应用快速启动，替代品：</p><ul><li><a href="https://github.com/raycast/extensions">Raycast</a>：目前免费状态，这是其开源插件仓库</li><li><a href="https://github.com/cerebroapp/cerebro">Cerebro</a>：开源替代品</li></ul></li><li><p><a href="https://github.com/kyleneideck/BackgroundMusic">BackgroundMusic</a>：音频管理工具，可以管控各个 <code>APP</code> 的音量（开源）</p></li><li><p><a href="https://web.archive.org/web/20150322050645/http://ftnew.com/files/CatchMouse.zip">CatchMouse</a>：多显示器切换软件，根据快捷键快速切换到目标显示器（免费）</p></li><li><p><a href="https://github.com/pqrs-org/Karabiner-Elements">Karabiner-Elements</a>：键盘键位修改神器，特别针对有多款键盘的人（开源）</p></li><li><p><a href="https://github.com/leaves615/KeyboardHolder">KeyboardHolder</a>：一款补足 <code>macOS</code> 自带有一个自动切换到文稿到输入法功能遗憾的软件（免费）</p></li><li><p><a href="https://github.com/noah-nuebling/mac-mouse-fix">mac-mouse-fix</a>：轻量级鼠标控制功能定制软件（开源）</p></li><li><p><a href="https://mounty.app/">Mounty</a>：一款 <code>NTFS</code> 格式读写工具</p></li><li><p><a href="https://github.com/Caldis/Mos">Mos</a>：一个平滑你的鼠标滚动效果或单独设置滚动方向的小工具，让你的滚轮爽如触控板（开源）</p></li><li><p><a href="https://peazip.github.io/">peazip</a>：解压缩工具（开源）</p></li><li><p><a href="https://github.com/rxhanson/Rectangle">Rectangle</a>：多窗口管理工具（开源）</p></li><li><p><a href="https://github.com/avibrazil/RDM">RDM</a>：轻松将 <code>Mac Retina</code> 显示器设置为更高的分辨率（开源）</p></li></ul><h2 id="系统管理"><a href="#系统管理" class="headerlink" title="系统管理"></a>系统管理</h2><ul><li><p><a href="https://github.com/lwouis/alt-tab-macos">AltTab</a>：<code>AltTab</code> 将 <code>Windows</code> 的 <code>Alt-Tab</code> 窗口切换器带到 <code>MacOS</code>（开源）</p></li><li><p>Bartender</p><p>：方便的状态栏管理工具，开源替代品有：</p><ul><li><a href="https://github.com/Mortennn/Dozer">Dozer</a></li><li><a href="https://github.com/dwarvesf/hidden">hidden</a></li></ul></li><li><p><a href="https://github.com/balena-io/etcher">balenaEtcher</a>：镜像制作工具（开源）</p></li><li><p><a href="https://www.cakebrew.com/">cakebrew</a>： 如果使用 <code>Homebrew</code> 的话，可以使用这款来进行管理（开源）</p></li><li><p><a href="https://github.com/gao-sun/eul">eul</a>：系统状态监控工具（开源）</p></li><li><p><a href="https://justgetflux.com/news/pages/macquickstart/">flux</a>：一款比较好的免费屏幕护眼软件</p></li><li><p><a href="https://github.com/newmarcel/KeepingYouAwake">KeepingYouAwake</a>：根据自己的需求设置 <code>Mac</code> 多少分钟/多少小时后进入睡眠</p></li><li><p><a href="https://maccy.app/">Maccy</a>：剪贴板管理（开源）</p></li><li><p><a href="https://github.com/MonitorControl/MonitorControl">MonitorControl</a>：控制外部显示器的亮度和音量（开源）</p></li><li><p><a href="https://github.com/jacklandrin/OnlySwitch">OnlySwitch</a>：系统功能快速开关工具（开源）</p></li><li><p><a href="https://www.parallels.com/">Parallels Desktop</a>：能让您在 <code>Mac</code> 上同时使用 <code>Windows</code> 等系统</p></li><li><p><a href="https://github.com/sbarex/SourceCodeSyntaxHighlight">SourceCodeSyntaxHighlight</a>：增强文件预览（开源）</p></li><li><p><a href="https://tunnelblick.net/">Tunnelblick</a>：<code>OpenVPN</code> 客户端（开源）</p></li><li><p><a href="https://lemon.qq.com/">腾讯柠檬</a>：腾讯出品的系统清理工具（开源）</p></li></ul><h2 id="编程开发"><a href="#编程开发" class="headerlink" title="编程开发"></a>编程开发</h2><ul><li><p><a href="https://www.anaconda.com/">Anaconda</a>：数据科学常用 <code>Python</code> 环境管理程序</p></li><li><p><a href="https://github.com/ObuchiYuki/DevToysMac">DevToysMac</a>：程序员常用工具集（开源）</p></li><li><p><a href="https://www.docker.com/">Docker</a>：用容器化的形式使用一些常用软件，推荐使用 <a href="https://github.com/portainer/portainer">portainer</a> 管理（开源）</p></li><li><p><a href="https://github.com/macvim-dev/macvim">MacVim</a>：文本编辑器（开源）</p></li><li><p>Offset Explorer</p><p>：个人免费的跨平台</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Kafka</span><br></pre></td></tr></table></figure></li></ul><p>  界面管理工具，</p><ul><li><p><a href="https://github.com/provectus/kafka-ui">kafka-ui</a>：<code>Web</code> 自部署，简洁好用、速度快、颜值高（开源）</p></li><li><p><a href="https://code.visualstudio.com/">VSCode</a>：微软出品的免费跨平台代码编辑器（开源）</p></li><li><p>终端：</p><ul><li><a href="https://github.com/electerm/electerm">electerm</a>：一款基于 <code>Electron</code> 开发的 <code>SSH/SFTP</code> 跨平台客户端、（开源）</li><li><a href="https://iterm2.com/">Iterm2</a>：免费好用的终端工具，一般搭配 <code>Brew</code> 和 <code>ZSH</code> 使用</li><li><a href="https://github.com/Eugeny/tabby">tabby</a>：一个可高度配置的终端模拟器和 <code>SSH</code> 或串口跨平台客户端（开源）</li><li><a href="https://github.com/kingToolbox/WindTerm">WindTerm</a>：基于 <code>C</code> 语言开发的的专业级替代品（开源）</li></ul></li><li><p>数据库：</p><ul><li>通用：<ul><li><a href="https://github.com/beekeeper-studio/beekeeper-studio">beekeeper-studio</a>：跨平台的 <code>SQL</code> 编辑器和数据库管理器（开源）</li><li><a href="https://github.com/dbeaver/dbeaver">DBeaver</a>：为开发人员、<code>SQL</code> 程序员、数据库管理员和分析人员提供的免费多平台数据库工具，有 <code>JDBC</code> 驱动即可支持使用（开源）</li><li><a href="https://github.com/dbgate/dbgate">dbgate</a>：支持 <code>Mysql、Postgresql、SQL Server、Mongodb、Redis、SQLite</code> 等数据库的管理软件，同时也满足在 <code>Windows、Linux、Mac Web</code> 下运行，还提供插件体系（开源）</li></ul></li><li>Elasticsearch：<ul><li><a href="https://github.com/1340691923/ElasticView">ElasticView</a>：简单好用的 <code>ES</code> 可视化客户端，支持连接6，7，8版本（开源）</li><li><a href="https://opensource.appbase.io/mirage/">appbaseio/mirage</a>：用于简化 <code>ES</code> 查询语句编写的项目，你可以用基于块的交互形式来组成 <code>Elasticsearch</code> 查询语句（开源）</li><li><a href="https://github.com/cars10/elasticvue">elasticvue</a>：基于 <code>Vue</code> 的 <code>Elasticsearch</code> 管理客户端，支持<a href="https://chrome.google.com/webstore/detail/elasticvue/hkedbapjpblbodpgbajblpnlpenaebaa/related?utm_source=chrome-ntp-icon">浏览器插件</a>和 <code>Docker</code> 自建（开源）</li></ul></li><li>MongoDB：<ul><li><a href="https://github.com/mongo-express/mongo-express">mongo-express</a>：可自建的 <code>MongoDB</code> 数据库管理软件，针对线上数据库需要共享的需求，可以统一部署在一台服务器给所有员工用，然后设置只读模式，非常实用（开源）</li><li><a href="https://github.com/Studio3T/robomongo">Robo 3T</a>：<code>MongoDB</code> 数据库管理软件（开源）</li></ul></li><li>MySQL：<ul><li><a href="https://github.com/Sequel-Ace/Sequel-Ace">Sequel-Ace</a>：原生的 <code>MySQL/MariaDB</code> 数据库管理软件（开源）</li></ul></li><li>Redis：<ul><li><a href="https://github.com/qishibo/AnotherRedisDesktopManager">AnotherRedisDesktopManager</a>：跨平台的 <code>Redis</code> 桌面管理客户端，性能出众（开源）</li><li><a href="https://github.com/Kuari/RedisFish">RedisFish</a>：一款便捷、跨平台、专注于数据的 <code>Redis GUI</code> 客户端（开源）</li></ul></li><li>PostgreSQL：<ul><li><a href="https://github.com/pgadmin-org/pgadmin4">pgadmin4</a>：跨平台的 <code>PostgreSQL</code> 数据库管理软件（开源）</li></ul></li><li>SQLite：<ul><li><a href="https://github.com/sqlitebrowser/sqlitebrowser">sqlitebrowser</a>：<code>DB4S</code> 是一个高质量、可视化、开源的工具，用于创建、设计和编辑与 <code>SQLite</code> 兼容的数据库（开源）</li></ul></li></ul></li><li><p>API 请求调试：</p><ul><li><a href="https://github.com/hoppscotch/hoppscotch">hoppscotch</a>：基于 <code>Web</code> 提供服务（开源）</li><li><a href="https://github.com/Kong/insomnia">insomnia</a>：跨平台 （开源）</li><li><a href="https://www.postman.com/">Postman</a>：比较老牌的 <code>API</code> 接口功能测试工具</li><li><a href="https://github.com/star7th/showdoc">showdoc</a>：一个非常适合 IT 团队的在线 <code>API</code> 文档、技术文档工具（开源）</li><li><a href="https://marketplace.visualstudio.com/items?itemName=rangav.vscode-thunder-client">Thunder Client</a>：如果使用<a href="https://code.visualstudio.com/">VSCode</a>，推荐使用这款插件 💡</li></ul></li></ul><h2 id="浏览娱乐"><a href="#浏览娱乐" class="headerlink" title="浏览娱乐"></a>浏览娱乐</h2><ul><li><a href="https://www.aliyundrive.com/">aliyundrive</a>：阿里云盘</li><li><a href="https://github.com/blogwy/BilibiliVideoDownload">BilibiliVideoDownload</a>：跨平台下载 <code>bilibili</code> 视频桌面端软件（开源）</li><li><a href="https://www.google.com/chrome/">Chrome</a>：浏览器</li><li><a href="https://github.com/iina/iina">iina</a>：现代化的视频播放器（开源）</li><li><a href="https://apps.apple.com/us/app/irvue/id1039633667?mt=12">Irvue</a>：基于 Unsplash 的免费壁纸切换工具</li><li><a href="https://www.mowglii.com/itsycal/">itsycal</a>：一款简单优雅的菜单栏日历（开源）</li><li><a href="https://github.com/justinfrankel/licecap">licecap</a>：轻量小巧的录屏工具（开源）</li><li>沟通：<a href="https://weread.qq.com/">微信</a> | <a href="https://www.dingtalk.com/">钉钉</a> | <a href="https://telegram.org/">TG</a></li><li><a href="https://www.stellarplayer.com/">恒星播放器</a>：一款纯粹专注的播放器</li><li><a href="https://music.163.com/">网易云音乐</a>：推荐一款开源替代品 <a href="https://github.com/qier222/YesPlayMusic">YesPlayMusic</a></li></ul><h2 id="阅读写作"><a href="#阅读写作" class="headerlink" title="阅读写作"></a>阅读写作</h2><ul><li><a href="https://ripperhe.gitee.io/bob/#/">Bob</a>：翻译工具（开源，但是正式版买断收费）</li><li><a href="https://github.com/yang991178/fluent-reader">fluent-reader</a>：<code>RSS</code> 阅读器（开源）</li><li><a href="https://joplinapp.org/">Joplin</a>：跨平台笔记管理工具，有不错的社区支持（开源）</li><li>Pngyu](<a href="https://joplinapp.org/)%EF%BC%9A%E5%85%8D%E8%B4%B9%E7%9A%84PNG%E5%9B%BE%E7%89%87%E5%8E%8B%E7%BC%A9%E5%B7%A5%E5%85%B7%EF%BC%8C%E5%90%8C%E6%A0%B7%E5%A5%BD%E7%94%A8%E7%9A%84%E8%BF%98%E6%9C%89%EF%BC%9A">https://joplinapp.org/)：免费的PNG图片压缩工具，同样好用的还有：</a><ul><li><a href="https://github.com/kyleduo/TinyPNG4Mac">TinyPNG4Mac</a>（开源）</li><li><a href="https://imageoptim.com/mac">ImageOptim</a>（开源）</li></ul></li><li><a href="https://typora.io/releases/all">Typora</a>：比较经典的所见即所得 <code>Markdown</code> 编辑器（提供免费版）</li><li><a href="https://github.com/gee1k/uPic">uPic</a>：原生的图床管理工具（开源）</li><li><a href="https://xnipapp.com/">Xnip</a>：挺不错的截图软</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;转载地址 &lt;a href=&quot;https://weekly.howie6879.com/soft/mac.html&quot;&gt;https://weekly.howie6879.com/soft/mac.html&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;mac-soft&quot;&gt;&lt;a href=&quot;#</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>如何找出Java进程占用CPU高的元凶(转发)</title>
    <link href="https://imlike.cc/129d01fc.html"/>
    <id>https://imlike.cc/129d01fc.html</id>
    <published>2025-01-18T07:04:12.000Z</published>
    <updated>2025-01-18T07:15:56.842Z</updated>
    
    <content type="html"><![CDATA[<p>转发: <a href="https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247543282&idx=1&sn=b0b3d858b70c49c996221d265fa0fecf&chksm=e86b7b221aface2870c9b4217eeffd4e8e0c953937bf8492e7f83fb102260f922a39c2f11da1&mpshare=1&scene=24&srcid=12059mpwWmSG7Rse36RT6hp5&sharer_shareinfo=788a814db98d7ed844f50438fa229815&sharer_shareinfo_first=788a814db98d7ed844f50438fa229815#rd">如何找出Java进程占用CPU高的元凶</a></p><p>开发的时候登录OSS控制台预发机器，发现Java进程CPU占用率其高，按道理预发机器只是内部开发及产品会使用，根本不可能占用这么大的资源，第一反应就是，进程在某个地方死循环了。</p><p><img src="../img/640.webp" alt="图片"></p><p>二、调查</p><p>猜测归猜测，还是要用事实说话。</p><p>第一步：top -Hp 15057 查看下进程中的线程资源占用情况</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLbC5OYRrb96ib9NtMYx13mBXNRQ4Wo5qgtqRX3aGuGP5F3S2tylTgOIkZ0oAKib5S95rCHT5dndtLw/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>由上图可见，CPU时间片主要是被15393 这个线程给吃掉了， 所以目标锁定在 15393。</p><p>执行 printf “%x\n” 15393，计算出线程ID对应的16进制。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLbC5OYRrb96ib9NtMYx13mB1qn6Mibf92Gdo9tTVV1fIY17TLhZZ8lpO7BblibVJYxZAic33hUrAUJzQ/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>第二步：执行 sudo -u www jstack 15057，获取当前进程中各线程的调用栈</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLbC5OYRrb96ib9NtMYx13mBpQZSuJsBib6ic8L3YDZgibNp7XcCITDrzpH85yTWYqZKjOJjfb1PLoib3A/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>对比之前计算出来的二进制id：3c21，找到占用CPU资源最高的线程堆栈，如上图所示。</p><p>看样子是在LoguUtil的255行出了问题，赶紧定位到这一行看看：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLbC5OYRrb96ib9NtMYx13mBbW0MKG09EfsWlprtvrSvxOF8gLCaibwfSL75iaCp9AIHv7icKB6PMmuibw/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>这里写了一个死循环，并在255行调用了阻塞队列的poll（），很明显，方法调用错了，poll（）在队列会空的时候会直接返回null，并不会阻塞等待，所以造成进程一直在这儿死循环。</p><p>那么为什么测试的时候没有发现呢？因为只要有日志，代码很难走到255行，之所以能发现这个问题，是因为我登录机器这段时间是在深夜，刚好没有日志。</p><p>三、验证</p><p>将代码修改提交部署后，在登录机器看看CPU占用情况：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLbC5OYRrb96ib9NtMYx13mB6LbLXY614icHcFic4UkmrhQOibcxGJe9mZgOcwYSgynahzOHhjecmoQHQ/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>此时Java进程的CPU占用已经恢复正常了。</p><p>四、总结</p><p>平时开发需求，除了验证基本的功能完整性之外，一定要注意对性能的影响，及时发现并解决问题。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;转发: &lt;a href=&quot;https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247543282&amp;idx=1&amp;sn=b0b3d858b70c49c996221d265fa0fecf&amp;chksm=e86b7b221af</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>mysql连接问题</title>
    <link href="https://imlike.cc/22281c22.html"/>
    <id>https://imlike.cc/22281c22.html</id>
    <published>2025-01-18T06:52:45.000Z</published>
    <updated>2025-01-18T07:15:56.841Z</updated>
    
    <content type="html"><![CDATA[<p>在使用 bitnami 的镜像来搭建 mysql 的集群环境,但是突然驱动出现了问题,进入容器对于的那台机器查询对于的命令</p><blockquote><p>/opt/bitnami/mysql/bin/mysqld –defaults-file=/opt/bitnami/mysql/conf/my.cnf –basedir=/opt/bitnami/mysql –datadir=/ bitnami/mysql/data –socket=/opt/bitnami/mysql/tmp/mysql.sock –bind-address=127.0.0.1 –skip-slave-start –upgrade=force</p></blockquote><p><img src="../img/image.png"></p><p>研究了一通是因为  –upgrade=force ,目前由于我们是bitnami集群时[<a href="https://github.com/bitnami/containers/issues/44854">bitnami/mysql] installed in the k8s cluster keeps prompting that the upgrade fails after restarting · Issue #44854 · bitnami/containers</a></p><p>同时在容器中常见的命令地址如下</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;opt&#x2F;bitnami&#x2F;scripts&#x2F;mysql&#x2F;entrypoint.sh </span><br><span class="line">&#x2F;opt&#x2F;bitnami&#x2F;scripts&#x2F;mysql&#x2F;run.sh</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在使用 bitnami 的镜像来搭建 mysql 的集群环境,但是突然驱动出现了问题,进入容器对于的那台机器查询对于的命令&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;/opt/bitnami/mysql/bin/mysqld –defaults-file=/opt/bitna</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>java线程池注意事项</title>
    <link href="https://imlike.cc/8a4449c5.html"/>
    <id>https://imlike.cc/8a4449c5.html</id>
    <published>2025-01-18T06:46:39.000Z</published>
    <updated>2025-01-18T07:15:56.841Z</updated>
    
    <content type="html"><![CDATA[<p>java 线程池使用的人很多,通常情况下为了不注册当前的线程的执行,同时提升执行的效率</p><p>但是需要有时候使用不当回出现意想不到的问题,不如下面这种问题</p><p><a href="https://javaguide.cn/java/concurrent/java-thread-pool-best-practices.html#spring-%E5%86%85%E9%83%A8%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E5%9D%91">Java 线程池最佳实践 | JavaGuide</a></p><p><a href="https://javaguide.cn/java/concurrent/java-thread-pool-best-practices.html#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%92%8C-threadlocal-%E5%85%B1%E7%94%A8%E7%9A%84%E5%9D%91">线程池和 ThreadLocal 共用的坑</a></p><p>在线程池中使用了比如 springMVC中设置了 ThreadLocal方便其他的线程使用,但是有几个问题,上一次设置的ThreadLocal 变量可能会被覆盖导致,拿不到想要的值.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;java 线程池使用的人很多,通常情况下为了不注册当前的线程的执行,同时提升执行的效率&lt;/p&gt;
&lt;p&gt;但是需要有时候使用不当回出现意想不到的问题,不如下面这种问题&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://javaguide.cn/java/concurrent/ja</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>quartz使用问题</title>
    <link href="https://imlike.cc/81077f05.html"/>
    <id>https://imlike.cc/81077f05.html</id>
    <published>2025-01-18T06:32:13.000Z</published>
    <updated>2025-01-18T07:15:56.842Z</updated>
    
    <content type="html"><![CDATA[<p>接手公司的代码在使用 quartz 中使用了,最近在开发新功能,突然任务都阻塞的,后面发现是是因为改动了一部分代码导致执行了这部分代码</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">trigger &#x3D; TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME).startAt(startTime).endAt(endTime).build(); </span><br><span class="line"></span><br></pre></td></tr></table></figure><p>远程访问线程后显示我没有设置withSchedule 导致一直访问</p><blockquote><p>SELECT * FROM T_QRTZ_LOCKS WHERE SCHED_NAME = ‘quartzScheduler_dq’ AND LOCK_NAME = ‘TRIGGER_ACCESS’ FOR UPDATE</p></blockquote><p>研究了一下在 Quartz 调度框架中，触发器（Trigger）是用于定义任务的启动、结束时间、重复执行间隔等细节的。当没有设置 <code>withSchedule</code> 时，Quartz 默认的行为是认为这个触发器是一个“一次性”触发器，即在 <code>startAt</code> 指定的时间启动，并且不会重复执行。</p><p>然而，<code>T_QRTZ_LOCKS</code> 表格是 Quartz 用来管理锁和调度状态的数据库表，<code>LOCK_NAME = &#39;TRIGGER_ACCESS&#39;</code> 说明当前 Quartz 调度器正在尝试获取对某个资源的锁，可能是在创建或执行触发器时遇到了并发问题。具体来说，这种情况可能是由于以下原因导致的：</p><ol><li>锁的竞争：创建的触发器没有明确的调度计划（例如，没有设置 <code>withSchedule</code>），可能导致 Quartz 试图获取资源的锁，而该锁在其他地方已经被占用。Quartz 会用数据库表 <code>T_QRTZ_LOCKS</code> 来保证分布式环境中不同调度器的协调，防止重复执行。正在尝试访问的锁是 <code>TRIGGER_ACCESS</code>，Quartz 在执行时检查并锁定资源，以防止多个实例同时执行同一个任务。</li><li>没有指定调度计划（Schedule）：如果没有设置 <code>withSchedule</code>，Quartz 会认为这个任务没有重复执行的计划，这意味着每次启动时，Quartz 可能会频繁地访问锁，造成资源竞争。</li></ol><h3 id="目前解决方案："><a href="#目前解决方案：" class="headerlink" title="目前解决方案："></a>目前解决方案：</h3><ul><li><p>设置触发器的调度计划：可以使用 <code>withSchedule</code> 来设置触发器的调度计划</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">trigger &#x3D; TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME).startAt(startTime).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(60)  &#x2F;&#x2F; 每60秒执行一次.repeatForever())  &#x2F;&#x2F; 重复执行.build();&#96;</span><br></pre></td></tr></table></figure></li></ul><ul><li>检查并发执行：如果系统是分布式的，确保 Quartz 实例之间的锁定机制正常工作。Quartz 通过数据库锁来防止多个调度器同时处理同一个任务，确保任务的唯一执行。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;接手公司的代码在使用 quartz 中使用了,最近在开发新功能,突然任务都阻塞的,后面发现是是因为改动了一部分代码导致执行了这部分代码&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pr</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>技术债务治理(转载)</title>
    <link href="https://imlike.cc/25cadf25.html"/>
    <id>https://imlike.cc/25cadf25.html</id>
    <published>2025-01-11T05:17:55.000Z</published>
    <updated>2025-09-07T07:49:53.195Z</updated>
    
    <content type="html"><![CDATA[<p>转载: <a href="https://jbfhxmeaps.feishu.cn/docx/M8qXdYOYJoMaJbx9VK7c9dIknig">‌⁢⁤‍⁢⁢⁤⁤⁡‬⁣‍‬‌⁢﻿‍⁣⁤‬‬‍⁤⁢⁤‬⁤⁡⁢‍‬⁣‬⁢‬‍﻿‍⁢⁤<a href="https://mp.weixin.qq.com/s/l3uj5r2zWuPoJRT0fqWOrA">聊一下，技术债务治理</a></a></p><p>在现代软件开发中，技术债务（Technical Debt）已成为一个不可忽视的重要概念。它指的是在软件开发过程中，为了追求短期目标而做出的妥协，导致未来需要付出额外成本来修复这些妥协所带来的问题。技术债务的管理不仅影响项目的质量和可维护性，还直接关系到团队的工作效率和公司的长期发展。</p><p><strong>什么是技术债务？</strong></p><p>技术债务的定义可以追溯到Ward Cunningham，他将其比喻为“借款”，即在软件开发中选择了一个较为简单的解决方案，而非最佳实践。这种选择虽然在短期内能加快开发进度，但却可能在未来导致更高的维护成本和更复杂的技术问题。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MDUxY2E4NThhMDY5OGUyN2EyNmNmNmRlMmMzMmVhNjFfYjBtTWQ4b3gzZXduSHJUODhZNkhDME1hNnZUOG1oRTNfVG9rZW46TThKNGJYb3Y3bzJVbEN4Y0xmYWNBSUgzbjNkXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>为了提升需求开发速度，我们有时会在应当采纳最佳方案时作出妥协，转而选择那些短期内能迅速推进项目进程的方案。然而，这种做法往往会导致未来的错误问题增多，并给自己带来额外的开发负担。这种技术层面的抉择，犹如背负了一笔债务。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YjNiZGRkYjc1OWM0YTYwMjI1ZjczMmRhYzJmZmZiNjBfaTZHYmhraU5MYUhzdFk1S29tUU5JN21DUWVaRUlOSDVfVG9rZW46UmdOOGJjUlJEbzVBekR4dnNjcmNNa0d4bjRiXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>技术债务的分类</strong></p><p>同样，技术债务也有其层次之分，通常根据其影响程度和解决的紧迫性，我们可以将其划分为四个象限，即技术债务的四象限模型。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NmYzN2VlZjJjODIyYTgyMzk1Y2Q2ZjU1NmZlMzhjZThfQ1RkVjdOb1dZWHF3blZuR21SdEc4ZzVBeTlpN3lCZlNfVG9rZW46UGYyT2JUdVhYb3dPa254WHp3TmNTWTRlbnBmXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>技术债务可以根据不同的标准进行分类：</p><p><strong>有意和无意两种：</strong></p><ul><li><strong>有意技术债务</strong> ：团队明确意识到当前的解决方案并非最佳选择，且计划在未来进行改进。</li><li><strong>无意技术债务</strong> ：团队在缺乏足够信息或经验的情况下做出的选择，往往潜伏较久，难以察觉。</li></ul><p><strong>鲁莽型和谨慎型：</strong></p><ul><li><strong>鲁莽技术债务</strong> ：由于缺乏规划和规范而产生的债务，通常会导致严重的后果。</li><li><strong>谨慎技术债务</strong> ：在项目进度中做出的合理妥协，虽然存在风险，但在可控范围内。</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YjE4NTQ3M2E3ZDBhMmYwODI4YTRhZjQzMGYwMjM5MDVfNjZvWnlTY0ZGck5xcU82ZWRONVBLZWRudWR3UnZURDBfVG9rZW46Qk5HRGI2ZTNGb3NrcHF4dnZ3QWNidlh6bmxnXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>技术债务全景图</strong></p><p>根据卡内基-梅龙大学软件工程研究所（SEI）的Robert Nord在《The Future of Managing Technical Debt》中提出的“技术债务全景图”，技术债务可以从多个维度进行分析：</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NDk3ZGU1OWM5YzIwOTk1MmU2OTQ2NjI2MTRmM2NkZjRfWmltUG5NcmZ1SGU1WmhTMFE1WnRSeEFmTEdnT2FaN2pfVG9rZW46SGFOUmJVTUk3b1ZQaVh4cXFkVWNYdTlibkxkXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>这张全景图清晰地展现了技术债务的多个层面，包括那些通常与架构相关联的债务、因环境变化而产生的技术差距型债务，以及主要由内部代码质量低下引起的小粒度技术债务。</p><p>此外，通过这张图，我们还可以洞察到两个重要的方向。</p><p><strong>可演进性</strong></p><p>本质上，架构的元特征描述的是软件架构在演进过程中趋于目标的能力。这种演进目标并不仅限于支撑功能快速迭代的灵活性，同样可以涵盖其他重要的架构属性，如高可用性和可扩展性。</p><p><strong>可维护性</strong></p><p>狭义上的代码问题主要涉及代码的易理解性、问题的易修复性，以及在现有基础上的易扩展性。这些因素共同影响着代码的质量和可维护性。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MjBmYmUwYWRkNmI2MzMwN2EwNmE3ZmNlNDk2YjdkODVfWlp0WUNkcE5NNE43YTJaOFZjTUtsWHJUSENXV0dvYm9fVG9rZW46SzJYR2J6VVd5b0t2aWd4d2xCemNWV3FobjBmXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>背景</strong></p><p>当技术债务已经严重影响了公司的运作、工作的效率时，才会着手去处理这些方面的问题，可要付出的代价就太大了。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NzdiYTI1ZmNmOTcxNmQ0NGNmYjg0YjI0ODlhYzViNGRfdnI5TjdRaDFXMUVEZXJvNWthWHJJMWNObmpYMmVrZlhfVG9rZW46WHdVc2JlVVFnb2xFbFJ4cVNldWNFNzh0bmdiXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>随着滴滴国际化业务的快速发展，技术栈的多样化使得技术债务的管理变得愈发复杂。当前，研发所需的语言已不仅局限于平台原生语言，跨平台技术（如Flutter及其Dart语言）逐渐成为主流。这一转变带来了新的技术债务挑战，尤其是在代码质量和架构设计方面。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=OWMyODg1NDU3YzBkYmZlMmI4MTVmMTU3ZDI4OTQwZGNfaHduS2pPbnV5UVQ1OFhpTDVjN0VpM0FxcWRhemNPMklfVG9rZW46WmZpS2I2aGoyb2Q1MW54ZWpoSmNlOVZtbnpjXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>演绎过程</strong></p><p>在项目的初期阶段，我们面临着快速上线和快速迭代的压力，因此问题的积累是不可避免的。然而，随着我们的不断发展，我们意识到如果继续这种状态，将会对项目的质量和成本带来双重风险。同时，随着业务逐渐融入Flutter跨平台能力，我们在学习和研发Flutter的过程中，也遇到了诸多挑战。特别是随着Flutter SDK的不断升级，我们在这个过程中也积累了大量的技术债务，例如空安全适配问题。目前，我们的SDK版本支持2.12.0，这是一个允许空安全和非空安全混合的版本，因此存在很大的隐患。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=ODBjNTA5YzU1MmVhMTU5M2YxNDRhNjU1NzlkNWQ0YzVfdUF1T1prWm9iTTdXNzBEb05WOVc3ZEhwUXdpN0czR0VfVG9rZW46TUQ4UGJUdjAwb0dMZkR4cTB6bGNzM1ptbmNGXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>影响分析</strong></p><p><strong>对开发的影响</strong></p><p>也许某一天我们接收了一个陌生的模块，也许是自己曾经的代码，发现如同屎山一样，如下图，自己都看不懂了，为了应付快速迭代的需求，只能不停的往这上面堆，这个屎山也会愈发庞大和混乱，如果这样继续下去，知道某一天因为一个小小的Bug，你需要花半天的时间来排查问题出在哪里，最后当你觉得问题终于改好了的时候，却不料碰了不该碰的地方，结果就是 <strong>fixing 1 bug will create 10 new bugs</strong> ，甚至程序的崩溃。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=ZTc5YTg4YzQ3ZjNkMzU1ODljNWRjYWJmMWRiZDJmNDBfeFVWZGRhMXZNRDBNTU5sbHJ4TVlaVGx1WDhRc0l4WTlfVG9rZW46Sm9JeWJJcmRqb29Cd2l4STliUWNvbUZJbk9RXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>（图片由AI生成）</p><p>我们需要正确面对、积极面对这个事情，它不是没有技术含量，他能给我们带来更多的技术和业务上的挑战。</p><p><strong>对效率的影响</strong></p><p>技术债务的治理本质上是提升效率的过程。</p><p>治理不当将导致开发周期延长、资源浪费和团队士气下降。 <strong>因此，及时识别和解决技术债务是确保项目成功的关键。</strong></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=Mjg3NjYwYWQzOTc2ODBiYTQ0ZjczMDk4NTNjYTVlOTlfZERYa3NvbVJBOFRaMjZ4Qkd0dERTZGt4RldjUko5UVFfVG9rZW46RXpMMmJRaXBJb2dPMVJ4QVhrZ2NWUHVNbmdkXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YWEwM2EwZDZlZWVjYzk0Y2VhOGQ0OTNhMWFiMzE2ZDVfVDVpZmMwbFZhaTdWTVkwcUFrTmV0ZktjTnBiTG9ydk1fVG9rZW46VFY4d2JGemF5b21XbGt4cGVQR2NzVGRUbk1nXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>现状梳理</strong></p><p>业务发展至今，通过整理存量问题和结合监控报警沉淀的问题，可以看出目前工程存在的问题方向。 （非最全）</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NTRjZDlkZTJkMWJhZjk3MDdjNmIwZjQ1M2MyNzEyNTFfMEFUZUw5QUpGb2xsUkx5SzVRZXFJYUtFbERUajhUNlBfVG9rZW46VWtUSGJ1WXBOb0hLZ1l4dU5uWmMwNjhobmNmXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>代码复杂</strong></p><p>在快速迭代过程中，往往忽视了良好的代码组织与模块化设计，导致组件间出现高度耦合的现象。此外， 类 文件行数过长也是一个需要关注的问题。这些问题可能会影响代码的可读性和可维护性，进而降低开发效率。因此，我们需要重视代码结构的优化和模块化设计，以降低组件间的耦合度，并合理控制 类 文件行数，从而提高代码质量。</p><p><strong>架构混乱</strong></p><ul><li>业务架构在从初期到后期的迭代过程中，经历了逐步分化和尝试等阶段，尚未形成统一的结构走势。</li><li>目前存在新旧架构混合使用的情况。</li></ul><p><strong>代码风 格</strong></p><p>在Flutter跨平台代码中，代码结构和规范风格的不统一是一个常见问题。这主要是由于不同IDE的使用，很容易引发代码风格上的冲突，进而带来潜在的风险。为了提高代码的可读性和可维护性，降低风险，我们需要确保在整个代码库中保持一致的代码结构和规范风格。</p><p><strong>基建混乱</strong></p><p>在业务组件基建和服务基建方面，由于缺乏统一的最佳实践范式，导致使用层的代码出现混乱。这一问题亟待解决，以确保代码的整洁性和可维护性。</p><p><strong>工程效率</strong></p><p>管理缺乏统一性，功能分散，导致功能可用性低下。</p><p><strong>性能债务</strong></p><ul><li>解决由持续SDK升级触发的报警问题</li><li>优化内存管理</li><li>清理未使用的资源和已下架的代码</li><li>实施lint代码质量检查与治理</li><li>进行空安全适配（针对Flutter框架）</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=OGQ1NjZmZDMzYTFlM2EzN2ZjZTk3Y2ZhMTJhYWY5ZjVfNjhJTHdKMVRXTk8xT3lqUmNON0toUUZ3eVlTV0R2QVVfVG9rZW46U2U5OWJPaHEzb0U1dmh4MHVJZmNFUGxobm1GXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>目标</strong></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=OTE0NjEwMDVjNDBjMzYwNTliZmMzM2QyMTgzNmNjNTlfM24zYzBDVHdkSGVYOTdUcENOSmt1ZDVBT0lzN0dlYTFfVG9rZW46WjJFOGJ2RThvb0ZMSmp4VjgxMWNMSWpjbmpoXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>产物目标</strong></p><p><strong>一套简易可视化运营平台</strong></p><ul><li>结合Lean平台，对Lean平台录入信息，通过脚本产出自定义报告。</li><li>增加巡检能力，周频次跟进问题状态。</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MzAxMmI4OTJjNzE1MDE1MzJmYzEyYjBjMWQ1OGNjYWVfMm1XOXZXYmZMbVhJRXl4VnU5VDk4cFNUOFlJdWNjWGJfVG9rZW46SFdQRGJKczF0b3l0NW14UnpEVWMxYTVmbmxlXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>稳定性目标</strong></p><p><strong>沉淀问题，整合债务</strong></p><p>通过深入剖析问题和细致整合债务，将技术债务治理提升为确保系统稳定性的关键环节。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YmQ3OGY2MGMwM2Q5ZDcwYzM4YjA4YzkyZDc5ODkzNDVfM1NPOWt2Smh4ajBkcTNCSFlNSFVKRlVkUHZIWkE3SFJfVG9rZW46R0ZrUGJiODlTbzNlcXZ4WFdqNGNaRVBkblZoXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>质量目标</strong></p><p><strong>提高代码质量</strong></p><ul><li>提高代码质量，确保代码符合Lint标准。</li><li>完成Flutter的空安全适配 。</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NjE5MzM0MTU3ODdkZjQ4OWUyZDVlZjcwMmYzOWJlODNfZ25JNFI2clFtS0dScmRpbzJydENzSTlzNnVDaEpudXJfVG9rZW46SDlPMmJuVmN0b1FZUTJ4dzQ1QmNzeklUbjlmXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>面对挑战</strong></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MjE1N2NhMzRjNTc4MTUwOTAyN2E5NTNiODk1NjU2NTlfeDdOajFQSk5XY3gzUm54c2FxYWw4Rm9RWFZhN1BqMzVfVG9rZW46Qzg2eWJkTDZEb0tEc1R4U3RxdGNmYzl0bmliXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>业务挑战</strong></p><ul><li>稳定性的设计需要针对老业务流程进行二次梳理，如何保证线上稳定性是关键。</li><li>在需求中不断植入Fix的问题，确保技术债务的及时解决。</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NTkwZDA5YjczZjY4YWJiNzI5ZTZmNTdmYTEyMTJiNjZfbmZ1Q3N3cWRCYXppRTlSNXRwUDhnc1A3bmlUTnZUY1NfVG9rZW46UlhGWmJNZ0N2b25POHR4Nks0SmNZSkpJbjFHXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>技术挑战</strong></p><ul><li>优化思路和设计需要更全面的考虑。</li><li>如何通过架构设计更完美地落地修改和重构。</li><li>对技术的深入理解是实现更好方案的基础。</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MTAxZjEyZmFiYjIwMDEzYTNjMWMxYWE5OWMxMGUxYWJfaGxlM2pZWEE4eTVVUVlZVE5iOWZBZVFGalhrSzRUbnFfVG9rZW46SzRKU2I2MEU1b05wbnZ4WmlaZ2NKVHpIbmpzXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>治理方案</strong></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=Y2JlNWNjMDU2NTAyYWI5NDJlZTkxN2U2NDcxYTE5ODZfbVRPRjB5UTFYbU1mejA1alFlTnNsR01oNkZTcTNET1pfVG9rZW46QUY2VGJ6bHM3b0hKRnF4YUJEeWNTOHd1bmFjXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>债务整体架构</strong></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MzE5NGJjNGFhNjg2NmU3Y2UxMDQ4NjgwY2E2MDc0NWFfSXRWNUJwZFhOV1Y4Mmp3MXM4SlpYMEI1YjZEdHV0aGxfVG9rZW46UXNBRWJPMnlsb3I5Y2F4SjJPNGM2NU1EbmhlXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>方向：</strong> 通过对当前问题的归纳，合理划分技术债务的治理方向</p><ul><li><strong>业务架构</strong> ：主要以业务代码实现为主，最佳范式等；</li><li><strong>基建</strong> ：对接底层基建能力，使用上不合理不舒服的点。</li><li><strong>代码</strong> ：实施代码规范、Lint治理和代码格式化。</li><li><strong>效能</strong> ：所有辅助程序运行的脚本能力。</li></ul><p><strong>治理运营</strong> ：一套可持续运行的方案</p><p>任何人不管问题的大小，都可以畅快的提出问题（不是谁提出谁修改，你只管提），把痛点问题进行描述，通过Lean平台记录，并会有专门的人（提出人）标记方向（分类），负责的同学或者感兴趣的同学都可以进行认领，并做出合理的方案和同步进度。</p><p><strong>沉淀：</strong></p><p>通过这些点沉淀能力，不断的下沉能力，解耦业务。</p><p><strong>建设：</strong></p><ul><li><strong>非开源</strong> ：可以按照产物进行成果分享。</li><li><strong>开源</strong> ：是最好的状态，开源我们一些厉害的能力，无论是什么方向的结果。</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YTE5ZGYxYzdiM2FjYzkxODJhYmRlNDkzYmNjZTU2NTZfVlNBTEFzeDFLUDZPR0tuY0h5U1dZZzlRY1lUcm1zUk5fVG9rZW46R2hsUGJOUjV0b3J0WjR4ZDF2RWN5QWtEbmRiXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>债务治理机制</strong></p><p>为了解决这些问题，我们决定采取一系列措施来优化我们的项目和技术栈，并最终沉淀出一套我们可执行可长期运营的方案。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NGMxYjBiZjA1YjZiM2Y3NGQ3Y2Y1YmYwYWU0NzUxYjZfak1WaEV3dERHa21YWnByV0lHcUVMQlBxRElMVlZuMjhfVG9rZW46R2pHWGJralNyb3NWUnd4V2hmUGNQeHhNbnpjXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>识别</strong></p><ul><li>技术的持续改进离不开团队中每个人的努力，因此需要每个成员都积极参与。在日常交付中，团队成员应该持续识别和记录需要改进的问题并将其放入Lean平台中，以便在技术改进会议中与团队同步。</li><li>此外，团队还可以定期组织头脑风暴，以收集技术痛点和改进建议。</li></ul><p><strong>可视化平台</strong></p><p>通过一个共享平台，我们可以高效地录入和展示信息，从而更清晰地一览所有问题的分布情况和各类问题的占比。这样的设计不仅提升了工作效率，还使得数据分析更加直观、便捷。</p><p><strong>优先级</strong></p><p>我们时常会遇到的问题是，需要改进的地方太多，尤其是对于遗留系统。怎么办？先排优先级。我们可以基于价值/成本矩阵来评估改进任务的价值和成本。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=OThkNTQzMmQzNTAwMDg3Yjc1OTNjMDFiNTIwNmI4ZDJfTkpNdng0SXZZOHZRYjNQaXZrMGlCRGRrZFFFcW05OTBfVG9rZW46SXEzbGI1NnMwbzZ2WlN4SVhKOWNqSE9HblFkXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>基于矩阵</strong> ：</p><ul><li>优先解决 <strong>高价值+低成本</strong> 的技术债。</li><li>尝试将 <strong>高价值+高成本</strong> 的技术债拆分为 <strong>高价值+低成本</strong> 的技术债，“尽早、频繁、小批”地进行PDCA（Plan/Do/Check/Adjust）的迭代解决。</li><li>在没有 <strong>高价值+高/低成本</strong> 的技术债时，再来考虑 <strong>低价值+低成本</strong> 的技术债。</li><li>最后如果只剩下 <strong>低价值+高成本</strong> 的技术债，还是先拆分，再解决，或可考虑 <strong>直接移除</strong> 。</li></ul><p><strong>执行</strong></p><p><strong>债务问题，是无法集中清理的，每个人每天都有自己的业务需求，所以我个人认为可以存在两个进度方式：</strong></p><ul><li>在版本跌在中，引入20%的工作量进行技术任务的改进。</li><li>在技术架构升级或者重构等方案中，评估债务任务的清理。</li></ul><p><strong>总结&amp;公式</strong></p><ul><li>每周固定时间进行报告产出。</li><li>存在这个能力，就能更好的整体观测治理的大盘，有助于促进治理的节奏，不会石沉大海。</li><li>让债务问题成为一个话题榜，成为一个论坛贴。从枯燥变成一种可持续输出知识点的平台。</li></ul><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=ZmZjOTY1YTQwNGI5OGEyY2YyMTlmNThmN2Q3YzM4NzhfT21YazdwdHdUTXYxVlZlUUVEUUNEVFhtekwwajk5Y2dfVG9rZW46RnI0NWJZU1BZb0tWYUV4SnY0c2NGdE1RbjdMXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>（热门标签贴）</p><p>我认为在技术债务管理中，这一步是很重要的，我们需要分享解决的思路和成果，它是具有价值的，分享的过程是信息同步也是团队认知的对齐。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=OGRhNjliOTQyYTg4MmVjY2JjOWExZTEyNDRiODM5OTZfOXB0ano1UFNxZTZtbXNYWU9NRTJ6ZkE4dlU1em1tN2FfVG9rZW46UXVBRGJ4RkZwb2pBMkN4eHdvWWNQVVRKblllXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>(自定义报告生成平台)</p><p><strong>总结</strong></p><p>通过这套精心设计的治理机制，我们能够高效地对问题进行细致分类，并实现有条不紊的治理。结合先进的可视化平台Lean+报告产出平台，我们可以实时追踪问题的处理进度。这一机制不仅帮助我们成功解决了问题，还促进了宝贵知识的积累和共享，形成了丰富的知识库。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=ZDkwYzA1NjdlNjYwNWY0NWFjZDY5MDc4MGM4NGRlZjJfYTRLeW9pVnNFbVlGY29jRUxobndTTVQza0xDZEU0NlRfVG9rZW46WE5DRWJRVlhzb0piNHJ4RnJDcGNOQXIybmxnXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>稳定性方向沉淀</strong></p><p>公司层面一直在推进稳定性，通过事前、事中、事后三个阶段进行预防、监控、复盘总结，形成一个闭环流程。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YWQzZWE4NjhiOWQ3YmMwMDAxZTI5MWE5YjJiYmZiYjlfZWdKQkRRZ1F1eVZqTnhxU1BydjFaWWUyU3dKcWRDWXFfVG9rZW46Rmpvb2J0UWxBb0thYnN4akk3VGNOczJYblpVXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>在技术债务治理方面，我认为它扮演着事前过滤器的重要角色。通过运用技术债务治理的手段，我们可以有效地识别并处理许多潜在隐患，从而为系统的稳定性奠定坚实基础。</p><p>在整体稳定性的三个阶段中，事中和事后阶段能够持续揭露技术债务问题的多维面貌，并对其进行系统归纳与整理。这些宝贵的经验教训随后被转化为事前阶段的预防性过滤网，从而助力我们更加精准地预防和应对未来潜在的问题挑战。</p><p><strong>总结</strong></p><p>在事中、事后阶段，我们要能够及时发现并沉淀归纳债务问题，确保问题留痕、总结到位，并达成共识，以便更出色地完成事前规划的任务。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NjU3NmY2OGQ3OTA0MGU3ZmNlYjRhMzIwNDk2Nzg2ZGFfVnd4NHlNcXZkaU01VnFiNW14OVRKS0p4UmdTT20yb29fVG9rZW46THNEQmJKQkdsb1JVa0x4VGlLMmNOQVBMbmZmXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>代码质量治理</strong></p><p><strong>lint治理</strong></p><p>从此时此刻起：债务问题不再新增，趋势线逐步下降；</p><p>严格执行代码规范、CR机制、Dlinter统一规范，提交高质量代码。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NjQ0YTkwNWYzMTZiYjU5OWUzZWQ0MGRiNzlhMDhmYTBfZkF6RlZQRTZoR1lMcWhnYVBqZVQ2WXQ2QmJmYmpGTXBfVG9rZW46QnpIWGJFd0hDbzJGdUF4eGVFUWNhVmxqbnRoXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>工程配置规则、远程代码配置规则开启，自动reject。（Flutter 配置为主）</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YjhmNjI1N2RjMzFmYzViNmRjYmYwMjk0OTBkZDcyZjRfbzhDTXNwREU4dUVLTTM3Tk4wUHdQME94cVdUeGsxNnlfVG9rZW46VkxZaGIycXBob0hocFp4Yzc1VWNocXZsbnlnXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>空安全适配（Flutter）</strong></p><p>我们强烈建议你按顺序迁移代码，先迁移依赖关系中的处于最末端的依赖。例如，如果 C 依赖了 B，B 依赖了 A，那么应该按照 A -&gt; B -&gt; C 的顺序进行迁移。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=OGNhNmU4ZjRkOTk2N2UyNjNhYzJjZmJjMzk1NjJhZTVfR05EbDNuRjJvdU5rUm51Y0p3N24yZnNGa01XZjJ6ZjRfVG9rZW46VUkwYWJtY3hLbzQ2NzB4QmZlU2NHM1M1blljXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p>迁移时序层</p><p>从底层服务类出发，逐层向上适配。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NzJlMGJlYTllYmUxYzNhMjQ1M2Q5YWM4MDQ2NDE5ZDdfV2lScG9lbHhKVG51eGlqQXpFdjRnRUVZTlJydks2ZkhfVG9rZW46WDNEQmJubFBvb2lvWml4bXlWTGN5bVM3bkhkXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=N2Y0OTc2NWJjNjcwMzkwYTNlYjNhNTllMzE4Yzc4NGRfT0pWYjlZdTJpd0FvN2RnMTBHTUFETVR5YXlIZ3FDWVFfVG9rZW46Q0lVZGJ4c1Job0hCWU14YUhOZmM2NUdrbjZnXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>总结</strong></p><p>技术债务是项目进程中难以避免的现象，然而，如何将其控制在可管理范围内，却是我们必须深思的问题。要想有效预防和化解技术债务，离不开优秀开发人员的贡献，而团队的协同合作更是至关重要。借助这套精心设计的治理机制，我们能够对各类问题进行科学分类和有序治理。同时，结合高效的可视化平台，我们可以实时追踪问题进展，不仅及时解决现有问题，还能在此过程中积累并提炼出大量宝贵的共享知识资源。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NTJkM2UwZDY2NDU4MjY5OWI2YjRkNDQ2ZGIyOWQ0MjdfYmFwRWhET2luaUtHN3drcnhFd0tHREdLeE8xZUhTY0hfVG9rZW46UTlGemJRT1lJb05EMEt4SlVicGNPUlk0bkVkXzE3MzY1NzI2OTY6MTczNjU3NjI5Nl9WNA" alt="img"></p><p><strong>结论</strong></p><p>技术债务在现代软件开发中屡见不鲜，然而，借助高效的治理策略与团队的协同合作，我们完全有能力将其潜在影响压缩至最小。不懈的学习与持续的改进乃是项目取得成功的基石，唯有如此，我们方能在日新月异的技术浪潮中稳立潮头，保持强劲的竞争力。</p><p>技术债务是一个普遍存在的问题，它不受平台或编程语言的限制。我们应该共同努力，不断学习和提升自己，以应对这一挑战，共同推动技术进步。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;转载: &lt;a href=&quot;https://jbfhxmeaps.feishu.cn/docx/M8qXdYOYJoMaJbx9VK7c9dIknig&quot;&gt;‌⁢⁤‍⁢⁢⁤⁤⁡‬⁣‍‬‌⁢﻿‍⁣⁤‬‬‍⁤⁢⁤‬⁤⁡⁢‍‬⁣‬⁢‬‍﻿‍⁢⁤&lt;a href=&quot;https://mp.w</summary>
      
    
    
    
    
    <category term="转载" scheme="https://imlike.cc/tags/%E8%BD%AC%E8%BD%BD/"/>
    
  </entry>
  
  <entry>
    <title>从头到尾说一说Java时间日期体系的前世今生(转载)</title>
    <link href="https://imlike.cc/afee6eb0.html"/>
    <id>https://imlike.cc/afee6eb0.html</id>
    <published>2025-01-11T05:12:49.000Z</published>
    <updated>2025-01-12T06:11:42.872Z</updated>
    
    <content type="html"><![CDATA[<p>转载链接:  <a href="https://mp.weixin.qq.com/s?src=11&timestamp=1736572324&ver=5743&signature=PJXVw3zvmhLrj*-*Mp3vngu7NlHlvoQoyS-WWdLwf0niEjgyecqHKWBxTlg6Yf2OUM2h78zZFuNRuSuozeA5CKuFJVogAx4QWfgzTm4ogSiXZ0hLObff60N6iurUVSGO&new=1">从头到尾说一说Java时间日期体系的前世今生</a></p><p>在计算机领域作者重新梳理了计算机世界里日期时间体系的前世今生。</p><p>突击检查</p><p>如下代码输出什么，机器当下所设定的时区为美国时区，在北京时间 2024-12-07 11:20:51 时，传入字符串“2024-12-07 11:46:36”。最终输出应该是true，还是false呢？</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MjdhODc2YzgxOWIyMGYyMWM5ZTRlYjk4YjFlNWZlMjJfQzFoTzNVQzFwdjlQNzU4RE1iQ0haYmw3ejBQbG9la1NfVG9rZW46UndSNWJVZEFQb0x6VER4cUJDSWM2OU5Vbm5oXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><p>前言</p><p>约38亿年前地球出现生命体，约46亿年前太阳系形成，大约138亿年前宇宙大爆炸，那再往前呢？想起吕秀才对姬无命发出灵魂之问『时间是否有开端，宇宙是否有尽头』。施一公曾经在一次演讲中说，宇宙中从来不存在时间，只存在运动。地球公转太阳一圈是一年，这是运动，地球自转一圈是一天，这也是运动。从来就没有时间，或者说时间就是空间。</p><p>『三十年春，秦晋围郑。郑伯使烛之武如秦』两千多年前我们就以时间记事，在造物主已经缔造的这一片井然有序的世界里，我们凭空创建出一个新的概念，并不断尝试融入这个世界体系–沙漏、水钟、日晷等等。今天站在计算机这个领域，也让我们重新梳理一遍，计算机世界里日期时间体系的前世今生。</p><p>日期从1970 年1月1日说起</p><p>任何一个软件开发人员对这个时间应该都不陌生，有时我们忘记初始化或者忘记赋值时，日期就会显示为1970-01-01，我们也叫日期初始值。那为什么日期的初始值是从1970-01-01开始呢？有一个说法是说遵循了Unix的时间计数，Unix认为 1970年1月1日0点 [1]是时间纪元，那为什么Unix要以这个时间为准呢？</p><p>有一处说法是说，当时操作性系统都是32位，如果每一个数值代表一秒，那么最多可以表示2^32-1，也就是2147483647秒，换算成年大概是68年。而Unix系统就是由Ken Thompson、Dennis Ritchie和Douglas McIlroy等人在贝尔实验室开发于1969年开发的，他们为了让时间尽可能的多利用起来，便用了下一年，即 1970年1月1日作为开始，然后这个约定也逐步延伸到其他各个计算机领域。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NGI5ZjUyZWM5MTVkZDcwNGVhYzMzMmVlZmE5YTYxM2JfWWRxSUE5TlhQVTRFTVVvTHM1RW9ZbGpPMVZvQlYzVklfVG9rZW46VzJwbWJqVUxZbzA4cTV4QmpiTGNUWnpxbmFjXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><p>时间从GMT与UTC说起</p><p>聊完日期我们再来看时间，爱好体育的应该都知道，看欧冠得半夜起来看，看NBA得早上起来看，现在是北京时间的14点，同时也是纽约时间的凌晨1点半。那是因为我们各地处不同时区，那时区以什么为初始划分的呢？</p><p><strong>GMT</strong> <strong>格林威治时间</strong></p><p>GMT的全称是 Greenwich Mean Time [2]即格林威治标准时间，是一种与地球自转相关、以太阳日为单位的时间标准。在十七世纪，格林威治皇家天文台为了海上霸权的扩张计划，选择了穿过英国伦敦格林威治天文台子午仪中心的一条经线作为零度参考线，也就是我们教科书上记载的本初子午线。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=ZjE3ZDhlNTNjNzA2MjUxYTZkYjAwNTkzNjFmOWYyNzVfWHlvTEtmcmJSWnJ2cThpU2sweEw5WGk1VmJwaHV1eXlfVG9rZW46SE9ja2JjcGpCb1ZiUmJ4ZlliN2NFTE5WbnNnXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><p>并约定从本初子午线起，经度每向东或者向西间隔15°，就划分一个新的时区[3]，每个时区间隔1小时，在这个区域内，大家使用同样的标准时间。但各个国家也会基于各个国家的情况拆分或合并时区，比如中国横跨5个时区，但我们统一使用东八区；而美国则有东部时间、西部时间、夏威夷时间等等。</p><p>从 1924 年开始，格林威治天文台每小时就会向全世界播报时间，最终截止到 1979 年。至于为什么会终止，自然有它的缺点和局限性，那我们就得聊聊UTC时间了。</p><p><strong>UTC</strong> <strong>世界协调时间</strong></p><p>UTC的全称是 Coordinated Universal Time [4]协调世界时间，也称世界标准时间。据说按英语的简称是CUT，按法语的简称是TUC，然后大家相互拉扯一波后，统一叫了UTC。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MjUxOTA1YTc2YmE5YjAxNWFlNzYyNmQwYjU2ZjNjMDNfUnlDdWhEVFBOd2s1SkRoMlZ1RGhhM29JSkZWeTl6OFFfVG9rZW46VmRKR2JJMjhrb0VZZTF4VnRUd2MzZmZvbjdmXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><p>上述所说GMT时间是以地球自转与围太阳公转来计时的，GMT时间认为地球自转一圈是24<em>3600秒，而地球的运动轨迹受很多方面影响，比如潮汐摩擦、气象变化、地震及地质活动等等，运动的时间周期并不是完全规律和相同的。这样会导致其实一天并不完全是24</em>3600秒，这样平均算下来GMT的一秒就不是完全意义上最精确的一秒。但偏差通常也不会很大，基本为毫秒级偏差，但日积月累如果不加以扶正，就会越差越远。</p><p>而UTC的计数是基于 原子钟（Atomic Clock） [5]的计数，比如铯原子钟采用铯-133原子的特性，在特定能级跃迁时会产生一个非常确定的频率9,192,631,770赫兹。然后基于铯-133原子的运动经过换算确定出我们需要的时间周期，据说这种误差可达每百万年内不到一秒。</p><p>UTC 最终由两部分构成：原子时间与世界时间。原子时间基于原子钟，来标准化我们钟表中每一秒时间前进的数据；世界时间是结合GMT时间，我们用多少个原子时来决定一个地球日的时间长度。从1972年开始，UTC被正式采用为国际标准时间。这年实施了一种新的时间调整机制，包括使用闰秒[6]以便对齐地球自转与原子时间。</p><p>JDK 时间日期的发展史</p><p><strong>糟糕的java.util.Date</strong></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NjA1MDE4M2I4YjQxMTk2MGVlOWZmYWZiNDM1NmM1NTJfbjNLdHpLMlY2QlBuQkdibndESE1KQkQ3S0pMTkNJZFRfVG9rZW46RWNRcWJpdHJFb2owazB4elFVSmNwekRybmJkXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><p>说起Date那可是JDK的正牌嫡系，从1.0开始就一直存在并延续至今。但只要大家用过一些代码扫描工具，基本都是在提示你尽量不要使用Date。在oracle的官方JDK文档中，有超过一半的函数都是deprecated，要细说Date的问题，那可真是一言难尽。</p><h3 id="不能单独表示日期或时间"><a href="#不能单独表示日期或时间" class="headerlink" title="不能单独表示日期或时间"></a>不能单独表示日期或时间</h3><p>Sat Dec 07 17:36:58 CST 2024 这是我们输出new Date()之后的数据，因为Date本质是某一个时刻的时间戳，导致它不能单独表示日期，更不能表示不带日期的时间。</p><h3 id="令人捉摸不透的API"><a href="#令人捉摸不透的API" class="headerlink" title="令人捉摸不透的API"></a>令人捉摸不透的API</h3><p>单就Date的方法名来看，应该是非常友好的。它提供了getYear(), getDay()等等，你但凡用过一次，一定让你抓狂。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">public static void main(String[] args) &#123;    Date date = new Date();    // 输出 6    System.out.println(date.getDay());    // 输出 11    System.out.println(date.getMonth());    // 输出 124    System.out.println(date.getYear());&#125;</span><br></pre></td></tr></table></figure><p>day和month是从0开始计数的，所以月最大是11，日最大是30，年输出124是因为2024年距离1900年有124年。至于为什么是减1900，有知道的小伙伴评论区打出来😂。</p><h3 id="不支持时区设定"><a href="#不支持时区设定" class="headerlink" title="不支持时区设定"></a>不支持时区设定</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Date now = Calendar.getInstance(Locale.CHINA).getTime();</span><br></pre></td></tr></table></figure><p>曾经写过一段这样的代码，取当前的中国时间，被老板臭骂一顿。。。Date的本质是一个时间戳。当前此时此刻，全球任何一个地方的时间戳都是同一个，Date本身不支持时区。PS.本质上这行代码也指定不了时区哦~</p><h3 id="Date是可变的"><a href="#Date是可变的" class="headerlink" title="Date是可变的"></a>Date是可变的</h3><p>Date是一个非常基础底层的类，但它却设计为可变。当我们计算这个data3天后是不是周末，如果程序计算中把这个date加了3天，那么你手上拿着得date也变成了3天后的日期。相比同为底层基础类的String，做得就优秀多了。</p><p><strong>难当大任的Calendar</strong></p><p>JDK刚推出就发现了问题，于是赶紧在1.1版本推出了Calendar，尝试用来解决令人诟病的Date，并将Date一众函数都标记为了deprecated。但Calendar依然是可变对象、最多也只能精确到毫秒、线程不安全、API的使用复杂且笨重等等，Calendar整体而言并没有挽回颓势。</p><p><strong>曙光来临之JSR310</strong></p><p>在聊JSR310之前，不得不先提一提 Joda-Time [7]这个开源Java库。Joda-Time以清晰的API、良好的时区支持、不可变性、强类型化等特性，得到了开发者社区的广泛好评，并在很多项目中被采用，被视为改善Java日期和时间处理的标杆库。Joda-Time如此优秀，Oracle也开启了收编之旅。2013年Java8发布，其中针对日期时间带来一套全新的标准规约 JSR310 [8]，而JSR310的核心制作者就是Joda-Time的作者Stephen Colebourne。</p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=YjRkODRiYWEyNDhhMDVhNDVkYzRlMjdjZDFhMTUxZTlfYWlEdkxHNmlGZnZoODRUM1dRU1ZHd0M5TWJGS3VJamRfVG9rZW46TXlBSWI4RXlvb0o3dHd4SW84ZmNpcHpXbmJoXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><p>Instant</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/** * The number of seconds from the epoch of 1970-01-01T00:00:00Z. */private final long seconds;/** * The number of nanoseconds, later along the time-line, from the seconds field. * This is always positive, and never exceeds 999,999,999. */private final int nanos;</span><br></pre></td></tr></table></figure><p>Instant这个单词的中文含义是『瞬间』，严格来说Java8之前的Date就应该是现在的Instant。Instant类有维护2个核心字段，当前距离时间纪元的秒数以及秒中的纳秒部分。它指代当前这个时刻，全球任一位置这一时刻都是同一时刻。这一时刻川建国同学在高床软枕打着呼，这一时刻我泡着龙井写着文稿。</p><h3 id="LocalDateTime"><a href="#LocalDateTime" class="headerlink" title="LocalDateTime"></a>LocalDateTime</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/******************** LocalDate ********************/    /**     * The year.     */    private final int year;    /**     * The month-of-year.     */    private final short month;    /**     * The day-of-month.     */    private final short day;</span><br><span class="line">/******************** LocalTime ********************/    /**     * The hour.     */    private final byte hour;    /**     * The minute.     */    private final byte minute;    /**     * The second.     */    private final byte second;    /**     * The nanosecond.     */    private final int nano;</span><br></pre></td></tr></table></figure><p>LocalDateTime由LocalDate和LocalTime组成，分别日期和时间，以此来解决Date中不能单独表示日期和时间的问题。它们都与时区无关，只客观代表一个无时区的时间，比如2024-12-08 13:46:21，LocalDateTime记录着它的年、月、日、时、分、秒、纳秒。但具体是北京时间的13点还是伦敦时间的13点，由上下文语境自行处理。</p><h3 id="Duration"><a href="#Duration" class="headerlink" title="Duration"></a>Duration</h3><p>Duration中文含义译为『期间』，通常用来计算2个时间之前相差的周期，不得不说这一套时间JDK确实定义得语义非常清晰。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Instant startInstant = xxx;Instant endInstant = xxx;Duration.between(startInstant, endInstant).toMinutes();</span><br></pre></td></tr></table></figure><p>这个很好理解，比较2个时间戳时间的相差分钟数。但如果换成LocalDateTime，会是怎样呢？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LocalDateTime startTime = xxx;LocalDateTime endTime = xxx;Duration.between(startTime, endTime).toMinutes();</span><br></pre></td></tr></table></figure><p>因为LocalDateTime是不带时区的，所以LocalDateTime是不能直接换成成Instant的。而Duration的比较也是不带时区的，或者你可以理解它是把时间放在同一个时区进行比较，来抹去时区的影响。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/********************* JDK Duration.between 部分源码 *******************************/@Overridepublic long until(Temporal endExclusive, TemporalUnit unit) &#123;    LocalDateTime end = LocalDateTime.from(endExclusive);    if (unit instanceof ChronoUnit) &#123;        if (unit.isTimeBased()) &#123;            long amount = date.daysUntil(end.date);            if (amount == 0) &#123;                return time.until(end.time, unit);            &#125;            long timePart = end.time.toNanoOfDay() - time.toNanoOfDay();            if (amount &gt; 0) &#123;                amount--;  // safe                timePart += NANOS_PER_DAY;  // safe            &#125; else &#123;                amount++;  // safe                timePart -= NANOS_PER_DAY;  // safe            &#125;// 余下省略&#125;</span><br></pre></td></tr></table></figure><p>上述是Duration部分源码，它首先计算出2个时间相差多少天，再比较当天的时间里相差多少纳秒，再进行累加。所以你传过来2024-12-08 和 2024-12-04，那就是相差4天，至于是北京时间的12-08还是伦敦时间的12-04，在Duration里都被抹去了时区的概念。 <strong>看到这里，上面的编程题里做对了吗？</strong></p><h3 id="ZonedDateTime"><a href="#ZonedDateTime" class="headerlink" title="ZonedDateTime"></a>ZonedDateTime</h3><p>真正需要使用时区，我们就需要用到ZonedDateTime。「zoned」这个单词在英汉词典中是zone的过去分时，译为『划为区域的』。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">// 输出：2024-12-08T14:18:32.554144+08:00[Asia/Shanghai]ZonedDateTime defaultZoneTime = ZonedDateTime.now(); // 默认时区// 输出：2024-12-08T01:18:32.560931-05:00[America/New_York]ZonedDateTime usZoneTime = ZonedDateTime.now(ZoneId.of(&quot;America/New_York&quot;)); // 用指定时区获取当前时间</span><br></pre></td></tr></table></figure><p>因为LocalDateTime是没有时区的，如果我们需要将LocalDateTime转成ZonedDateTime，就需要带上时区信息。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LocalDateTime localDateTime = LocalDateTime.of(2024, 12, 8, 14, 21, 17);ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());ZonedDateTime usZonedDateTime = localDateTime.atZone(ZoneId.of(&quot;America/New_York&quot;));</span><br></pre></td></tr></table></figure><p>随着JDK不断地发布演进，Time模块确实得到了质的提升，这里不一一细说Java日期时间相关API。如果你还在苦于对Date做各种Utils的花式包装，请拥抱java.time吧。</p><p>时间日期引起的惨案</p><p><strong>夏令时与冬令时</strong></p><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=MjFlNzJjNzJjYTZlNjE0Mzk4ZDZmNWE5ZmYwMWNjN2ZfMnlvTHVMVmtlZGs0d2pROUh4ZWtaZ0pOVXFsTTdvdEJfVG9rZW46VDdLR2JRRHo3b0ZYS3N4ZEtVT2NReHA0bkZkXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><p>曾经小A做了一个鉴权系统，用于对请求做加密解密，保证每一次都是真实合法有效的接口请求。其中做了一个判定，如果请求的时间距现在已经超过10分钟，就会拒绝该次请求。从逻辑上来说，这很合理，但问题的雪崩却出现在3月的那个晚上。。。</p><h3 id="什么是夏令时"><a href="#什么是夏令时" class="headerlink" title="什么是夏令时"></a>什么是夏令时</h3><p>夏令时[9]又称夏时制，英文原文为Daylight Saving Time，从名字上可以看出，夏令时诞生的背景是为了更好的利用白天的时间。夏令时概念的提出最早可以追溯到1895年，新西兰昆虫学家乔治·哈德逊向惠灵顿哲学学会提出，提前2小时的日光节约提案，以此在工作结束后，可以获得多出一段的白昼时间。</p><p>具体夏令时的实施，以美国为例，美国会在每年3月的第二个星期日的凌晨2:00，时钟会往前调1个小时变为3:00。再在每年11月的第一个星期日的凌晨2:00，将时钟在往后调1个小时变成1:00，此时的回拨也被称为“冬令时”。</p><h3 id="夏令时实施的国家与地区"><a href="#夏令时实施的国家与地区" class="headerlink" title="夏令时实施的国家与地区"></a>夏令时实施的国家与地区</h3><p><img src="https://jbfhxmeaps.feishu.cn/space/api/box/stream/download/asynccode/?code=NWVkOGM1MDRjNDE5ZjU0MzNjNjAyYzkzYzA5NzljMTlfbWN5VVN4emdwWEw2WHhwbkhMYlZieUdxSWVkbkN3TFNfVG9rZW46RHVKcWJXR3VPb0FpcjZ4QVlFT2M2eFFBbjNkXzE3MzY1NzI0NjU6MTczNjU3NjA2NV9WNA" alt="img"></p><blockquote><p>蓝色为正在实施夏令时的国家和地区 灰色为曾经实施但现在已经取消夏令时的国家和地区 黑色为从未实施夏令时的过去和地区</p></blockquote><p>1916年4月30日，德国与奥匈帝国成为世界上第一组实施夏时制的国家，目的是为了能在战争期间节约煤炭消耗。在1970年代，由于美洲与欧洲地区也受到能源危机影响，至此夏令时开始广泛被实施。当下全球有共约70多个国家和时区在使用夏令时，我国也曾短暂使用过夏令时，但因节约能源效果不显著，以及对日常生活工作等带来的一些影响，到1992年全国宣布取消夏令时。</p><p><strong>闰年与闰秒</strong></p><p>2008年是闰年存在2月29日，但微软一些软件在处理部分任务的时候会因为闰年导致处理错误。微软甚至在SQL Server 2008 CTP发布后曾经宣读了一份证明，建议用户不要在2月29日安装和运行软件，以减少影响。并且在Windows Small Business Server上还会出现更严重的错误：因为在微软的日历里根本没那么一天，因此就无法颁发证书。</p><h3 id="为什么要闰年"><a href="#为什么要闰年" class="headerlink" title="为什么要闰年"></a>为什么要闰年</h3><p>闰年大家比较熟悉，闰年的设置是为了使日历年与太阳年（即地球绕太阳公转一周的时间）更精准地一致。严格来说地球绕太阳一圈的时间，大约是365.2422天。经过大约四年，累计误差将接近一天（0.2422 * 4 ≈ 0.9688天），但如果每4年就加1天，这样每128年又会多算出1天。所以基于此定义出了普通闰年与世纪闰年。</p><ul><li>普通闰年：公历年份是4的倍数，且不是100的倍数的，为闰年（如2004年、2020年等就是闰年）。</li><li>世纪闰年：公历年份是整百数的，必须是400的倍数才是闰年（如1900年不是闰年，2000年是闰年）。</li></ul><h3 id="为什么要闰秒"><a href="#为什么要闰秒" class="headerlink" title="为什么要闰秒"></a>为什么要闰秒</h3><p>闰秒[10]本质上和闰年的作用是一样的，也是解决时间解释运动中所存在的偏差。闰秒的调整是为了确保协调世界时（UTC）与地球自转时间（UT1）[11]保持一致。由于地球自转速度的不均匀性和减慢，UTC需要定期添加或删除一秒钟来进行调整，这一秒钟称为“闰秒”。</p><p>国际地球自转与参考系统服务（IERS）是负责监测和发布闰秒调整的机构。ERS会根据地球自转的实际变化和测量数据，决定是否需要调整闰秒。闰秒通常在6月30日或12月31日的最后一秒添加或删除。这意味着在某些年份，时间序列可能会变为：23:59:59 → 23:59:60 → 00:00:00。</p><p>写在最后</p><p>『存在不一定合理，但一定有原因』这是曾经我的主管跟我说的，至今我也受益其中。对所有事情怀有一丝怀疑心态，搞懂它的前世今生，或许它不那么合理，但至少当时这样做解决了一定的问题，我们在做新设计的时候可以提前考虑与规避。水多了加面，面多了加水，如果我们只是看到当下的混乱就指着“前人”没有设计思想没有技术匠心，却不了解最初“前人”这样做的意图与背景，骂着“前人”的我们终有一天也会成为后人眼中的“前人”。</p><p><strong>参考链接：</strong> </p><p>[1]<a href="https://en.wikipedia.org/wiki/Unix_time">https://en.wikipedia.org/wiki/Unix_time</a></p><p>[2]<a href="https://baike.baidu.com/item/%E4%B8%96%E7%95%8C%E6%97%B6/692237">https://baike.baidu.com/item/世界时/692237</a></p><p>[3]<a href="https://www.timeanddate.com/time/zones/">https://www.timeanddate.com/time/zones/</a></p><p>[4]<a href="https://www.utctime.net/">https://www.utctime.net/</a></p><p>[5]<a href="https://baike.baidu.com/item/%E5%8E%9F%E5%AD%90%E9%92%9F/765460">https://baike.baidu.com/item/原子钟/765460</a></p><p>[6]<a href="https://baike.baidu.com/item/%E9%97%B0%E7%A7%92">https://baike.baidu.com/item/闰秒</a></p><p>[7]<a href="https://www.joda.org/joda-time/">https://www.joda.org/joda-time/</a></p><p>[8]<a href="https://jcp.org/en/jsr/detail">https://jcp.org/en/jsr/detail</a></p><p>[9]<a href="https://baike.baidu.com/item/%E5%A4%8F%E4%BB%A4%E6%97%B6/1809579">https://baike.baidu.com/item/夏令时/1809579</a></p><p>[10]<a href="https://baike.baidu.com/item/%E9%97%B0%E7%A7%92/696742">https://baike.baidu.com/item/闰秒/696742</a></p><p>[11]<a href="https://zh.wikipedia.org/wiki/%E4%B8%96%E7%95%8C%E6%97%B6">https://zh.wikipedia.org/wiki/世界时</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;转载链接:  &lt;a href=&quot;https://mp.weixin.qq.com/s?src=11&amp;timestamp=1736572324&amp;ver=5743&amp;signature=PJXVw3zvmhLrj*-*Mp3vngu7NlHlvoQoyS-WWdLwf0niEjg</summary>
      
    
    
    
    
  </entry>
  
</feed>
