{"id":39195,"date":"2023-07-31T13:51:10","date_gmt":"2023-07-31T04:51:10","guid":{"rendered":"https:\/\/8gfg.shop\/blog\/?p=39195"},"modified":"2023-07-31T13:51:10","modified_gmt":"2023-07-31T04:51:10","slug":"designing-web-backend-services-a-strategy-considering-scalability-and-flexibility","status":"publish","type":"post","link":"https:\/\/8gfg.shop\/blog\/development\/designing-web-backend-services-a-strategy-considering-scalability-and-flexibility","title":{"rendered":"\uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4 \uc124\uacc4: \ud655\uc7a5\uc131\uacfc \uc720\uc5f0\uc131\uc744 \uace0\ub824\ud55c \uc804\ub7b5"},"content":{"rendered":"
\uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4\ub294 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ud575\uc2ec\uc801\uc778 \ubd80\ubd84\uc73c\ub85c, \ud074\ub77c\uc774\uc5b8\ud2b8\uc640 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc0ac\uc774\uc5d0\uc11c \ub3d9\uc791\ud558\ub294 \uc911\uc694\ud55c \uc5ed\ud560\uc744 \ud55c\ub2e4. \uc774\ub7ec\ud55c \uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4\uc758 \uc124\uacc4\ub294 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \uc131\ub2a5\uacfc \uc548\uc815\uc131\uc5d0 \uc9c1\uc811\uc801\uc778 \uc601\ud5a5\uc744 \ubbf8\uce58\uae30 \ub54c\ubb38\uc5d0 \ub9e4\uc6b0 \uc911\uc694\ud558\ub2e4. <\/p>\n
\uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4 \uc124\uacc4\ub294 \ud655\uc7a5\uc131\uacfc \uc720\uc5f0\uc131\uc744 \uace0\ub824\ud558\ub294 \uac83\uc774 \ud544\uc218\uc801\uc774\ub2e4. \uc774\ub294 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc774 \uc0ac\uc6a9\uc790 \uc99d\uac00\ub098 \ub354 \ub9ce\uc740 \uae30\ub2a5 \ucd94\uac00\uc5d0 \ub300\uc751\ud560 \uc218 \uc788\ub3c4\ub85d \ud558\ub294 \uac83 \ubfd0\ub9cc \uc544\ub2c8\ub77c, \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \uc720\uc9c0\ubcf4\uc218\uc131\uc744 \ub192\uc774\ub294 \ub370\uc5d0\ub3c4 \ub3c4\uc6c0\uc774 \ub41c\ub2e4.<\/p>\n
\ud655\uc7a5\uc131\uc740 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc774 \uc0ac\uc6a9\uc790 \uc99d\uac00\uc5d0 \ub300\uc751\ud560 \uc218 \uc788\ub294 \ub2a5\ub825\uc744 \uc758\ubbf8\ud55c\ub2e4. \uc774\ub97c \uc704\ud574\uc11c\ub294 \uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4\uac00 \uc218\ud3c9\uc801\uc73c\ub85c \ud655\uc7a5 \uac00\ub2a5\ud558\ub3c4\ub85d \uc124\uacc4\ub418\uc5b4\uc57c \ud55c\ub2e4. \uc218\ud3c9\uc801 \ud655\uc7a5\uc740 \uc11c\ubc84\uc758 \uc218\ub97c \ub298\ub9ac\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n
\uc6b0\uc120, \ub85c\ub4dc \ubc38\ub7f0\uc2f1\uc744 \uace0\ub824\ud574\uc57c \ud55c\ub2e4. \ub85c\ub4dc \ubc38\ub7f0\uc2f1\uc740 \uc11c\ubc84\uc758 \ubd80\ud558\ub97c \ubd84\uc0b0\uc2dc\ucf1c \uc11c\ubc84\uc758 \uc131\ub2a5\uc744 \ucd5c\uc801\ud654\ud558\ub294 \uac83\uc774\ub2e4. \uac00\uc7a5 \ub9ce\uc774 \uc0ac\uc6a9\ub418\ub294 \ub85c\ub4dc \ubc38\ub7f0\uc11c\ub294 Nginx\ub098 HAProxy \ub4f1\uc774 \uc788\ub2e4.<\/p>\n
\ub2e4\uc74c\uc73c\ub85c\ub294 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \uace0\ub824\ud574\uc57c \ud55c\ub2e4. \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub294 \ub9ce\uc740 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud558\uace0 \ucc98\ub9ac\ud558\ub294 \ub370 \uc0ac\uc6a9\ub418\uae30 \ub54c\ubb38\uc5d0, \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc131\ub2a5\uc744 \ucd5c\uc801\ud654\ud558\ub294 \uac83\uc774 \ub9e4\uc6b0 \uc911\uc694\ud558\ub2e4. \ub530\ub77c\uc11c \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc0e4\ub529\uc774\ub098 \ubcf5\uc81c \ub4f1\uc744 \uace0\ub824\ud574\uc57c \ud55c\ub2e4.<\/p>\n
\ub9c8\uc9c0\ub9c9\uc73c\ub85c\ub294 \uce90\uc2f1\uc744 \uace0\ub824\ud574\uc57c \ud55c\ub2e4. \uce90\uc2f1\uc740 \ub370\uc774\ud130\ub97c \ubbf8\ub9ac \uc800\uc7a5\ud574 \ub193\ub294 \uac83\uc73c\ub85c, \uce90\uc2dc\uc5d0 \uc800\uc7a5\ub41c \ub370\uc774\ud130\ub97c \uc0ac\uc6a9\ud558\uba74 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0 \uc811\uadfc\ud558\uc9c0 \uc54a\uc544\ub3c4 \ub418\uae30 \ub54c\ubb38\uc5d0 \uc131\ub2a5\uc744 \ud5a5\uc0c1\uc2dc\ud0a4\ub294 \ub370\uc5d0 \ub3c4\uc6c0\uc774 \ub41c\ub2e4. \uac00\uc7a5 \ub9ce\uc774 \uc0ac\uc6a9\ub418\ub294 \uce90\uc2dc\ub294 Redis\ub098 Memcached \ub4f1\uc774 \uc788\ub2e4.<\/p>\n
# Nginx\ub97c \uc774\uc6a9\ud55c \ub85c\ub4dc \ubc38\ub7f0\uc2f1 \uc608\uc2dc\n\nupstream backend {\n server backend1.example.com;\n server backend2.example.com;\n server backend3.example.com;\n}\n\nserver {\n listen 80;\n\n location \/ {\n proxy_pass http:\/\/backend;\n }\n}<\/code><\/pre>\n\uc720\uc5f0\uc131 \uace0\ub824\ud55c \uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4 \uc124\uacc4 \uc804\ub7b5<\/h2>\n
\uc720\uc5f0\uc131\uc740 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc774 \uc0c8\ub85c\uc6b4 \uae30\ub2a5\uc744 \ucd94\uac00\ud558\uac70\ub098 \ubcc0\uacbd\ud560 \uc218 \uc788\ub294 \ub2a5\ub825\uc744 \uc758\ubbf8\ud55c\ub2e4. \uc774\ub97c \uc704\ud574\uc11c\ub294 \uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4\uac00 \ubaa8\ub4c8\ud654\ub418\uc5b4 \uc788\uc5b4\uc57c \ud55c\ub2e4. \ubaa8\ub4c8\ud654\ub294 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \uae30\ub2a5\uc744 \uc791\uc740 \ub2e8\uc704\ub85c \ub098\ub204\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n
\uc6b0\uc120, RESTful API\ub97c \uc0ac\uc6a9\ud574\uc57c \ud55c\ub2e4. RESTful API\ub294 HTTP \ud504\ub85c\ud1a0\ucf5c\uc744 \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc804\uc1a1\ud558\ub294\ub370, \uc774\ub97c \uc774\uc6a9\ud558\uba74 \uc11c\ubc84\uc640 \ud074\ub77c\uc774\uc5b8\ud2b8\uac00 \ub3c5\ub9bd\uc801\uc73c\ub85c \uac1c\ubc1c\ub420 \uc218 \uc788\ub2e4. \uc989, \uc11c\ubc84\uc640 \ud074\ub77c\uc774\uc5b8\ud2b8\uac00 \uac01\uac01 \ubcc0\uacbd\ub420 \uc218 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc720\uc5f0\uc131\uc744 \ub192\uc77c \uc218 \uc788\ub2e4.<\/p>\n
\ub2e4\uc74c\uc73c\ub85c\ub294 \ub9c8\uc774\ud06c\ub85c\uc11c\ube44\uc2a4 \uc544\ud0a4\ud14d\ucc98\ub97c \uace0\ub824\ud574\uc57c \ud55c\ub2e4. \ub9c8\uc774\ud06c\ub85c\uc11c\ube44\uc2a4 \uc544\ud0a4\ud14d\ucc98\ub294 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc791\uc740 \uc11c\ube44\uc2a4\ub85c \ub098\ub204\uc5b4 \uac01\uac01 \ub3c5\ub9bd\uc801\uc73c\ub85c \ubc30\ud3ec\ud558\uace0 \uc2e4\ud589\ud558\ub294 \uc544\ud0a4\ud14d\ucc98\uc774\ub2e4. \uc774\ub97c \uc774\uc6a9\ud558\uba74 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \uae30\ub2a5\uc744 \ub354\uc6b1 \uc138\ubd84\ud654\ud560 \uc218 \uc788\uc73c\uba70, \uac01\uac01\uc758 \uc11c\ube44\uc2a4\ub97c \ub3c5\ub9bd\uc801\uc73c\ub85c \ubcc0\uacbd\ud560 \uc218 \uc788\ub2e4.<\/p>\n
\ub9c8\uc9c0\ub9c9\uc73c\ub85c\ub294 \ucee8\ud14c\uc774\ub108 \uae30\uc220\uc744 \uc774\uc6a9\ud574\uc57c \ud55c\ub2e4. \ucee8\ud14c\uc774\ub108\ub294 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc2e4\ud589\ud558\uae30 \uc704\ud55c \ub3c5\ub9bd\uc801\uc778 \ud658\uacbd\uc744 \uc81c\uacf5\ud558\ub294 \uae30\uc220\uc774\ub2e4. \ucee8\ud14c\uc774\ub108\ub294 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc2e4\ud589\ud558\ub294 \ub370 \ud544\uc694\ud55c \ubaa8\ub4e0 \ub77c\uc774\ube0c\ub7ec\ub9ac\uc640 \uc758\uc874\uc131\uc744 \ud3ec\ud568\ud558\uace0 \uc788\uae30 \ub54c\ubb38\uc5d0, \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc27d\uac8c \ubc30\ud3ec\ud560 \uc218 \uc788\ub2e4.<\/p>\n
# Kubernetes\ub97c \uc774\uc6a9\ud55c \ub9c8\uc774\ud06c\ub85c\uc11c\ube44\uc2a4 \uc544\ud0a4\ud14d\ucc98 \uc608\uc2dc\n\napiVersion: v1\nkind: Service\nmetadata:\n name: backend\n labels:\n app: backend\nspec:\n ports:\n - name: http\n port: 80\n targetPort: 8080\n selector:\n app: backend\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n name: backend\nspec:\n replicas: 3\n selector:\n matchLabels:\n app: backend\n template:\n metadata:\n labels:\n app: backend\n spec:\n containers:\n - name: backend\n image: myapp\/backend:v1\n ports:\n - containerPort: 8080<\/code><\/pre>\n\uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4 \uc124\uacc4: \uc131\uacf5\uc801\uc778 \uad6c\ud604\uc744 \uc704\ud55c \uc9c0\uce68<\/h1>\n
\uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4 \uc124\uacc4\ub294 \ub9e4\uc6b0 \uc911\uc694\ud558\uc9c0\ub9cc, \uc131\uacf5\uc801\uc778 \uad6c\ud604\uc744 \uc704\ud574\uc11c\ub294 \uba87 \uac00\uc9c0 \uc9c0\uce68\uc744 \ub530\ub77c\uc57c \ud55c\ub2e4.<\/p>\n
\uccab\uc9f8, TDD(Test-Driven Development)\ub97c \uc774\uc6a9\ud574\uc57c \ud55c\ub2e4. TDD\ub294 \ud14c\uc2a4\ud2b8 \ucf54\ub4dc\ub97c \uba3c\uc800 \uc791\uc131\ud558\uace0, \uc774\ub97c \uae30\ubc18\uc73c\ub85c \uac1c\ubc1c\uc744 \uc9c4\ud589\ud558\ub294 \ubc29\ubc95\uc774\ub2e4. \uc774\ub97c \uc774\uc6a9\ud558\uba74 \ucf54\ub4dc\uc758 \ud488\uc9c8\uc744 \ub192\uc774\uace0, \ubc84\uadf8\ub97c \uc904\uc77c \uc218 \uc788\ub2e4.<\/p>\n
\ub458\uc9f8, \ub85c\uae45\uc744 \uc801\uadf9\uc801\uc73c\ub85c \ud65c\uc6a9\ud574\uc57c \ud55c\ub2e4. \ub85c\uae45\uc740 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ub3d9\uc791 \uc0c1\ud0dc\ub97c \uae30\ub85d\ud558\ub294 \uac83\uc73c\ub85c, \ub85c\uadf8\ub97c \ubd84\uc11d\ud568\uc73c\ub85c\uc368 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ub3d9\uc791 \uc0c1\ud0dc\ub97c \ud30c\uc545\ud560 \uc218 \uc788\ub2e4.<\/p>\n
\uc14b\uc9f8, \ubaa8\ub2c8\ud130\ub9c1\uc744 \uc801\uadf9\uc801\uc73c\ub85c \ud65c\uc6a9\ud574\uc57c \ud55c\ub2e4. \ubaa8\ub2c8\ud130\ub9c1\uc740 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ub3d9\uc791 \uc0c1\ud0dc\ub97c \uc2e4\uc2dc\uac04\uc73c\ub85c \ud30c\uc545\ud558\ub294 \uac83\uc73c\ub85c, \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ubb38\uc81c\ub97c \ube60\ub974\uac8c \ud30c\uc545\ud558\uace0 \ub300\ucc98\ud560 \uc218 \uc788\ub2e4.<\/p>\n
\ub137\uc9f8, \ubcf4\uc548\uc744 \uace0\ub824\ud574\uc57c \ud55c\ub2e4. \uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4\ub294 \ub9ce\uc740 \uc0ac\uc6a9\uc790 \uc815\ubcf4\ub97c \ub2e4\ub8e8\uae30 \ub54c\ubb38\uc5d0, \ubcf4\uc548\uc5d0 \ub300\ud55c \uace0\ubbfc\uc774 \ud544\uc218\uc801\uc774\ub2e4. \ub530\ub77c\uc11c SSL\uc744 \uc801\uc6a9\ud558\uac70\ub098, \uc778\uc99d\uc744 \uac15\ud654\ud558\ub294 \ub4f1\uc758 \ubcf4\uc548 \ub300\ucc45\uc774 \ud544\uc694\ud558\ub2e4.<\/p>\n
# Flask\ub97c \uc774\uc6a9\ud55c TDD \uc608\uc2dc\n\nimport unittest\nfrom myapp import app\n\nclass MyTest(unittest.TestCase):\n def setUp(self):\n self.app = app.test_client()\n\n def test_hello_world(self):\n rv = self.app.get('\/')\n assert b'Hello, World!' in rv.data<\/code><\/pre>\n# Python logging \uc608\uc2dc\n\nimport logging\n\nlogging.basicConfig(filename='example.log', level=logging.DEBUG)\n\ndef my_function():\n logging.info('Starting my_function')\n # ...\n\nmy_function()<\/code><\/pre>\n# Prometheus\ub97c \uc774\uc6a9\ud55c \ubaa8\ub2c8\ud130\ub9c1 \uc608\uc2dc\n\nglobal:\n scrape_interval: 15s\n\nscrape_configs:\n - job_name: 'backend'\n metrics_path: '\/metrics'\n static_configs:\n - targets: ['backend:8080']<\/code><\/pre>\n# Flask\ub97c \uc774\uc6a9\ud55c \ubcf4\uc548 \uc608\uc2dc\n\nfrom flask import Flask, session, redirect, url_for, request\nfrom flask_session import Session\nfrom werkzeug.security import generate_password_hash, check_password_hash\n\napp = Flask(__name__)\napp.config['SECRET_KEY'] = 'secret'\napp.config['SESSION_TYPE'] = 'filesystem'\nSession(app)\n\[email protected]('\/')\ndef index():\n if 'username' in session:\n return f'Logged in as {session[\"username\"]}'\n else:\n return 'You are not logged in'\n\[email protected]('\/login', methods=['GET', 'POST'])\ndef login():\n if request.method == 'POST':\n username = request.form['username']\n password = request.form['password']\n if username == 'admin' and \n check_password_hash(generate_password_hash('password'), password):\n session['username'] = username\n return redirect(url_for('index'))\n else:\n return 'Invalid username\/password'\n else:\n return '''\n\n '''\n\[email protected]('\/logout')\ndef logout():\n session.pop('username', None)\n return redirect(url_for('index'))<\/code><\/pre>\n\uacb0\ub860<\/h2>\n
\uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4 \uc124\uacc4\ub294 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \uc131\ub2a5\uacfc \uc548\uc815\uc131\uc5d0 \uc9c1\uc811\uc801\uc778 \uc601\ud5a5\uc744 \ubbf8\uce58\uae30 \ub54c\ubb38\uc5d0 \ub9e4\uc6b0 \uc911\uc694\ud558\ub2e4. \uc774\ub97c \uc704\ud574\uc11c\ub294 \ud655\uc7a5\uc131\uacfc \uc720\uc5f0\uc131\uc744 \uace0\ub824\ud558\ub294 \uac83\uc774 \ud544\uc218\uc801\uc774\uba70, TDD, \ub85c\uae45, \ubaa8\ub2c8\ud130\ub9c1, \ubcf4\uc548 \ub4f1\uc758 \uc9c0\uce68\uc744 \ub530\ub77c\uc57c \ud55c\ub2e4. \uc774\ub7ec\ud55c \uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4 \uc124\uacc4\uc758 \uc911\uc694\uc131\uc744 \uc778\uc2dd\ud558\uace0, \uc801\uadf9\uc801\uc73c\ub85c \uc801\uc6a9\ud55c\ub2e4\uba74 \ub354\uc6b1 \uc548\uc815\uc801\uc774\uace0 \uc131\ub2a5\uc774 \uc6b0\uc218\ud55c \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uac1c\ubc1c\ud560 \uc218 \uc788\ub2e4.<\/p>\n","protected":false},"excerpt":{"rendered":"
\uc6f9 \ubc31\uc5d4\ub4dc \uc11c\ube44\uc2a4\uc758 \uc124\uacc4\ub294 \ud655\uc7a5\uc131\uacfc \uc720\uc5f0\uc131\uc744 \uace0\ub824\ud558\ub294 \uc804\ub7b5\uc774 \ud544\uc218\uc801\uc785\ub2c8\ub2e4.<\/p>\n","protected":false},"author":1,"featured_media":12882,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1957],"tags":[5898,2015,2076,584,2105,6171,2079,906,5979],"class_list":["post-39195","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","tag-backend","tag-development","tag-from","tag-global","tag-java","tag-msa","tag-security","tag-world","tag-5979"],"acf":[],"_links":{"self":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts\/39195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/comments?post=39195"}],"version-history":[{"count":1,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts\/39195\/revisions"}],"predecessor-version":[{"id":39283,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts\/39195\/revisions\/39283"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/media\/12882"}],"wp:attachment":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/media?parent=39195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/categories?post=39195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/tags?post=39195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}