[컴] docker 를 사용해서 GoCD 실행하기

ci/cd tool / cd tool / gocd

docker 를 사용해서 GoCD 실행하기

c:\> docker run -e MSG_TIME=0 -p 8153:8153 -p 8154:8154 -v ./godata:/godata --name mygocd gocd/gocd-server:v21.3.0
c:\> docker inspect --format="{{(index (index .NetworkSettings.IPAddress))}}" mygocd
172.17.0.2
c:\> docker run --rm -e GO_SERVER_URL=http://172.17.0.2:8153/go --name mygocd-agent gocd/gocd-agent-alpine-3.14:v21.3.0

docker-compose.yml

아래 git repository 에서 GoCD 에 대한 docker-compose.yml file 을 얻을 수 있다.

그런데 오래된 것이라서 아래처럼 수정했다.

version: "3"
services:
  server:
    container_name: gocd-server
    hostname: gocdserver
    ports:
      - 8153:8153
    image: gocd/gocd-server:v21.3.0
    volumes:
      - ./godata:/godata
    environment:
      - MSG_TIME=0
  agent:
    image: gocd/gocd-agent-alpine-3.14:v21.3.0
    environment:
      - GO_SERVER_URL=http://gocdserver:8153/go
    depends_on:
      - server

networks:
  gocdnet:

# docker run --rm -e MSG_TIME=0 -p 8153:8153 -v ./godata:/godata --name mygocd gocd/gocd-server:v21.3.0 
# docker inspect --format="{{(index (index .NetworkSettings.IPAddress))}}" mygocd
# docker run --rm -e GO_SERVER_URL=http://172.17.0.2:8153/go --name mygocd-agent gocd/gocd-agent-alpine-3.14:v21.3.0

docker compose up

위의 docker-compose.yml 을 사용해서 docker compose up 을 하자.

mkdir godata
docker compose up

위 compose file 을 보면 알겠지만, godata directory 가 mount 된다.

gocd server로 접속

그리고 http://localhost:8153으로 접속하면 된다.

  • http://localhost:8153

agent 를 여러개 띄우기

아래처럼 실행하면 agent 라는 service 를 3개 실행시키게 된다.

docker compose up --sacle agent=3

gradle task 사용하기

See Also

  1. docker-compose scale | Docker Documentation
  2. 쿠…sal: [컴] GoCD 설치
  3. Control startup and shutdown order in Compose | Docker Documentation

Reference

  1. GoCD with Docker - boydfd’s blog

[컴][db] mongodb 에서 필요한 메모리 size 결정하는데 도움이 되는 정보 확인

 

mongodb 에서 필요한 메모리 size 결정하는데 도움이 되는 정보 확인

MongoDB v3.4이후 cache 관련 기본 설정

  • WiredTiger 내부 cache 크기 : 256MB 또는 “50% * (총ram - 1GB)” 중에 큰 쪽을 택한다.
  • 16GB 의 system 이라면, 15GB 의 50% 인 7.5GB 가 WiredTiger 내부 cache 크기가 된다.

db.serverStatus().wiredTiger.cache 명령어로 현재 설정을 확인할 수 있다. 이 값들의 의미는 serverStatus.wiredTiger — MongoDB Manual 서 확인할 수 있다.

아래의 ‘maximum bytes configured’ 가 ‘wiredTiger.cache.maximum bytes configured’ 라고 보면 된다.

db.serverStatus().wiredTiger.cache
/* 1 */
{
    "application threads page read from disk to cache count" : 108427,
    "application threads page read from disk to cache time (usecs)" : 33973418,
    "application threads page write from cache to disk count" : 7870,
    "application threads page write from cache to disk time (usecs)" : 330718,
    "bytes allocated for updates" : 80145389,
    "bytes belonging to page images in the cache" : NumberLong(3854909989),
    "bytes belonging to the history store table in the cache" : 916,
    "bytes currently in the cache" : NumberLong(5526337681),
    "bytes dirty in the cache cumulative" : 889517611,
    "bytes not belonging to page images in the cache" : 1671427692,
    "bytes read into cache" : NumberLong(3606044753),
    "bytes written from cache" : 686646597,
    "cache overflow score" : 0,
    "checkpoint blocked page eviction" : 0,
    "checkpoint of history store file blocked non-history store page eviction" : 0,
    "eviction calls to get a page" : 4543,
    "eviction calls to get a page found queue empty" : 651,
    "eviction calls to get a page found queue empty after locking" : 50,
    "eviction currently operating in aggressive mode" : 0,
    "eviction empty score" : 0,
    "eviction gave up due to detecting an out of order on disk value behind the last update on the chain" : 0,
    "eviction gave up due to detecting an out of order tombstone ahead of the selected on disk update" : 0,
    "eviction gave up due to detecting an out of order tombstone ahead of the selected on disk update after validating the update chain" : 0,
    "eviction gave up due to detecting out of order timestamps on the update chain after the selected on disk update" : 0,
    "eviction passes of a file" : 259,
    "eviction server candidate queue empty when topping up" : 11,
    "eviction server candidate queue not empty when topping up" : 248,
    "eviction server evicting pages" : 0,
    "eviction server slept, because we did not make progress with eviction" : 1268,
    "eviction server unable to reach eviction goal" : 0,
    "eviction server waiting for a leaf page" : 598,
    "eviction state" : 64,
    "eviction walk most recent sleeps for checkpoint handle gathering" : 0,
    "eviction walk target pages histogram - 0-9" : 0,
    "eviction walk target pages histogram - 10-31" : 0,
    "eviction walk target pages histogram - 128 and higher" : 0,
    "eviction walk target pages histogram - 32-63" : 0,
    "eviction walk target pages histogram - 64-128" : 259,
    "eviction walk target pages reduced due to history store cache pressure" : 0,
    "eviction walk target strategy both clean and dirty pages" : 0,
    "eviction walk target strategy only clean pages" : 0,
    "eviction walk target strategy only dirty pages" : 259,
    "eviction walks abandoned" : 6,
    "eviction walks gave up because they restarted their walk twice" : 0,
    "eviction walks gave up because they saw too many pages and found no candidates" : 0,
    "eviction walks gave up because they saw too many pages and found too few candidates" : 0,
    "eviction walks reached end of tree" : 9,
    "eviction walks restarted" : 0,
    "eviction walks started from root of tree" : 6,
    "eviction walks started from saved location in tree" : 253,
    "eviction worker thread active" : 4,
    "eviction worker thread created" : 0,
    "eviction worker thread evicting pages" : 3840,
    "eviction worker thread removed" : 0,
    "eviction worker thread stable number" : 0,
    "files with active eviction walks" : 0,
    "files with new eviction walks started" : 9,
    "force re-tuning of eviction workers once in a while" : 0,
    "forced eviction - history store pages failed to evict while session has history store cursor open" : 0,
    "forced eviction - history store pages selected while session has history store cursor open" : 0,
    "forced eviction - history store pages successfully evicted while session has history store cursor open" : 0,
    "forced eviction - pages evicted that were clean count" : 0,
    "forced eviction - pages evicted that were clean time (usecs)" : 0,
    "forced eviction - pages evicted that were dirty count" : 4,
    "forced eviction - pages evicted that were dirty time (usecs)" : 38127,
    "forced eviction - pages selected because of a large number of updates to a single item" : 0,
    "forced eviction - pages selected because of too many deleted items count" : 133,
    "forced eviction - pages selected count" : 11,
    "forced eviction - pages selected unable to be evicted count" : 0,
    "forced eviction - pages selected unable to be evicted time" : 0,
    "hazard pointer blocked page eviction" : 0,
    "hazard pointer check calls" : 3851,
    "hazard pointer check entries walked" : 10177,
    "hazard pointer maximum array length" : 1,
    "history store score" : 0,
    "history store table insert calls" : 0,
    "history store table insert calls that returned restart" : 0,
    "history store table max on-disk size" : 0,
    "history store table on-disk size" : 12288,
    "history store table out-of-order resolved updates that lose their durable timestamp" : 0,
    "history store table out-of-order updates that were fixed up by reinserting with the fixed timestamp" : 0,
    "history store table reads" : 0,
    "history store table reads missed" : 0,
    "history store table reads requiring squashed modifies" : 0,
    "history store table truncation by rollback to stable to remove an unstable update" : 0,
    "history store table truncation by rollback to stable to remove an update" : 0,
    "history store table truncation to remove an update" : 0,
    "history store table truncation to remove range of updates due to key being removed from the data page during reconciliation" : 68461,
    "history store table truncation to remove range of updates due to out-of-order timestamp update on data page" : 0,
    "history store table writes requiring squashed modifies" : 0,
    "in-memory page passed criteria to be split" : 14,
    "in-memory page splits" : 7,
    "internal pages evicted" : 0,
    "internal pages queued for eviction" : 0,
    "internal pages seen by eviction walk" : 3490,
    "internal pages seen by eviction walk that are already queued" : 0,
    "internal pages split during eviction" : 0,
    "leaf pages split during eviction" : 471,
    "maximum bytes configured" : NumberLong(8053063680),
    "maximum page size at eviction" : 0,
    "modified pages evicted" : 3844,
    "modified pages evicted by application threads" : 0,
    "operations timed out waiting for space in cache" : 0,
    "overflow pages read into cache" : 248,
    "page split during eviction deepened the tree" : 0,
    "page written requiring history store records" : 0,
    "pages currently held in the cache" : 108693,
    "pages evicted by application threads" : 0,
    "pages evicted in parallel with checkpoint" : 246,
    "pages queued for eviction" : 25900,
    "pages queued for eviction post lru sorting" : 25694,
    "pages queued for urgent eviction" : 378,
    "pages queued for urgent eviction during walk" : 0,
    "pages queued for urgent eviction from history store due to high dirty content" : 0,
    "pages read into cache" : 108871,
    "pages read into cache after truncate" : 47,
    "pages read into cache after truncate in prepare state" : 0,
    "pages requested from the cache" : 34351374,
    "pages seen by eviction walk" : 52348,
    "pages seen by eviction walk that are already queued" : 1459,
    "pages selected for eviction unable to be evicted" : 0,
    "pages selected for eviction unable to be evicted as the parent page has overflow items" : 0,
    "pages selected for eviction unable to be evicted because of active children on an internal page" : 0,
    "pages selected for eviction unable to be evicted because of failure in reconciliation" : 0,
    "pages selected for eviction unable to be evicted because of race between checkpoint and out of order timestamps handling" : 0,
    "pages walked for eviction" : 380926,
    "pages written from cache" : 12981,
    "pages written requiring in-memory restoration" : 3826,
    "percentage overhead" : 8,
    "the number of times full update inserted to history store" : 0,
    "the number of times reverse modify inserted to history store" : 0,
    "tracked bytes belonging to internal pages in the cache" : 51625791,
    "tracked bytes belonging to leaf pages in the cache" : NumberLong(5474711890),
    "tracked dirty bytes in the cache" : 0,
    "tracked dirty pages in the cache" : 0,
    "unmodified pages evicted" : 0
}

메모리 관련 server status 값 [ref.1]

  • wiredTiger.cache.maximum bytes configured : 현재 최대 cache size
  • wiredTiger.cache.bytes currently in the cache
    • 현재 cache에 있는 data 의 size.
    • 일반적으로 “cache size 의 80% + dirty cache 양(아직 disk 에 write 되지 않은 내용)”
    • 이 값이 wiredTiger.cache.maximum 보다 큰 값이 되서는 안된다.
    • 만약 이 값이 wiredTiger.cache.maximum 보다 크게 나온다면 scale out 을 해야한다는 의미다.
  • wiredTiger.cache.tracked dirty bytes in the cache
    • cache 에 있는 dirty data 의 size
    • cache size 값의 5% 보다 작아야 한다. 만약 그것보다 크면 scale out 을 해야 한다.
    • 5% 보다 크면, WiredTiger 는 cache 에서 data 를 지우는데 좀 더 공격적이게 된다.
      어떤 경우에는 성공적으로 write 가 끝나기 전에 client 에게 data 를 cache 에서 제거하도록 강제할 수 있다.
  • wiredTiger.cache.pages read into cache
    • cache 로 읽어오는 page의 수이다.
    • 그리고 초당 평균(per-second average)을 판단하는데 이것을 이용할 수 있다.
      어떤 data 가 cache 로 오는지 알 수 있다.(?)
      (This is the number of pages that are read into cache and you can use this to judge its per-second average to know what data is coming into your cache.)
    • 이 값이 read-heavy application 들에 대한 issue 의 지표가 될 수도 있다.
    • 이 값이 꾸준히 cache size 의 큰 부분을 차지하고 있으면, ’메모리를 늘리는 것’이 전체적인 read 성능을 올릴 수 있을 것이다.
  • wiredTiger.cache.pages written from cache
    • cache 에서 disk 로 write 된 page의 ’수’이다.
    • chckpoint 들이 일어나기 전에 특히 큰 값을 갖는다.
    • 만약 이 값이 계속 증가한다면, 너의 checkpoint 들은 계속 해서 길어질 것이다.

working set memory size 가 충분한지 여부[ref. 2]

top 등의 명령어로 볼때 mongodb 가 동작중에 memory 가 여유분이 있다면, 그것은 working set 이 memory 에 fit 하다는 이야기다.

free memory 가 없는 경우 cache.pages 를 확인하자.

몽고db가 memory 를 거의 다 잡아먹는 경우, 다음 2개의 값이 높으면, server 가 cache 를 통해 data 를 순환시키고 있다는 이야기다. 그말은 working set 이 memory 보다 크다는 이야기다.

disk read 의 양 을 확인한다.

  • drive 에서 많은 read activity 가 있다면, 일반적으로 working set 이 메모리 크기보다 크다는 신호일 수 있다.
  • cache 동작때문에, 높은 cache eviction 지만, 낮은 IO 를 볼 수도 있다.?

allowDiskUse

aggregate 시에 너무 많은 양의 data 처리해서 memory 가 부족하게 되면 QueryExceededMemoryLimitNoDiskUseAllowed 가 나게 된다. 이 경우 allowDiskUse option 을 사용하면 된다.

allowDiskUse 는 <dbPath>/_tmp 에 data 를 write 하게 된다.

각각의 pipeline 의 stage 는 100MB 의 RAM 만을 사용한다. 기본적으로 이 값을 넘으면 error 가 난다. $search 는 100MB 제한이 걸리지 않는다. 왜냐하면 이것은 분리된 process 에서 run 되기 때문이다.

See Also

  1. 쿠…sal: [컴][db] MongoDB WiredTiger의 Memory 사용

References

  1. MongoDB 101: How to Tune Your MongoDB Configuration After Upgrading to More Memory - Percona Database Performance Blog, 2021-01-28
  2. How to Tell if Your MongoDB Server Is Correctly Sized For Your Working Set - Orange Matter

[컴][db] elasticsearch 에서 paginate (v6, v7)

 pagination / paging / page / offset

elasticsearch 에서 paginate (v6, v7)

from, size

1만개 이하의 hits 라면 from, size 을 이용하면 된다.

GET /_search
{
  "from": 5,
  "size": 20,
  "query": {
    "match": {
      "user.id": "kimchy"
    }
  }
}

그런데 너무 깊게, 또는 한번에 많은 결과를 가져올 것이라면, 이녀석을 사용하지 말라고 한다.

이유는 다음과 같다.

Search request 들은 일반적으로 여러 shard 들에 걸쳐있는데, 각 shard 는 “요청받은 hit들” 과 “이전 모든 page들의 hit들”(any previous pages) 메모리에 load해야만 한다. “deep page” 들과 “많은양의 결과” 에게 이 작업들은 memory 와 cpu 사용을 현저하게 높여서 성능저하 또는 node failure 를 일으키게 된다.[ref. 1]

그래서 기본 설정은 10,000 hit들 보다 많은 hits 를 paginate 할 것이라면, from, size 를 사용할 수 없다. 이 값은 index.max_result_window index setting 에 의해 설정된다.[ref. 1]

그래서 1만개 이상의 hits 를 paging 하려면, search_after parameter 를 사용하라고 한다.

scroll 도 있지만, v7에선 search_after 를 사용하는 것을 권장하는 듯 하다.(참고)

version 6 에서는 아직 search_after에 PIT 가 없기 때문에, scroll 을 사용하는 것이 나은 듯 하다.

명확하진 않지만, “1만개의 hits” 를 확인할 때는 query 를 했을때 나오는 결과값에 보면, hits.total 값이 있는데, 이 값을 보고 1만 hits 가 넘는 경우에는 사용하지 않으면 될 것 같다.

search after

_shard_doc

PIT 는 version 7 부터 들어갔다.

  • 모든 PIT search request 에는 sort tiebreaker field 인 _shard_doc 라는 field 가 들어가게 된다. 이 tiebreaker field 는 각 document 마다 unique 한 값을 가져야만 한다. 이 tiebreaker field 가 없으면 paged result 는 hits 를 빼먹거나, 중복된 hits 를 보여줄 수 있다.
  • sort 할 때 document 마다 있는 unique 값이 사용되어져야 한다. 그렇지 않으면, paged result 의 값이 중복되거나, 빠지거나 한다.[ref. 2, v6 의 document]
  • _id 가 unique 한 field 이지만, 이것을 사용하는 것은 추천하지 않는다. _id field 에 대해서 doc value 가 disabled 되어 있기 때문이다. 그래서 version 6 에서는 _id field 의 복사본을 사용하는 방법을 취한다. [ref. 2, v6 의 document]
  • ref. 3 에 따르면, version 6에서는 _id 를 대신할만한 unique value 를 직접 넣어줘야 하는 것 같다. 글의 느낌은 document 에 아예 기록해 놓으라는 느낌이다.
  • search_after 가 완전하게 또는 부분적으로 tiebreaker 값과 match 되는 첫번째 document 를 찾는다.
  • search after request 들은 sort order 가 _shard_doc 이면서 total hits 가 추적되지 않을때 더 빠르게 최적화 되어 있다. 순서에 상관없이 모든 documents 를 iterate 하길 원한다면, 이것이 가장 효과적이다.
  1. pit id 를 얻어온다.
  2. pit 를 넣고, query
POST /my-index-000001/_pit?keep_alive=1m
GET my-index-000001/_search
{
  "size": 10000,
  "query": {
    "match" : {
      "user.id" : "elkbee"
    }
  },
  "pit": {
    "id":  "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==", 
    "keep_alive": "1m"
  },
  "sort": [ 
    {"@timestamp": {"order": "asc", "format": "strict_date_optional_time_nanos", "numeric_type" : "date_nanos" }}
  ]
}
GET my-index-000001/_search
{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "sort": [
        {"date": "asc"},
        {"tie_breaker_id": "asc"}      
    ]
}

scroll

pagination 을 위한 함수는 아닌듯 하다. 그저 많은 page 를 불러오려할 때 유용해 보인다. 그래서 v6에서 거대한 page에 대한 pagination 을 하려면, sort, 와 page 의 구분은 다른 query 조건을 줘서 스스로 해야 할 듯 보인다. search_after 도 존재는 하지만, v7에 비하면 불완전해 보인다.

code example

const client = new Client({ node: 'http://3.112.194.162:9200' })
const result = await client.search({
  index: 'my-index-001',
  // keep the search results "scrollable" for 30 seconds
  scroll: '30s',
  size: 10,
  // filter the source to only include the quote field
  _source: ['s.d'],
  body: {
    "query": {
      "bool": {
        "must": [
          {
            "match": {
              "myid": "3220"
            }
          },
          {
            "range": {
              "s.date": {
                "gte": 1627776000000, // 2021-08-01 GMT
                "lt": 1630454400000,  // 2021-09-01 GMT
                "format": "epoch_millis"
              }
            }
          }
        ],
        "filter": [],
        "should": [],
        "must_not": []
      }
    }
  }
})
if (result.statusCode != 200) {
  console.error(result)
  return
}
result.body.hits.hits.map((val, i)=>{
  console.log(JSON.stringify(val))
})


// scroll next
const scrollId = result.body._scroll_id
let totalReqHitCount = 0
while(true){
  const res2 = await client.scroll({
    scroll_id: scrollId,
    scroll: '30s'
  })
  if(res2.statusCode != 200){
    console.error(JSON.stringify(res2))
    break
  }
  this._doSomething(res2)
  const hits = res2.body.hits
  totalReqHitCount += hits.hits.length
  if (hits.total === totalReqHitCount) {
    break
  } 
}


client.clearScroll({
    scroll_id: result.body._scroll_id,
})

결과:

'{"_index":"my-index-001","_type":"as","_id":"478274297bf453483e792499fd6ad4a0ad9c1b11::f2b8577cfc7c41bdb18ec2b57c881676","_score":2,"_source":{"s":{"date":1627782547273}}}'

'{"_index":"uh-as-202108","_type":"as","_id":"b496b241b720d98687de9df760ec497245fbc7b3::230f53df51aa4617a88b76f573e73a1a","_score":2,"_source":{"s":{"date":1627928148753}}}'

sort _doc

search after 의 _shard_doc 같은 느낌이다. 순서에 상관없이 빠르게 가져올 때 좋다고 한다.

GET /_search?scroll=1m
{
  "sort": [
    "_doc"
  ]
}

Reference

  1. Paginate search results | Elasticsearch Guide [7.15] | Elastic
  2. Search After | Elasticsearch Guide [6.7] | Elastic
  3. [Alerting] Add a tie breaker field to alerts · Issue #62002 · elastic/kibana · GitHub

[컴] nodejs 의 readline 사용법

node js / node 의 / 파일을 1줄씩 한줄씩 읽는 법 / 노드

nodejs 의 readline 사용법

readline 을 callback 을 이용해서 사용

const fs = require('fs');
const readline = require('readline');

const rl = readline.createInterface({
  input: fs.createReadStream('sample.txt'),
  crlfDelay: Infinity
});

rl.on('line', (line) => {
  console.log(`Line from file: ${line}`);
});

readline 을 async/await 을 이용해서 사용

const fs = require('fs');
const readline = require('readline');

async function processLineByLine() {
  const fileStream = fs.createReadStream('input.txt');

  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity
  });
  // Note: we use the crlfDelay option to recognize all instances of CR LF
  // ('\r\n') in input.txt as a single line break.

  for await (const line of rl) {
    // Each line in input.txt will be successively available here as `line`.
    console.log(`Line from file: ${line}`);
  }
}

processLineByLine();

for await...of loop 이 약간 느릴 수 있다고 한다. 그래서 아래처럼 하면 좀 낫다고 한다.

const { once } = require('events');
const { createReadStream } = require('fs');
const { createInterface } = require('readline');

(async function processLineByLine() {
  try {
    const rl = createInterface({
      input: createReadStream('big-file.txt'),
      crlfDelay: Infinity
    });

    rl.on('line', (line) => {
      // Process the line.
    });

    await once(rl, 'close');

    console.log('File processed.');
  } catch (err) {
    console.error(err);
  }
})();

read 후 write 하려면


// read 후 write 하려면

let rf = readline.createInterface({
  input: fs.createReadStream(file.path),
  terminal: false
});
rf.on('error', (err) => { console.log(err); });

let wf = fs.createWriteStream(file.destination + file.originalname);

rf.on('line', (line) => {
  if (line.match(/mykey/)) {
    line = line.replace(/mykey/, 'mykey2');
  }
  wf.write(line + '\n');
});
rf.on('close', () => {
  wf.close();
});

See Also

  1. 쿠…sal: [컴] read file in nodejs

[컴] Java 의 String.HashCode() 의 구현

 java hashcode javascript 로

Java 의 String.HashCode() 의 구현

java api 문서(ref. 1) 에 String.hashCode() 의 계산방법이 나와있다.

계산식은 다음과 같다.

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

java 에서 hashCode() 는 .equals() 를 호출할 때 true 가 나오는 값이라면, 같은 ’hash 값’을 갖도록 하면 된다.

javascript version

String.prototype.hashCode = function(){
    var hash = 0;
    if (this.length == 0) return hash;
    for (i = 0; i < this.length; i++) {
        char = this.charCodeAt(i);
        hash = ((hash<<5)-hash)+char;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

Reference

  1. String (Java Platform SE 7 )
  2. How String Hashcode value is calculated? - GeeksforGeeks
  3. [Java/Tip] String.hashCode()는 유일한 값을 반환할까?
  4. Javascript implementation of Java’s String.hashCode() method – Manwe
  5. The 3 things you should know about hashCode() - EclipseSource : hashCode() 를 key 로 쓰면 안되는 이유등이 나와 있다. 간단한 예로, "Aa" and "BB" 가 같은 hashCode 를 갖는다 한다.

[컴] windows 에서 ’사용자동의 없이 설치된 앱’이란?

 윈도우즈 / 번역 오류 /

windows 에서 ’사용자동의 없이 설치된 앱’이란?

윈도우즈에서 ’사용자동의 없이 설치된 앱’에 대한 차단을 할 수 있다.

그런데 이 번역이 오해를 좀 가져와서 여기서 정리를 좀 하려한다.

ref. 1 과 ref. 2 를 확인하면, ‘사용자동의 없이 설치된 앱’ 의 원래 영문은 ‘Potentially Unwanted Application’(PAU) 이다. 즉, ‘잠재적으로 원해지지 않는 앱’ 이다. 그리고 ref. 3 에는 ‘잠재적으로 원치 않는 응용 프로그램’ 로 번역해 놨다.(아마도 자동번역이라.)

이 PAU 들, 즉, ’잠재적으로 유저가 원할것 같지 않은 앱’은 윈도우즈가 나름의 ’평판이 낮은 앱’에 대한 정보를 가지고 그 앱들을 PAU 로 판단한다고 보면 된다. 어떤 프로그램을 ms 가 PAU 로 판단하는지는 ref. 3 에 있다.

만약 내가 의도적으로 설치한 광고프로그램이 있다면 그것도 ’사용자동의 없이 설치된 앱’이라고 뜬다는 이야기다.

그래서 windows os 에서 번역을 수정하지 않는한 ’사용자동의 없이 설치된 앱’이란 단어는 PAU 로서 ’잠재적으로 원치 않는 응용 프로그램’을 이야기하는 것이구나 라고 판단해야 할 것 같다.

“사용자 동의 없이 설치된 앱 차단” 설정 끄기

‘Windows 보안’ 설정 창 열기

  • window키 + R(실행창) –> ms-settings:windowsdefender –> ‘Windows 보안 열기’ 클릭

“사용자 동의 없이 설치된 앱 차단” 설정 끄기

  • “앱 및 브라우저 컨트롤” –> “평판 기반 보호” –> “평판 기반 보호 설정” 클릭 –> “사용자 동의 없이 설치된 앱 차단”

Reference

  1. Microsoft Defender 바이러스 백신을 통해 사용자 동의없이 설치된 응용 프로그램 차단 | Microsoft Docs
  2. Block potentially unwanted applications with Microsoft Defender Antivirus | Microsoft Docs
  3. Microsoft에서 맬웨어 및 잠재적으로 원치 않는 응용 프로그램을 식별하는 방법 - Windows security | Microsoft Docs