|
1 | 1 | # Course Project at UNAH-MM545: Distributed Text File System |
2 | 2 |
|
3 | | -Implementation of a server/client application in Java RMI and JavaFX to manage concurrent connections for managing a file system that accepts operations on users text files. |
| 3 | +[](https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system) |
| 4 | + |
| 5 | +[](https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system/blob/main/LICENSE) |
| 6 | + |
| 7 | +Implementation of a server/client application in Java RMI and JavaFX to manage concurrent |
| 8 | +connections for managing a file system that accepts operations on users' text files. |
| 9 | + |
| 10 | +The original course project required a much simpler implementation, and the main objective was to |
| 11 | +apply DevOps skills. Needless to say, as I often do, I have added a huge amount of extra value to |
| 12 | +this project to make it worth it. My objectives are to keep working on some new features after the |
| 13 | +first release and build good DevOps documentation. Additionally, it's a good chance to show good use |
| 14 | +cases of the main underlying technologies: Java and JavaFX. |
4 | 15 |
|
5 | 16 | ## Required technologies |
6 | 17 |
|
7 | 18 | - Java RMI or Python Pyro only. |
8 | 19 | - Anything that works for the client. |
9 | 20 | - Linux containers. |
10 | 21 |
|
| 22 | +## Getting started |
| 23 | + |
| 24 | +This system can be deployed in several ways. According to the course topics, you should use linux |
| 25 | +containers for the server applications. For this server, there are two applications that run the |
| 26 | +distributed system: |
| 27 | + |
| 28 | +- **RMI Registry:** Receives the request from clients to connect to the remote object from the file |
| 29 | + server. |
| 30 | + |
| 31 | + |
| 32 | +- **RMI File System Server:** Manages the actual file system and physical files in storage. The |
| 33 | + clients access the remote object of this application through the RMI Registry, so the registry may |
| 34 | + be deployed separately from the server storing the actual files. |
| 35 | + |
| 36 | +On the other side, for the client application you should run three or more of them to show the real |
| 37 | +time functionality. |
| 38 | + |
| 39 | +One way to deploy all the system is as a standalone fashion. This way you need tons of RAM to run |
| 40 | +many VMs, JVMs, Linux Containers and other open applications as depicted by the following diagram: |
| 41 | + |
| 42 | + |
| 43 | + |
| 44 | +In that case, I would even suggest trying to use GraalVM to avoid that crazy amount of JVMs. That is |
| 45 | +something I haven't tested yet and the project at this stage is quite unstable. GraalVM also doesn't |
| 46 | +play well with the latest non-LTS Java versions and just properly deploying JavaFX is a bit of a |
| 47 | +mess by itself these days mostly if you use the latest versions of tools prior waiting for issue |
| 48 | +fixes. So let's keep that game for later with Java 17 LTS since I am also using `JDK 16` + |
| 49 | +`--enable-preview` as a good mathematician to take advantage of the new data oriented and FP |
| 50 | +features for the *model* (or domain) layer. |
| 51 | + |
| 52 | +### Requirements |
| 53 | + |
| 54 | +#### AIO deploy |
| 55 | + |
| 56 | +For the "All-In-One" deployment model the requirements are as follows: |
| 57 | + |
| 58 | +**Minimum requirements** |
| 59 | + |
| 60 | +- Intel® Core™ i3-6100 / Intel® Core™ i5-2400 |
| 61 | +- 8 GB of system memory |
| 62 | +- 35 GB of available storage |
| 63 | + |
| 64 | +**Recommended requirements** |
| 65 | + |
| 66 | +- Intel® Core™ i5-4590 / Intel® Core™ i7-2600 |
| 67 | +- 12 GB of system memory |
| 68 | +- 50 GB of available SSD storage |
| 69 | +- Nvidia GT-730 / 256 MB of dedicated VRAM |
| 70 | + |
| 71 | +Additionally, a broadband internet connection is required to install all the tools. |
| 72 | + |
| 73 | +Some of these requirements are for the Ubuntu VM installation and accelerated graphics boots to make |
| 74 | +the VM run smoother. |
| 75 | + |
| 76 | +#### Cloud deploy |
| 77 | + |
| 78 | +For a cloud deployment the requirements are simple: |
| 79 | + |
| 80 | +- An Ubuntu VM with at least 1 vCPU, 2 GB RAM, 8 GB storage. |
| 81 | +- A desktop computer to run the JavaFX clients. |
| 82 | + |
| 83 | +It doesn't hurt to pick a better one. An Azure B2s / B2ms size is plenty enough for testing. |
| 84 | + |
| 85 | +**Important:** If you plan to set up a cloud deployment over a WAN or the Internet then you must |
| 86 | +have a good background in networking since this is a really tough/impossible endeavor. I have |
| 87 | +tried for many days to achieve this goal but it is not feasible to fulfill. I don't plan on doing so, |
| 88 | +because the underlying technology is archaic (RMI) and I'm a Software Engineer and not a DevOps. |
| 89 | +The problem is likely due to the system using callbacks and the client has to be a server too to |
| 90 | +export its object, then firewall and inbound rules have to be configured for each client machine, |
| 91 | +the IPs and ports are another mess and a machine might just be able to run only one client at a |
| 92 | +time. Then, just make an "AIO"-fashioned deploy where all of the machines run on the same LAN if |
| 93 | +you don't have a larger infraestructure running on the same LAN. |
| 94 | +More on this: |
| 95 | + |
| 96 | +- [How to send a message from Server to Client using Java RMI?](https://stackoverflow.com/questions/29284276/how-to-send-a-message-from-server-to-client-using-java-rmi) |
| 97 | +- [Can I invoke a client´s method from a server with RMI](https://stackoverflow.com/questions/21665300/can-i-invoke-a-client%C2%B4s-method-from-a-server-with-rmi) |
| 98 | +- [Java rmi over the internet](https://stackoverflow.com/questions/16268391/java-rmi-over-the-internet) |
| 99 | + |
| 100 | +### Deployment |
| 101 | + |
| 102 | +For this version of the software, you need to do some manual configs regarding IP addresses or |
| 103 | +hostnames. This is because the RMI technology requires knowing not only the server hostname where |
| 104 | +the JVM is running but also the client's hostname to answer back to it. If the hostname property |
| 105 | +isn't set on the client app then the server won't be able to respond to that client, or it might |
| 106 | +take a huge amount of time to respond. Fortunately, everything is set up already, and the config |
| 107 | +process just requires a bit of work. |
| 108 | + |
| 109 | +#### Server applications |
| 110 | + |
| 111 | +On server machine (assumed to be Ubuntu 20.x x64), install LXC, configure LXD and create two |
| 112 | +containers: `registry` and `fs`; for the registry server and the file-system server respectively. I |
| 113 | +don't recommend using snap along with LXC since I had a trouble which made me uninstall it later. |
| 114 | +Then install a proxy device into the registry container to map the VM RMI port to the registry |
| 115 | +container port: |
| 116 | + |
| 117 | +`sudo apt update` |
| 118 | + |
| 119 | +`sudo apt upgrade` |
| 120 | + |
| 121 | +`sudo apt install lxd` |
| 122 | + |
| 123 | +Choose the latest version of LXD (4.x+) and run `lxc list` to check it appears an empty list of |
| 124 | +containers, and the installation was successful. Run `sudo lxd init` and choose all the defaults to |
| 125 | +finish the lxd set up. Now install an Ubuntu image (in this case 20.04) and create the two |
| 126 | +containers required: |
| 127 | + |
| 128 | +`lxc launch ubuntu:20.04 registry` |
| 129 | + |
| 130 | +`lxc launch ubuntu:20.04 fs` |
| 131 | + |
| 132 | +Then check with `lxc list` that you have created two new linux containers. |
| 133 | + |
| 134 | +##### Common set up |
| 135 | + |
| 136 | +Next, run the following commands on both containers `registry` and `fs` to install common tools that |
| 137 | +are suggested to deploy the applications: |
| 138 | + |
| 139 | +`lxc exec { container } -- bash` |
| 140 | + |
| 141 | +`sudo apt update` |
| 142 | + |
| 143 | +`sudo apt upgrade` |
| 144 | + |
| 145 | +`sudo apt install zip` |
| 146 | + |
| 147 | +`sudo apt install unzip` |
| 148 | + |
| 149 | +Install SDKMAN: |
| 150 | + |
| 151 | +`curl -s "https://get.sdkman.io" | bash` |
| 152 | + |
| 153 | +`source "$HOME/.sdkman/bin/sdkman-init.sh"` |
| 154 | + |
| 155 | +Check SDKMAN installation: `sdk version`. Now install Gradle and Java. The current non-LTS version |
| 156 | +of Java I used is JDK16 with enable-preview, I suggest installing JDK17+ (which is not GA yet at the |
| 157 | +time of this release) for the current release v0.1.0: |
| 158 | + |
| 159 | +`sdk list java` (choose the latest 17.0.x, 17+ version) |
| 160 | + |
| 161 | +`sdk install java 17.0.{ x }-open` |
| 162 | + |
| 163 | +`sdk install gradle` |
| 164 | + |
| 165 | +Clone the project repository into a directory of choice: |
| 166 | + |
| 167 | +`git clone https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system.git` |
| 168 | + |
| 169 | +Now the common configuration has finished for both containers. |
| 170 | + |
| 171 | +##### Registry container |
| 172 | + |
| 173 | +Install the proxy device into the registry container to accept communication to the outside: |
| 174 | + |
| 175 | +`lxc config device add registry rmi-port proxy listen=tcp:0.0.0.0:1099 connect=tcp:127.0.0.1:1099` |
| 176 | + |
| 177 | +Prior to continuing, you'd like to take note of both container's IP addresses, check it out |
| 178 | +with `lxc list`. |
| 179 | + |
| 180 | +Enter into the registry container and run the server as a registry application assuming you are into |
| 181 | +the project root directory: |
| 182 | + |
| 183 | +`lxc exec registry -- bash` |
| 184 | + |
| 185 | +`cd server` |
| 186 | + |
| 187 | +`gradle run --args="{ registry-ip-address } reg"` |
| 188 | + |
| 189 | +Thus, the server should be running as an RMI registry server and listening to incoming clients. |
| 190 | + |
| 191 | +##### FileSystem container |
| 192 | + |
| 193 | +Enter into the fs container and run the server as a file-system server: |
| 194 | + |
| 195 | +`lxc exec fs -- bash` |
| 196 | + |
| 197 | +`cd server` |
| 198 | + |
| 199 | +`gradle run --args="{ fs-ip-address } fs { registry-ip-address }"` |
| 200 | + |
| 201 | +Thus, the server should be running as an RMI file-system server. So, the remote object of this |
| 202 | +server has been bound to the registry server so that the registry server knows that clients want to |
| 203 | +access *that* remote object located at *this* container. |
| 204 | + |
| 205 | +##### Troubleshooting |
| 206 | + |
| 207 | +- Don't forget to configure the inbound/outbound security groups to allow traffic pass by your VM. |
| 208 | + |
| 209 | +- Since I haven't added the dynamic IP config via the `NetworkInterface` Java API, and they have to |
| 210 | + be passed manually by JVM args, don't forget that IP addresses change when restarting the network. |
| 211 | + I was playing with that API though JShell, and I think it will work well when I implement it. |
| 212 | + |
| 213 | +- [Storage issues](./docs/troubleshooting/storage/storage.md): Container out of space, "no space left on device" when running an app. |
| 214 | + |
| 215 | +#### Desktop client |
| 216 | + |
| 217 | +Finally, to deploy the client into a desktop machine: clone the repository, install SDKMAN, Gradle |
| 218 | +and a version of JDK with FX mods (Zulu FX or Liberica). If you use IntelliJ IDEA then it can be |
| 219 | +faster to run from the Gradle window. You will need the familiar commands if you are in Linux or |
| 220 | +Mac, for Windows the installations may be harder that's why I recommend using IntelliJ IDEA if you' |
| 221 | +re using Windows. The following commands work for an Ubuntu desktop: |
| 222 | + |
| 223 | +`sudo apt update` |
| 224 | + |
| 225 | +`sudo apt upgrade` |
| 226 | + |
| 227 | +`sudo apt install zip` |
| 228 | + |
| 229 | +`sudo apt install unzip` |
| 230 | + |
| 231 | +`curl -s "https://get.sdkman.io" | bash` |
| 232 | + |
| 233 | +`source "$HOME/.sdkman/bin/sdkman-init.sh"` |
| 234 | + |
| 235 | +`sdk install gradle` |
| 236 | + |
| 237 | +Install a JDK version of your choice (JDK17+) but make sure it contains the `fx` modules: |
| 238 | + |
| 239 | +`sdk list java | grep fx` |
| 240 | + |
| 241 | +`sdk install java 17.0.{ x }.fx-zulu` |
| 242 | + |
| 243 | +Now edit the source file: |
| 244 | + |
| 245 | +`cd client` |
| 246 | + |
| 247 | +`sudo nano src/main/java/com/github/tobiasbriones/cp/rmifilesystem/client/FileSystemServices.java` |
| 248 | + |
| 249 | +Then set the `HOST` constant of that file to the public IP address or hostname of your VM. |
| 250 | + |
| 251 | +Finally, run the application and pass the IP address of your current desktop machine where the |
| 252 | +client will run: |
| 253 | + |
| 254 | +`gradle run --args="{ client-ip-address }"` |
| 255 | + |
| 256 | +##### Troubleshooting |
| 257 | + |
| 258 | +- If you get a weird error when running the app, |
| 259 | + like [Error initializing QuantumRenderer: no suitable pipeline found](https://stackoverflow.com/questions/68204320/javafx-installation-issues-error-initializing-quantumrenderer) |
| 260 | + make sure to had installed an updated JDK version containing the JavaFX mods like Azul FX or |
| 261 | + BellSoft Liberica and run the application with that JDK. |
| 262 | + |
| 263 | +##### Suggested reading |
| 264 | + |
| 265 | +In [this article](./docs/troubleshooting/binary-incompatibility/binary-incompatibility.md), I talk about an experience I had with the famous binary compatibility. |
| 266 | + |
| 267 | +##### Issues |
| 268 | + |
| 269 | +One of the main issue of `v0.1.0` is the local FS update regarding deleting files. When a user |
| 270 | +deletes a file form the system, it's physically deleted from the user machine but not physically |
| 271 | +deleted from the other client machines. This feature will be implemented in a further project |
| 272 | +version. Significant performance optimizations will be scheduled for later releases too. |
| 273 | + |
| 274 | +### Bibliography |
| 275 | + |
| 276 | +- Linux Containers. (2021). Linuxcontainers.Org. https://linuxcontainers.org/ |
| 277 | + |
| 278 | +- Home - SDKMAN! the Software Development Kit Manager. (2021). Sdkman.Io. https://sdkman.io/ |
| 279 | + |
| 280 | +- Xenitellis, S. (2021, February 8). How to use the LXD Proxy Device to map ports between the host |
| 281 | + and the containers. |
| 282 | + Blog.Simos.Info. https://blog.simos.info/how-to-use-the-lxd-proxy-device-to-map-ports-between-the-host-and-the-containers/ |
| 283 | + |
| 284 | +## Screenshots |
| 285 | + |
| 286 | +**LXC and Registry Container** |
| 287 | + |
| 288 | + |
| 289 | +**LXC and FS container** |
| 290 | + |
| 291 | + |
| 292 | +**Client running and FS Server files** |
| 293 | + |
| 294 | + |
| 295 | +**Demo Animation** |
| 296 | + |
| 297 | + |
| 298 | +## Contact |
| 299 | + |
| 300 | +This project: [Docs](https://tobiasbriones.github.io/cp-unah-mm545-distributed-text-file-system), |
| 301 | +[Repository](https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system) |
| 302 | + |
| 303 | +Tobias Briones: [GitHub](https://github.com/tobiasbriones) |
| 304 | + |
11 | 305 | ## About |
12 | 306 |
|
13 | 307 | **Course Project at UNAH-MM545: Distributed Text File System** |
14 | 308 |
|
15 | | -Implementation of a server/client application in Java RMI and JavaFX to manage concurrent connections for managing a file system that accepts operations on users text files. |
| 309 | +Implementation of a server/client application in Java RMI and JavaFX to manage concurrent |
| 310 | +connections for managing a file system that accepts operations on users' text files. |
16 | 311 |
|
17 | 312 | Copyright © 2021 Tobias Briones. All rights reserved. |
18 | 313 |
|
|
0 commit comments